diff --git a/README.md b/README.md index d4d995398c8..190e0830434 100644 --- a/README.md +++ b/README.md @@ -216,7 +216,7 @@ project tested against at the point of release. | [@warp-drive/diagnostic](./packages/diagnostic#readme) | 🌌 | ![NPM LTS 4.12 Version](https://img.shields.io/npm/v/@warp-drive/diagnostic/lts-4-12?label&color=bbbbbb) | ![NPM LTS Version](https://img.shields.io/npm/v/@warp-drive/diagnostic/lts?label&color=0096ff) | ![NPM Stable Version](https://img.shields.io/npm/v/@warp-drive/diagnostic/latest?label&color=90EE90) | ![NPM Beta Version](https://img.shields.io/npm/v/@warp-drive/diagnostic/beta?label&color=ff00ff) | ![NPM Canary Version](https://img.shields.io/npm/v/@warp-drive/diagnostic/canary?label&color=FFBF00) | | [@warp-drive/ember](./packages/ember#readme) | 🐹 | ![NPM LTS 4.12 Version](https://img.shields.io/npm/v/@warp-drive/ember/lts-4-12?label&color=bbbbbb) | ![NPM LTS Version](https://img.shields.io/npm/v/@warp-drive/ember/lts?label&color=0096ff) | ![NPM Stable Version](https://img.shields.io/npm/v/@warp-drive/ember/latest?label&color=90EE90) | ![NPM Beta Version](https://img.shields.io/npm/v/@warp-drive/ember/beta?label&color=ff00ff) | ![NPM Canary Version](https://img.shields.io/npm/v/@warp-drive/ember/canary?label&color=FFBF00) | | [@warp-drive/experiments](./packages/experiments#readme) | 🌌 | ![NPM LTS 4.12 Version](https://img.shields.io/npm/v/@warp-drive/experiments/lts-4-12?label&color=bbbbbb) | ![NPM LTS Version](https://img.shields.io/npm/v/@warp-drive/experiments/lts?label&color=0096ff) | ![NPM Stable Version](https://img.shields.io/npm/v/@warp-drive/experiments/latest?label&color=90EE90) | ![NPM Beta Version](https://img.shields.io/npm/v/@warp-drive/experiments/beta?label&color=ff00ff) | ![NPM Canary Version](https://img.shields.io/npm/v/@warp-drive/experiments/canary?label&color=FFBF00) | -| [eslint-plugin-ember-data](./packages/eslint-plugin-ember-data#readme) | 🌌 | ![NPM LTS 4.12 Version](https://img.shields.io/npm/v/eslint-plugin-ember-data/lts-4-12?label&color=bbbbbb) | ![NPM LTS Version](https://img.shields.io/npm/v/eslint-plugin-ember-data/lts?label&color=0096ff) | ![NPM Stable Version](https://img.shields.io/npm/v/eslint-plugin-ember-data/latest?label&color=90EE90) | ![NPM Beta Version](https://img.shields.io/npm/v/eslint-plugin-ember-data/beta?label&color=ff00ff) | ![NPM Canary Version](https://img.shields.io/npm/v/eslint-plugin-ember-data/canary?label&color=FFBF00) | +| [eslint-plugin-warp-drive](./packages/eslint-plugin-warp-drive#readme) | 🌌 | ![NPM LTS 4.12 Version](https://img.shields.io/npm/v/eslint-plugin-warp-drive/lts-4-12?label&color=bbbbbb) | ![NPM LTS Version](https://img.shields.io/npm/v/eslint-plugin-warp-drive/lts?label&color=0096ff) | ![NPM Stable Version](https://img.shields.io/npm/v/eslint-plugin-warp-drive/latest?label&color=90EE90) | ![NPM Beta Version](https://img.shields.io/npm/v/eslint-plugin-warp-drive/beta?label&color=ff00ff) | ![NPM Canary Version](https://img.shields.io/npm/v/eslint-plugin-warp-drive/canary?label&color=FFBF00) | | [@ember-data/graph](./packages/graph#readme) | 🌌 | ![NPM LTS 4.12 Version](https://img.shields.io/npm/v/@ember-data/graph/lts-4-12?label&color=bbbbbb) | ![NPM LTS Version](https://img.shields.io/npm/v/@ember-data/graph/lts?label&color=0096ff) | ![NPM Stable Version](https://img.shields.io/npm/v/@ember-data/graph/latest?label&color=90EE90) | ![NPM Beta Version](https://img.shields.io/npm/v/@ember-data/graph/beta?label&color=ff00ff) | ![NPM Canarye Version](https://img.shields.io/npm/v/@ember-data/graph/canary?label&color=FFBF00) | | [@warp-drive/holodeck](./packages/holodeck#readme) | 🌌 | ![NPM LTS 4.12 Version](https://img.shields.io/npm/v/@warp-drive/holodeck/lts-4-12?label&color=bbbbbb) | ![NPM LTS Version](https://img.shields.io/npm/v/@warp-drive/holodeck/lts?label&color=0096ff) | ![NPM Stable Version](https://img.shields.io/npm/v/@warp-drive/holodeck/latest?label&color=90EE90) | ![NPM Beta Version](https://img.shields.io/npm/v/@warp-drive/holodeck/beta?label&color=ff00ff) | ![NPM Canary Version](https://img.shields.io/npm/v/@warp-drive/holodeck/canary?label&color=FFBF00) | | [@ember-data/json-api](./packages/json-api#readme) | 🌌🐹 | ![NPM LTS 4.12 Version](https://img.shields.io/npm/v/@ember-data/json-api/lts-4-12?label&color=bbbbbb) | ![NPM LTS Version](https://img.shields.io/npm/v/@ember-data/json-api/lts?label&color=0096ff) | ![NPM Stable Version](https://img.shields.io/npm/v/@ember-data/json-api/latest?label&color=90EE90) | ![NPM Beta Version](https://img.shields.io/npm/v/@ember-data/json-api/beta?label&color=ff00ff) | ![NPM Canary Version](https://img.shields.io/npm/v/@ember-data/json-api/canary?label&color=FFBF00) | diff --git a/config/eslint/ignore.js b/config/eslint/ignore.js index 8f901c5d9fe..2bd95aa5f76 100644 --- a/config/eslint/ignore.js +++ b/config/eslint/ignore.js @@ -18,6 +18,7 @@ const RULES = [ '.git/*', '.broccoli-cache/*', 'unstable-preview-types/*', + 'vite.config.mjs.timestamp-*', // # Special Cases 'docs/*', diff --git a/config/eslint/node.js b/config/eslint/node.js index 03f6a09c5c1..7bb1b3e50da 100644 --- a/config/eslint/node.js +++ b/config/eslint/node.js @@ -71,6 +71,7 @@ export function esm(config) { 'diagnostic.js', 'diagnostic.mjs', 'eslint.config.mjs', + 'vite.config.mjs', 'holodeck.js', 'holodeck.mjs', 'rollup.config.mjs', diff --git a/config/eslint/typescript.js b/config/eslint/typescript.js index d3dc0f80923..ec9cf68d603 100644 --- a/config/eslint/typescript.js +++ b/config/eslint/typescript.js @@ -44,7 +44,7 @@ export function rules(config = {}) { '@typescript-eslint/no-import-type-side-effects': 'error', '@typescript-eslint/no-inferrable-types': 'error', '@typescript-eslint/no-meaningless-void-operator': 'error', - '@typescript-eslint/no-throw-literal': 'error', + '@typescript-eslint/only-throw-error': 'error', // Many failures for these; they seem intentional so I don't want to just auto-fix: // '@typescript-eslint/no-unnecessary-boolean-literal-compare': 'error', // '@typescript-eslint/no-unnecessary-condition': 'error', @@ -123,6 +123,8 @@ export function browser(config) { parser: parser(), parserOptions: { project: './tsconfig.json', + // projectService: true, + // tsconfigRootDir: import.meta.dirname, extraFileExtensions: ['.gts', '.gjs'], }, /** @type {2022} */ diff --git a/config/package.json b/config/package.json index d7cf14a96b0..076c5dfa326 100644 --- a/config/package.json +++ b/config/package.json @@ -6,21 +6,22 @@ "dependencies": { "@babel/cli": "^7.24.5", "@babel/core": "^7.24.5", + "@babel/eslint-parser": "7.25.8", "@rollup/plugin-babel": "^6.0.4", - "@typescript-eslint/eslint-plugin": "^7.13.0", - "@typescript-eslint/parser": "^7.13.0", - "typescript-eslint": "^7.13.0", + "@typescript-eslint/eslint-plugin": "^8.10.0", + "@typescript-eslint/parser": "^8.10.0", + "typescript-eslint": "^8.10.0", "@embroider/addon-dev": "^4.3.1", "@eslint/js": "^8.57.0", "globals": "^15.2.0", - "ember-eslint-parser": "^0.4.3", - "eslint": "^8.57.0", + "ember-eslint-parser": "^0.5.2", + "eslint": "^9.12.0", "eslint-config-prettier": "^9.1.0", - "eslint-plugin-import": "^2.29.1", - "eslint-plugin-mocha": "^10.4.3", - "eslint-plugin-n": "^16.6.2", - "eslint-plugin-qunit": "^8.1.1", - "eslint-plugin-simple-import-sort": "^12.1.0", + "eslint-plugin-import": "^2.31.0", + "eslint-plugin-mocha": "^10.5.0", + "eslint-plugin-n": "^17.11.0", + "eslint-plugin-qunit": "^8.1.2", + "eslint-plugin-simple-import-sort": "^12.1.1", "rollup": "^4.17.2", "typescript": "^5.4.5", "vite": "^5.2.11", diff --git a/packages/-ember-data/package.json b/packages/-ember-data/package.json index 58de4e3b633..468b857fb40 100644 --- a/packages/-ember-data/package.json +++ b/packages/-ember-data/package.json @@ -152,7 +152,7 @@ "@ember/test-helpers": "^3.3.0", "@warp-drive/internal-config": "workspace:5.4.0-alpha.112", "ember-source": "~5.8.0", - "eslint": "^8.57.0", + "eslint": "^9.12.0", "pnpm-sync-dependencies-meta-injected": "0.0.14", "vite": "^5.2.11", "typescript": "^5.4.5", diff --git a/packages/-warp-drive/src/-private/shared/the-big-list.ts b/packages/-warp-drive/src/-private/shared/the-big-list.ts index 63668da9a6f..451c461a91f 100644 --- a/packages/-warp-drive/src/-private/shared/the-big-list.ts +++ b/packages/-warp-drive/src/-private/shared/the-big-list.ts @@ -19,9 +19,11 @@ export const Main = [ '@warp-drive/ember', '@warp-drive/holodeck', '@warp-drive/schema-record', + '@warp-drive/experiments', '@warp-drive/schema', 'ember-data', 'eslint-plugin-ember-data', + 'eslint-plugin-warp-drive', 'warp-drive', ]; diff --git a/packages/adapter/src/-private/utils/fetch.ts b/packages/adapter/src/-private/utils/fetch.ts index b43e4219bc5..dc279595180 100644 --- a/packages/adapter/src/-private/utils/fetch.ts +++ b/packages/adapter/src/-private/utils/fetch.ts @@ -1,6 +1,6 @@ import { assert } from '@warp-drive/build-config/macros'; -type FetchFunction = (input: RequestInfo, init?: RequestInit | undefined) => Promise; +type FetchFunction = (input: RequestInfo, init?: RequestInit) => Promise; let _fetch: (() => FetchFunction) | null = null; type MockRequest = { protocol?: string; get(key: string): string | undefined }; @@ -26,7 +26,6 @@ export function getFetchFunction(): FetchFunction { const httpRegex = /^https?:\/\//; const protocolRelativeRegex = /^\/\//; - // eslint-disable-next-line no-inner-declarations function parseRequest(request: MockRequest) { if (request === null) { throw new Error( @@ -38,7 +37,6 @@ export function getFetchFunction(): FetchFunction { return [request.get('host'), protocol]; } - // eslint-disable-next-line no-inner-declarations function buildAbsoluteUrl(url: string) { if (protocolRelativeRegex.test(url)) { const [host] = parseRequest(REQUEST); @@ -50,7 +48,6 @@ export function getFetchFunction(): FetchFunction { return url; } - // eslint-disable-next-line no-inner-declarations function patchedFetch(input: string | { href: string } | RequestInfo, options?: RequestInit) { if (input && typeof input === 'object' && 'href' in input) { const url = buildAbsoluteUrl(input.href); @@ -65,7 +62,7 @@ export function getFetchFunction(): FetchFunction { } _fetch = () => patchedFetch; - } catch (e) { + } catch { throw new Error(`Unable to create a compatible 'fetch' for FastBoot with node-fetch`); } } diff --git a/packages/adapter/src/rest.ts b/packages/adapter/src/rest.ts index bbb7b62aacb..9a0bd605cdc 100644 --- a/packages/adapter/src/rest.ts +++ b/packages/adapter/src/rest.ts @@ -1055,7 +1055,7 @@ class RESTAdapter extends Adapter.extend(BuildURLMixin) { if (response.ok && !(payload instanceof Error)) { return fetchSuccessHandler(this, payload, response, requestData); } else { - // eslint-disable-next-line @typescript-eslint/no-throw-literal + // eslint-disable-next-line @typescript-eslint/only-throw-error throw fetchErrorHandler(this, payload, response, null, requestData); } } else { @@ -1180,7 +1180,7 @@ class RESTAdapter extends Adapter.extend(BuildURLMixin) { try { json = JSON.parse(responseText); - } catch (e) { + } catch { // ignored } @@ -1281,6 +1281,7 @@ class RESTAdapter extends Adapter.extend(BuildURLMixin) { } } +// eslint-disable-next-line @typescript-eslint/no-empty-object-type interface RESTAdapter extends MixtBuildURLMixin {} function ajaxSuccess( @@ -1293,10 +1294,12 @@ function ajaxSuccess( try { response = adapter.handleResponse(responseData.status, responseData.headers, payload, requestData); } catch (error) { + // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors return Promise.reject(error); } if (response && response.isAdapterError) { + // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors return Promise.reject(response); } else { return response; @@ -1526,6 +1529,7 @@ function execjQAjax( hash.error = function (jqXHR, textStatus, errorThrown: Error | string) { const error = ajaxErrorHandler(adapter, jqXHR, errorThrown, requestData); + // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors reject(error); }; diff --git a/packages/codemods/package.json b/packages/codemods/package.json index d8de7fe8aa3..d8ab4c60587 100644 --- a/packages/codemods/package.json +++ b/packages/codemods/package.json @@ -43,7 +43,7 @@ "@types/bun": "^1.1.4", "@types/jscodeshift": "0.11.11", "@warp-drive/internal-config": "workspace:5.4.0-alpha.112", - "eslint": "^8.57.0", + "eslint": "^9.12.0", "pnpm-sync-dependencies-meta-injected": "0.0.14", "qunit": "^2.20.1" }, diff --git a/packages/diagnostic/server/bun/fetch.js b/packages/diagnostic/server/bun/fetch.js index 2a9d82e20a7..c8421eb4dd7 100644 --- a/packages/diagnostic/server/bun/fetch.js +++ b/packages/diagnostic/server/bun/fetch.js @@ -1,3 +1,4 @@ +/* eslint-disable n/no-unsupported-features/node-builtins */ import chalk from 'chalk'; import path from 'path'; diff --git a/packages/diagnostic/src/-types.ts b/packages/diagnostic/src/-types.ts index e9510a75838..f840abbf39b 100644 --- a/packages/diagnostic/src/-types.ts +++ b/packages/diagnostic/src/-types.ts @@ -90,6 +90,7 @@ export interface Diagnostic { satisfies(actual: J, expected: T, message?: string): void; } +// eslint-disable-next-line @typescript-eslint/no-empty-object-type export interface TestContext {} export type GlobalCallback = () => void | Promise; diff --git a/packages/diagnostic/src/internals/run.ts b/packages/diagnostic/src/internals/run.ts index b3985b34d48..8f04f0e2a5a 100644 --- a/packages/diagnostic/src/internals/run.ts +++ b/packages/diagnostic/src/internals/run.ts @@ -50,10 +50,12 @@ export async function runTest( testReport.start = instrument() && performance.mark(`test:${test.module.moduleName} > ${test.name}:start`); const Assert = new Diagnostic(DelegatingReporter, Config, test, testReport); + // eslint-disable-next-line @typescript-eslint/no-unused-expressions groupLogs() && console.groupCollapsed(test.name); DelegatingReporter.onTestStart(testReport); if (test.skip) { + // eslint-disable-next-line @typescript-eslint/no-unused-expressions groupLogs() && console.groupEnd(); testReport.end = instrument() && performance.mark(`test:${test.module.moduleName} > ${test.name}:end`); testReport.measure = @@ -93,6 +95,7 @@ export async function runTest( } Assert._finalize(); + // eslint-disable-next-line @typescript-eslint/no-unused-expressions groupLogs() && console.groupEnd(); testReport.end = instrument() && performance.mark(`test:${test.module.moduleName} > ${test.name}:end`); testReport.measure = @@ -112,6 +115,7 @@ export async function runModule( return; } + // eslint-disable-next-line @typescript-eslint/no-unused-expressions groupLogs() && console.groupCollapsed(module.name); const moduleReport: ModuleReport = { name: module.moduleName, @@ -178,6 +182,7 @@ export async function runModule( for (const hook of Config.globalHooks.afterModule) { await hook(); } + // eslint-disable-next-line @typescript-eslint/no-unused-expressions groupLogs() && console.groupEnd(); moduleReport.end = instrument() && performance.mark(`module:${module.moduleName}:end`); moduleReport.measure = diff --git a/packages/diagnostic/src/legacy/equiv.ts b/packages/diagnostic/src/legacy/equiv.ts index fa9a6a111c2..e30233bdeef 100644 --- a/packages/diagnostic/src/legacy/equiv.ts +++ b/packages/diagnostic/src/legacy/equiv.ts @@ -1,4 +1,4 @@ -/* eslint-disable @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-return,@typescript-eslint/no-unsafe-call,@typescript-eslint/ban-types,@typescript-eslint/no-unsafe-member-access */ +/* eslint-disable @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-return,@typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access */ /* * The utils below are from QUnit to support deepEqual. */ @@ -276,6 +276,7 @@ const entryTypeCallbacks = { typeof actual.constructor !== 'undefined' && typeof actual[i] === 'function' && typeof expected[i] === 'function' && + // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type (actual[i] as Function).toString() === (expected[i] as Function).toString() ) { continue; @@ -303,6 +304,7 @@ const entryTypeCallbacks = { typeof expected.constructor !== 'undefined' && typeof expected[i] === 'function' && typeof actual[i] === 'function' && + // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type (expected[i] as Function).toString() === (actual[i] as Function).toString() ) { continue; diff --git a/packages/diagnostic/src/reporters/dom.ts b/packages/diagnostic/src/reporters/dom.ts index 3d580d0f1e9..94c7608c93e 100644 --- a/packages/diagnostic/src/reporters/dom.ts +++ b/packages/diagnostic/src/reporters/dom.ts @@ -102,11 +102,13 @@ export class DOMReporter implements Reporter { }); if (compatTestReport.failed > 0 || test.result.failed) { + // eslint-disable-next-line @typescript-eslint/no-unused-expressions this.settings.params.debug.value && console.log(test, compatTestReport); } this._socket.emit('test-finish', compatTestReport); } else if (test.result.failed) { + // eslint-disable-next-line @typescript-eslint/no-unused-expressions this.settings.params.debug.value && console.log(test); } diff --git a/packages/eslint-plugin-ember-data/src/index.js b/packages/eslint-plugin-ember-data/src/index.js deleted file mode 100644 index f8c3771edaa..00000000000 --- a/packages/eslint-plugin-ember-data/src/index.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - rules: {}, -}; diff --git a/packages/eslint-plugin-ember-data/CHANGELOG.md b/packages/eslint-plugin-warp-drive/CHANGELOG.md similarity index 97% rename from packages/eslint-plugin-ember-data/CHANGELOG.md rename to packages/eslint-plugin-warp-drive/CHANGELOG.md index 208b47ac1c5..173815a5949 100644 --- a/packages/eslint-plugin-ember-data/CHANGELOG.md +++ b/packages/eslint-plugin-warp-drive/CHANGELOG.md @@ -1,4 +1,4 @@ -# eslint-plugin-ember-data Changelog +# eslint-plugin-warp-drive Changelog ## v0.0.2-alpha.71 (2024-06-15) diff --git a/packages/eslint-plugin-warp-drive/README.md b/packages/eslint-plugin-warp-drive/README.md new file mode 100644 index 00000000000..9dc37464e63 --- /dev/null +++ b/packages/eslint-plugin-warp-drive/README.md @@ -0,0 +1,26 @@ +# eslint-plugin-warp-drive + +> [!TIP] +> This Package is also available as eslint-plugin-ember-data + +## Rules + +- 🛠️ has Autofix +- 〽️ has Partial Autofix +- ✅ Recommended +- 💜 TypeScript Aware + +**🏷️ Categories** + +- 🐞 Helps prevent buggy code +- ⚡️ Helps prevent performance issues +- 🏆 Enforces a best practice + +| Rule | Description | 🏷️ | ✨ | +| ---- | ----------- | -- | -- | +| [no-create-record-rerender](./docs/no-create-record-rerender.md) | Helps avoid patterns that often lead to excess or broken renders | 🐞⚡️ | ✅ | +| [no-invalid-relationships](./docs/no-invalid-relationships.md) | Ensures the basic part of relationship configuration is setup appropriately | 🏆 | ✅ | +| [no-legacy-request-patterns](./docs/no-legacy-request-patterns.md) | Restricts usage of deprecated or discouraged request patterns | 🏆 | ✅ | +| [no-external-request-patterns](./docs/no-external-request-patterns.md) | Restricts usage of discouraged non-warp-drive request patterns | 🏆 | ✅ | + +## Usage diff --git a/packages/eslint-plugin-warp-drive/docs/index.md b/packages/eslint-plugin-warp-drive/docs/index.md new file mode 100644 index 00000000000..b2db35c059f --- /dev/null +++ b/packages/eslint-plugin-warp-drive/docs/index.md @@ -0,0 +1,8 @@ +# eslint-plugin-warp-drive + +## Rules + +- [no-create-record-rerender](./no-create-record-rerender.md) +- [no-invalid-relationships](./no-invalid-relationships.md) +- [no-legacy-request-patterns](./no-legacy-request-patterns.md) +- [no-external-request-patterns](./no-external-request-patterns.md) diff --git a/packages/eslint-plugin-warp-drive/docs/no-create-record-rerender.md b/packages/eslint-plugin-warp-drive/docs/no-create-record-rerender.md new file mode 100644 index 00000000000..79ff20d0bb3 --- /dev/null +++ b/packages/eslint-plugin-warp-drive/docs/no-create-record-rerender.md @@ -0,0 +1,134 @@ +# eslint-plugin-warp-drive + +| Rule | 🏷️ | ✨ | +| ---- | -- | -- | +| `no-create-record-rerender` | 🐞⚡️ | ✅ | + +> [!Note] +> This rule helps applications avoid patterns that often lead to excess or broken renders. + +`store.createRecord` creates a record available to +the application as a whole. For instance: say we create a new `'user'` and add it to the `friends` relationship of `user:2`. When we do this, two distinct +changes are immediately observable to the entirety of +the application: + +- the list of all users is updated (notifying the addition to the LiveArray used by `peekAll` and `findAll`) +- the membership of the `friends` array is immediately updated. + +If these updates occur *during* a render, one of several outcomes might occur: + +- parts of the screen might show an incorrect state +- the whole screen might re-render immediately once the current render completes (this is known as a backtracking re-render) +- an error might be thrown due to a backtracking re-render being detected + +For this reason, the rule restricts `createRecord` from being used inside constructors, getters, or class properties as these typically compute their value during a render. + +Instead, applications should create new records while responding to a user interaction or from within routing hooks, prior to the application initiating a render. + +### Incorrect Code + +```gjs +import Component from '@glimmer/component'; +import { tracked } from '@glimmer/tracking'; +import { on } from '@ember/modifier'; + +class MyForm extends Component { + @service store; + // ERROR: Cannot call `store.createRecord` in a class property initializer. + // Calling `store.createRecord` inside constructors, getters, and class + // properties can cause issues with re-renders. + model = this.store.createRecord('user'); + + +} + +export default ParentComponent extends Component { + @tracked isShowingForm = false; + + @action rerenderWithForm() { + this.isShowingForm = true; + } + + +} +``` + +### Correct Code + +```gjs +// app/components/parent-component.gts +import Component from '@glimmer/component'; +import { tracked } from '@glimmer/tracking'; +import { on } from '@ember/modifier'; + +class MyForm extends Component { + +} + +export default class ParentComponent extends Component { + @tracked isShowingForm = false; + + rerenderForm = () => { + this.model = this.store.createRecord('user'); + this.isShowingForm = true; + } + + +} +``` + +### In a Pinch + +In cases where refactoring to creating a new record in model hooks or while responding to user interactions is impractical, a cached promise pattern may be used. + +Note however, this approach effectively *intentionally embraces* +the two-render approach, but in a way in which each render can be +performed safely. + +```ts +import Component from '@glimmer/component'; +import { cached } from '@glimmer/tracking'; +import { getPromiseState } from '@warp-drive/ember'; +import { service } from '@ember/service'; + +async function createUser() { + // we must await something asynchronous + // before creating the record to ensure + // we are not part of the current render anymore + await Promise.resolve(); + return store.createRecord('user', {}); +} + +class CreateUser extends Component { + @service store; + + // by memoizing this promise, we ensure it is stable + // (doesn't recompute each time we access it) + @cached + get newUserPromise() { + return createUser(this.store); + } + + @cached + get user() { + const state = getPromiseState(this.newUserPromise); + return state.result ?? null; + } + + +} +``` diff --git a/packages/eslint-plugin-warp-drive/docs/no-external-request-patterns.md b/packages/eslint-plugin-warp-drive/docs/no-external-request-patterns.md new file mode 100644 index 00000000000..29193d77cda --- /dev/null +++ b/packages/eslint-plugin-warp-drive/docs/no-external-request-patterns.md @@ -0,0 +1,11 @@ +# eslint-plugin-warp-drive + +| Rule | 🏷️ | ✨ | +| ---- | -- | -- | +| `no-external-request-patterns` | 🏆 | ✅ | + +> [!Note] +> This rule disallows non-warp-drive patterns which make requests that don't +> follow the recommended RequestManager approach. + + diff --git a/packages/eslint-plugin-warp-drive/docs/no-invalid-relationships.md b/packages/eslint-plugin-warp-drive/docs/no-invalid-relationships.md new file mode 100644 index 00000000000..7aa68743c5e --- /dev/null +++ b/packages/eslint-plugin-warp-drive/docs/no-invalid-relationships.md @@ -0,0 +1,56 @@ +# eslint-plugin-warp-drive + +| Rule | 🏷️ | ✨ | +| ---- | -- | -- | +| `no-invalid-relationships` | 🏆 | ✅ | + +> [!TIP] +> A partial/complete autofix for this rule is possible but has not been implemented. +> An autofix PR would be a welcome addition. + +> [!Note] +> Ensures relationship configuration is setup appropriately + +This rule ensures that the `async` and `inverse` properties are specified in `@belongsTo` and `@hasMany` decorators in EmberData models. + +## Rule Details + +This rule disallows: + +- Using `@belongsTo` without specifying the `async` and `inverse` properties. +- Using `@hasMany` without specifying the `async` and `inverse` properties. + +### Notes + +- `async` may be either `true` or `false`, the historical default when unspecified was `true` +- `inverse` may be either the name of the field on the model on the other side of the relationship or `null` +- See the [relationships guide](https://github.com/emberjs/data/blob/main/guides/relationships/index.md) for more information on valid configurations + +## Examples + +Examples of **incorrect** code for this rule: + +```js +import Model, { belongsTo, hasMany } from '@ember-data/model'; + +export default class FolderModel extends Model { + @hasMany('folder', { inverse: 'parent' }) children; + @belongsTo('folder', { inverse: 'children' }) parent; +} +``` + +Examples of **correct** code for this rule: + +```js +import Model, { belongsTo, hasMany } from '@ember-data/model'; + +export default class FolderModel extends Model { + @hasMany('folder', { async: true, inverse: 'parent' }) children; + @belongsTo('folder', { async: true, inverse: 'children' }) parent; +} +``` + +## References + +- [Deprecation Guide](https://deprecations.emberjs.com/id/ember-data-deprecate-non-strict-relationships) +- [Relationship Guide](https://github.com/emberjs/data/blob/main/guides/relationships/index.md) diff --git a/packages/eslint-plugin-warp-drive/docs/no-legacy-request-patterns.md b/packages/eslint-plugin-warp-drive/docs/no-legacy-request-patterns.md new file mode 100644 index 00000000000..e542a209f03 --- /dev/null +++ b/packages/eslint-plugin-warp-drive/docs/no-legacy-request-patterns.md @@ -0,0 +1,15 @@ +# eslint-plugin-warp-drive + +| Rule | 🏷️ | ✨ | +| ---- | -- | -- | +| `no-legacy-request-patterns` | 🏆 | ✅ | + +> [!TIP] +> A partial autofix for this rule is possible but has not been implemented. +> An autofix PR would be a welcome addition. + +> [!Note] +> This rule disallows using methods which make requests that don't follow the +> recommended RequestManager approach. + + diff --git a/packages/eslint-plugin-ember-data/eslint.config.mjs b/packages/eslint-plugin-warp-drive/eslint.config.mjs similarity index 100% rename from packages/eslint-plugin-ember-data/eslint.config.mjs rename to packages/eslint-plugin-warp-drive/eslint.config.mjs diff --git a/packages/eslint-plugin-warp-drive/package.json b/packages/eslint-plugin-warp-drive/package.json new file mode 100644 index 00000000000..215f06fd003 --- /dev/null +++ b/packages/eslint-plugin-warp-drive/package.json @@ -0,0 +1,34 @@ +{ + "name": "eslint-plugin-warp-drive", + "description": "ESLint rules for Applications using WarpDrive or EmberData", + "main": "./src/index.js", + "version": "0.0.2-alpha.97", + "private": false, + "repository": { + "type": "git", + "url": "https://github.com/emberjs/data.git", + "directory": "packages/eslint-plugin-warp-drive" + }, + "volta": { + "extends": "../../package.json" + }, + "dependencies": { + "requireindex": "^1.2.0" + }, + "devDependencies": { + "@warp-drive/internal-config": "workspace:5.4.0-alpha.112", + "@babel/plugin-proposal-decorators": "7.25.7", + "@babel/core": "^7.24.5", + "eslint": "^9.12.0", + "mocha": "^10.4.0" + }, + "files": [ + "src", + "docs", + "CHANGELOG.md", + "README.md" + ], + "scripts": { + "test": "mocha tests" + } +} diff --git a/packages/eslint-plugin-warp-drive/src/index.js b/packages/eslint-plugin-warp-drive/src/index.js new file mode 100644 index 00000000000..75af6920396 --- /dev/null +++ b/packages/eslint-plugin-warp-drive/src/index.js @@ -0,0 +1,7 @@ +'use strict'; + +const requireIndex = require('requireindex'); + +module.exports = { + rules: requireIndex(`${__dirname}/rules`), +}; diff --git a/packages/eslint-plugin-ember-data/src/rules/.gitkeep b/packages/eslint-plugin-warp-drive/src/rules/.gitkeep similarity index 100% rename from packages/eslint-plugin-ember-data/src/rules/.gitkeep rename to packages/eslint-plugin-warp-drive/src/rules/.gitkeep diff --git a/packages/eslint-plugin-warp-drive/src/rules/no-create-record-rerender.js b/packages/eslint-plugin-warp-drive/src/rules/no-create-record-rerender.js new file mode 100644 index 00000000000..1abdd1d6419 --- /dev/null +++ b/packages/eslint-plugin-warp-drive/src/rules/no-create-record-rerender.js @@ -0,0 +1,164 @@ +// @ts-check + +const messageId = 'noCreateRecordRerender'; +const createRecordExpression = 'CallExpression[callee.property.name="createRecord"]'; +const emberObjectExtendExpression = 'CallExpression[callee.property.name="extend"]'; +const forbiddenParentMethodKeyNames = [ + 'init', + 'initRecord', // legacy modals + 'didReceiveAttrs', + 'willRender', + 'didInsertElement', + 'didRender', + 'didUpdateAttrs', + 'willUpdate', + 'willDestroyElement', + 'willClearRender', + 'didDestroyElement', +]; + +/** @type {import('eslint').Rule.RuleModule} */ +module.exports = { + meta: { + type: 'problem', + docs: { + description: 'Disallow use of `store.createRecord` in getters, constructors, and class properties', + category: 'Possible Errors', + recommended: true, + url: 'https://github.com/emberjs/data/tree/main/packages/eslint-plugin-warp-drive/docs/rules/no-create-record-rerender.md', + }, + messages: { + [messageId]: + 'Cannot call `store.createRecord` in {{location}}. Calling `store.createRecord` inside constructors, getters, and class properties can cause issues with re-renders.', + }, + }, + + create(context) { + return { + /** + * Handle class constructor + * @param {import('eslint').Rule.Node} node + */ + [`MethodDefinition[kind="constructor"] ${createRecordExpression}`](node) { + const maybeParentFunction = getParentFunction(node); + if (maybeParentFunction && !parentFunctionIsConstructor(maybeParentFunction)) { + return; + } + context.report({ + node, + messageId, + data: { location: 'a constructor' }, + }); + }, + + /** + * Handle class getter + * @param {import('eslint').Rule.Node} node + */ + [`MethodDefinition[kind="get"] ${createRecordExpression}`](node) { + context.report({ + node, + messageId, + data: { location: 'a getter' }, + }); + }, + + /** + * Handle class property initializer + * @param {import('eslint').Rule.Node} node + */ + [`PropertyDefinition ${createRecordExpression}`](node) { + if (getParentFunction(node)) { + return; + } + context.report({ + node, + messageId, + data: { location: 'a class property initializer' }, + }); + }, + + /** + * Handle lifecycle hooks in a class + * @param {import('eslint').Rule.Node} node + */ + [`MethodDefinition[key.name=/${forbiddenParentMethodKeyNames.join('|')}/] FunctionExpression ${createRecordExpression}`]( + node + ) { + const maybeParentFunction = getParentFunction(node); + if (maybeParentFunction && !parentFunctionIsInit(maybeParentFunction)) { + return; + } + context.report({ + node, + messageId, + data: { location: 'a lifecycle hook' }, + }); + }, + + /** + * Handle the init method in an EmberObject + * @param {import('eslint').Rule.Node} node + */ + [`${emberObjectExtendExpression} Property[key.name=/${forbiddenParentMethodKeyNames.join('|')}/] FunctionExpression ${createRecordExpression}`]( + node + ) { + const maybeParentFunction = getParentFunction(node); + if (maybeParentFunction && !parentFunctionIsInit(maybeParentFunction)) { + return; + } + context.report({ + node, + messageId, + data: { location: 'a lifecycle hook' }, + }); + }, + + /** + * Handle a property initializer in an EmberObject + * @param {import('eslint').Rule.Node} node + */ + [`${emberObjectExtendExpression} Property > ${createRecordExpression}`](node) { + context.report({ + node, + messageId, + data: { location: 'an object property initializer' }, + }); + }, + }; + }, +}; + +function getParentFunction(/** @type {import('eslint').Rule.Node} */ node) { + if (node.parent) { + if (node.parent.type === 'ArrowFunctionExpression' || node.parent.type === 'FunctionExpression') { + return node.parent; + } else if (node.parent.type === 'ClassBody') { + return null; + } + return getParentFunction(node.parent); + } + return null; +} + +/** + * + * @param {import('eslint').Rule.Node} maybeParentFunction + * @returns {boolean} + */ +function parentFunctionIsConstructor(maybeParentFunction) { + return 'kind' in maybeParentFunction.parent && maybeParentFunction.parent.kind === 'constructor'; +} + +/** + * + * @param {import('eslint').Rule.Node} maybeParentFunction + * @returns {boolean} + */ +function parentFunctionIsInit(maybeParentFunction) { + return ( + 'key' in maybeParentFunction.parent && + maybeParentFunction.parent.key.type === 'Identifier' && + forbiddenParentMethodKeyNames.includes(maybeParentFunction.parent.key.name) + ); +} diff --git a/packages/eslint-plugin-warp-drive/src/rules/no-external-request-patterns.js b/packages/eslint-plugin-warp-drive/src/rules/no-external-request-patterns.js new file mode 100644 index 00000000000..77d33d238ba --- /dev/null +++ b/packages/eslint-plugin-warp-drive/src/rules/no-external-request-patterns.js @@ -0,0 +1,154 @@ +'use strict'; + +const AJAX_SERVICE_NAMES = new Set(['apiAjax', 'ajax', 'najax']); +const METHOD_OBJECT_NAMES = new Set(['$']); +const OBJECT_PROPERTY_NAMES = new Set([ + 'get', + 'post', + 'put', + 'delete', + 'request', + 'patch', + 'query', + 'ajax', + 'fetch', + 'GET', + 'POST', + 'PUT', + 'DELETE', + 'PATCH', + 'QUERY', +]); +const ANY_METHOD_NAMES = new Set(['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'QUERY']); +const OBJECT_NAMES = new Set(['$', 'jQuery', 'jQ', 'najax']); +const FUNCTION_NAMES = new Set(['fetch', 'najax', 'GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'QUERY']); +const CONSTRUCTOR_NAMES = new Set(['XMLHttpRequest']); +const RULE_ID = 'warp-drive.no-external-request-patterns'; + +/** @type {import('eslint').Rule.RuleModule} */ +module.exports = { + meta: { + type: 'problem', + messages: { + [RULE_ID]: `Use \`store.request()\` instead of \`{{ objectName }}.{{propertyName}}()\``, + [`${RULE_ID}.no-method`]: `Use \`store.request()\` instead of \`{{functionName}}()\``, + }, + docs: { + description: 'Restricts usage of discouraged non-warp-drive request patterns', + category: 'Best Practices', + recommended: true, + url: 'https://github.com/emberjs/data/tree/main/packages/eslint-plugin-warp-drive/docs/rules/no-external-request-patterns.md', + }, + }, + + create(context) { + return { + NewExpression(node) { + if (CONSTRUCTOR_NAMES.has(node.callee.name)) { + context.report({ + node, + messageId: `${RULE_ID}.no-method`, + data: { functionName: node.callee.name }, + }); + } + }, + CallExpression(node) { + // only match call expressions that are member expressions + // e.g. ignore `foo()` + if (node.callee.type !== 'MemberExpression') { + // check for function names + if (node.callee.type === 'Identifier' && FUNCTION_NAMES.has(node.callee.name)) { + context.report({ + node, + messageId: `${RULE_ID}.no-method`, + data: { functionName: node.callee.name }, + }); + } + + return; + } + + // ignore computed expressions + // e.g. ignore `foo[bar]()` + if (node.callee.computed) { + return; + } + + const propertyName = node.callee.property.name; + + // ignore computed member expressions + // e.g. ignore `foo[bar].baz()` + if (node.callee.object.type === 'MemberExpression' && node.callee.object.computed) { + // unless we match one of ANY_METHOD_NAMES + if (ANY_METHOD_NAMES.has(propertyName)) { + context.report({ + node, + messageId: RULE_ID, + data: { objectName: '', propertyName }, + }); + } + return; + } + + const type = node.callee.object.type; + + if (type !== 'ThisExpression' && type !== 'Identifier' && type !== 'MemberExpression') { + // anything else we just don't even wanna try + // for instance `/expr/.test(val)` is a valid call expression + return; + } + + if (type !== 'ThisExpression') { + // check for common object names + if (OBJECT_NAMES.has(node.callee.object.name)) { + if (OBJECT_PROPERTY_NAMES.has(propertyName)) { + context.report({ + node, + messageId: RULE_ID, + data: { objectName: node.callee.object.name, propertyName }, + }); + } + return; + } + } + + const objectName = + // store.findRecord() + node.callee.object.type === 'Identifier' + ? node.callee.object.name + : // this.findRecord() + node.callee.object.type === 'ThisExpression' + ? 'this' + : // this.store.findRecord() + node.callee.object.property.name; + + if (METHOD_OBJECT_NAMES.has(objectName)) { + if (OBJECT_PROPERTY_NAMES.has(propertyName)) { + context.report({ + node, + messageId: RULE_ID, + data: { objectName, propertyName }, + }); + } + return; + } + if (AJAX_SERVICE_NAMES.has(objectName)) { + // all use of apiAjax is discouraged so we print this regardless of what the method is. + context.report({ + node, + messageId: RULE_ID, + data: { objectName, propertyName }, + }); + return; + } + if (ANY_METHOD_NAMES.has(propertyName)) { + context.report({ + node, + messageId: RULE_ID, + data: { objectName, propertyName }, + }); + } + }, + }; + }, +}; diff --git a/packages/eslint-plugin-warp-drive/src/rules/no-invalid-relationships.js b/packages/eslint-plugin-warp-drive/src/rules/no-invalid-relationships.js new file mode 100644 index 00000000000..0779d0bc8ed --- /dev/null +++ b/packages/eslint-plugin-warp-drive/src/rules/no-invalid-relationships.js @@ -0,0 +1,65 @@ +/** @type {import('eslint').Rule.RuleModule} */ +module.exports = { + meta: { + type: 'suggestion', + docs: { + description: 'require inverse to be specified in @belongsTo and @hasMany decorators', + category: 'Best Practices', + recommended: true, + url: 'https://github.com/emberjs/data/tree/main/packages/eslint-plugin-warp-drive/docs/rules/no-invalid-relationships.md', + }, + schema: [], + }, + + create(context) { + return { + CallExpression(node) { + const decorator = + node.parent.type === 'Decorator' && ['belongsTo', 'hasMany'].includes(node.callee.name) && node; + + if (decorator) { + const args = decorator.arguments; + const hasAsync = args.some( + (arg) => arg.type === 'ObjectExpression' && arg.properties.some((prop) => prop.key.name === 'async') + ); + const hasBooleanAsync = args.some( + (arg) => + arg.type === 'ObjectExpression' && + arg.properties.some((prop) => prop.key.name === 'async' && typeof prop.value.value === 'boolean') + ); + const hasInverse = args.some( + (arg) => arg.type === 'ObjectExpression' && arg.properties.some((prop) => prop.key.name === 'inverse') + ); + + if (!hasAsync) { + context.report({ + node, + message: 'The @{{decorator}} decorator requires an `async` property to be specified.', + data: { + decorator: decorator.callee.name, + }, + }); + } else if (!hasBooleanAsync) { + context.report({ + node, + message: 'The @{{decorator}} decorator requires an `async` property to be specified as a boolean.', + data: { + decorator: decorator.callee.name, + }, + }); + } + + if (!hasInverse) { + context.report({ + node, + message: 'The @{{decorator}} decorator requires an `inverse` property to be specified.', + data: { + decorator: decorator.callee.name, + }, + }); + } + } + }, + }; + }, +}; diff --git a/packages/eslint-plugin-warp-drive/src/rules/no-legacy-request-patterns.js b/packages/eslint-plugin-warp-drive/src/rules/no-legacy-request-patterns.js new file mode 100644 index 00000000000..9c0caddf4cc --- /dev/null +++ b/packages/eslint-plugin-warp-drive/src/rules/no-legacy-request-patterns.js @@ -0,0 +1,102 @@ +'use strict'; + +const STORE_METHOD_NAMES = new Set([ + 'findRecord', + 'findAll', + 'query', + 'queryRecord', + 'adapterFor', + 'serializerFor', + 'saveRecord', + 'peekRecord', + 'peekAll', +]); +const STORE_SERVICE_NAMES = new Set(['store', 'db', 'v2Store', 'v1Store']); +const MODEL_METHOD_NAMES = new Set(['save', 'destroyRecord', 'reload']); +const RULE_ID = 'warp-drive.no-legacy-request-patterns'; + +/** @type {import('eslint').Rule.RuleModule} */ +module.exports = { + meta: { + type: 'problem', + messages: { + [RULE_ID]: `Use \`store.request()\` instead of \`{{ objectName }}.{{propertyName}}()\``, + }, + docs: { + description: 'require the use of `store.request()` instead of legacy request patterns', + category: 'Best Practices', + recommended: true, + url: 'https://github.com/emberjs/data/tree/main/packages/eslint-plugin-warp-drive/docs/rules/no-legacy-request-patterns.md', + }, + }, + + create(context) { + return { + CallExpression(node) { + // only match call expressions that are member expressions + // e.g. ignore `foo()` + if (node.callee.type !== 'MemberExpression') { + return; + } + + // ignore computed expressions + // e.g. ignore `foo[bar]()` + if (node.callee.computed) { + return; + } + + const propertyName = node.callee.property.name; + + // ignore computed member expressions + // e.g. ignore `foo[bar].baz()` + if (node.callee.object.type === 'MemberExpression' && node.callee.object.computed) { + // unless we match one of MODEL_METHOD_NAMES + if (MODEL_METHOD_NAMES.has(propertyName)) { + context.report({ + node, + messageId: RULE_ID, + data: { objectName: 'record', propertyName }, + }); + } + return; + } + + const type = node.callee.object.type; + + if (type !== 'ThisExpression' && type !== 'Identifier' && type !== 'MemberExpression') { + // anything else we just don't even wanna try + // for instance `/expr/.test(val)` is a valid call expression + return; + } + + const objectName = + // store.findRecord() + node.callee.object.type === 'Identifier' + ? node.callee.object.name + : // this.findRecord() + node.callee.object.type === 'ThisExpression' + ? 'this' + : // this.store.findRecord() + node.callee.object.property.name; + + if (STORE_SERVICE_NAMES.has(objectName)) { + if (STORE_METHOD_NAMES.has(propertyName)) { + context.report({ + node, + messageId: RULE_ID, + data: { objectName, propertyName }, + }); + } + return; + } else if (MODEL_METHOD_NAMES.has(propertyName)) { + context.report({ + node, + messageId: RULE_ID, + data: { objectName, propertyName }, + }); + return; + } + }, + }; + }, +}; diff --git a/packages/eslint-plugin-warp-drive/tests/no-create-record-rerender.js b/packages/eslint-plugin-warp-drive/tests/no-create-record-rerender.js new file mode 100644 index 00000000000..79bffbb113f --- /dev/null +++ b/packages/eslint-plugin-warp-drive/tests/no-create-record-rerender.js @@ -0,0 +1,143 @@ +// @ts-nocheck +const rule = require('../src/rules/no-create-record-rerender'); +const RuleTester = require('eslint').RuleTester; + +const eslintTester = new RuleTester({ + languageOptions: { + parser: require('@babel/eslint-parser'), + ecmaVersion: 'latest', + sourceType: 'module', + parserOptions: { + requireConfigFile: false, + babelOptions: { + babelrc: false, + configFile: false, + plugins: [[require.resolve('@babel/plugin-proposal-decorators'), { legacy: true }]], + }, + }, + }, +}); + +eslintTester.run('no-create-record-rerender', rule, { + valid: [ + { + code: ` + export default class MyComponent extends Component { + @service store; + @action newThing() { + this.newThing = this.store.createRecord('thing'); + } + } + `, + }, + { + code: ` + export default class MyComponent extends Component { + @service store; + newThing = () => { + this.store.createRecord('thing'); + } + } + `, + }, + { + code: ` + export default class MyComponent extends Component { + @service store; + constructor() { + this.makeModel = () => this.store.createRecord('thing'); + } + } + `, + }, + { + code: ` + export default Component.extend({ + store: service(), + init() { + this.makeModel = () => this.store.createRecord('thing'); + } + }) + `, + }, + { + code: ` + const pojo = { + model: this.store.createRecord('thing') + }; + `, + }, + { + code: ` + const pojo = { + init() { + this.model = this.store.createRecord('thing'); + } + }; + `, + }, + ], + invalid: [ + { + code: ` + export default class MyComponent extends Component { + @service store; + constructor() { + this.model = this.store.createRecord('thing'); + } + } + `, + errors: [ + 'Cannot call `store.createRecord` in a constructor. Calling `store.createRecord` inside constructors, getters, and class properties can cause issues with re-renders.', + ], + }, + { + code: ` + export default class MyComponent extends Component { + @service store; + get myModel() { + return this.store.createRecord('thing'); + } + } + `, + errors: [ + 'Cannot call `store.createRecord` in a getter. Calling `store.createRecord` inside constructors, getters, and class properties can cause issues with re-renders.', + ], + }, + { + code: ` + export default class MyComponent extends Component { + @service store; + model = this.store.createRecord('thing'); + } + `, + errors: [ + 'Cannot call `store.createRecord` in a class property initializer. Calling `store.createRecord` inside constructors, getters, and class properties can cause issues with re-renders.', + ], + }, + { + code: ` + export default Component.extend({ + store: service(), + init() { + this.model = this.store.createRecord('foo'); + } + }) + `, + errors: [ + 'Cannot call `store.createRecord` in a lifecycle hook. Calling `store.createRecord` inside constructors, getters, and class properties can cause issues with re-renders.', + ], + }, + { + code: ` + export default Component.extend({ + store: service(), + model: this.store.createRecord('foo') + }) + `, + errors: [ + 'Cannot call `store.createRecord` in an object property initializer. Calling `store.createRecord` inside constructors, getters, and class properties can cause issues with re-renders.', + ], + }, + ], +}); diff --git a/packages/eslint-plugin-warp-drive/tests/no-external-request-patterns.js b/packages/eslint-plugin-warp-drive/tests/no-external-request-patterns.js new file mode 100644 index 00000000000..71f50142c7f --- /dev/null +++ b/packages/eslint-plugin-warp-drive/tests/no-external-request-patterns.js @@ -0,0 +1,199 @@ +// @ts-nocheck +const rule = require('../src/rules/no-external-request-patterns'); +const RuleTester = require('eslint').RuleTester; + +const eslintTester = new RuleTester({ + languageOptions: { + parser: require('@babel/eslint-parser'), + ecmaVersion: 'latest', + sourceType: 'module', + parserOptions: { + requireConfigFile: false, + babelOptions: { + babelrc: false, + configFile: false, + plugins: [[require.resolve('@babel/plugin-proposal-decorators'), { legacy: true }]], + }, + }, + }, +}); + +const errorId = 'warp-drive.no-external-request-patterns'; + +eslintTester.run('no-external-request-patterns', rule, { + valid: [ + { + code: ` + this.store.request(findRecord('user', '1')); + `, + }, + { + code: ` + store.request(findRecord('user', '1')); + `, + }, + { + code: ` + this.request('user', '1'); + `, + }, + { + code: ` + this.findRecord('user', '1'); + `, + }, + { + code: ` + findRecord('user', '1'); + `, + }, + { + code: ` + save(user); + `, + }, + { + code: ` + destroyRecord(user); + `, + }, + { + code: ` + reload(user); + `, + }, + { + code: ` + /expr/.test(val); + `, + }, + { + code: ` + // bad but we don't try to detect this + this[store].findRecord('user', '1'); + `, + }, + { + code: ` + // bad but we don't try to detect this + this.store[findRecord]('user', '1'); + `, + }, + ], + invalid: [ + { + code: ` + const foo = new XMLHttpRequest(); + `, + errors: [{ messageId: `${errorId}.no-method` }], + }, + { + code: ` + await fetch('/some-url'); + `, + errors: [{ messageId: `${errorId}.no-method` }], + }, + { + code: ` + this.$.get('/some-url'); + `, + errors: [{ messageId: `${errorId}` }], + }, + { + code: ` + $.get('/some-url'); + `, + errors: [{ messageId: `${errorId}` }], + }, + { + code: ` + jQ.get('/some-url'); + `, + errors: [{ messageId: `${errorId}` }], + }, + { + code: ` + jQuery.get('/some-url'); + `, + errors: [{ messageId: `${errorId}` }], + }, + { + code: ` + najax.get('/some-url'); + `, + errors: [{ messageId: `${errorId}` }], + }, + { + code: ` + this.najax.get('/some-url'); + `, + errors: [{ messageId: `${errorId}` }], + }, + { + code: ` + najax('/some-url'); + `, + errors: [{ messageId: `${errorId}.no-method` }], + }, + { + code: ` + this.apiAjax.get({}); + `, + errors: [{ messageId: errorId }], + }, + { + code: ` + this.ajax.get({}); + `, + errors: [{ messageId: errorId }], + }, + { + code: ` + this.apiAjax.request({}); + `, + errors: [{ messageId: errorId }], + }, + { + code: ` + this.ajax.request({}); + `, + errors: [{ messageId: errorId }], + }, + { + code: ` + this.apiAjax.delete({}); + `, + errors: [{ messageId: errorId }], + }, + { + code: ` + this.ajax.delete({}); + `, + errors: [{ messageId: errorId }], + }, + { + code: ` + this.apiAjax.post({}); + `, + errors: [{ messageId: errorId }], + }, + { + code: ` + this.ajax.post({}); + `, + errors: [{ messageId: errorId }], + }, + { + code: ` + anything.GET(); + `, + errors: [{ messageId: errorId }], + }, + { + code: ` + GET({}); + `, + errors: [{ messageId: `${errorId}.no-method` }], + }, + ], +}); diff --git a/packages/eslint-plugin-warp-drive/tests/no-invalid-relationships.js b/packages/eslint-plugin-warp-drive/tests/no-invalid-relationships.js new file mode 100644 index 00000000000..96f8f09924a --- /dev/null +++ b/packages/eslint-plugin-warp-drive/tests/no-invalid-relationships.js @@ -0,0 +1,218 @@ +'use strict'; + +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +const rule = require('../src/rules/no-invalid-relationships'); +const RuleTester = require('eslint').RuleTester; + +const parserOptions = { ecmaVersion: 2022, sourceType: 'module', requireConfigFile: false }; + +const ruleTester = new RuleTester({ + languageOptions: { + parser: require('@babel/eslint-parser'), + ecmaVersion: 'latest', + sourceType: 'module', + parserOptions: { + requireConfigFile: false, + babelOptions: { + babelrc: false, + configFile: false, + plugins: [[require.resolve('@babel/plugin-proposal-decorators'), { legacy: true }]], + }, + }, + }, +}); + +//------------------------------------------------------------------------------ +// Tests +//------------------------------------------------------------------------------ + +ruleTester.run('no-invalid-relationships', rule, { + valid: [ + `import Model, { belongsTo } from '@ember-data/model'; + + export default class extends Model { + @belongsTo('post', { async: true, inverse: 'comments' }) post; + }`, + `import Model, { hasMany } from '@ember-data/model'; + + export default class extends Model { + @hasMany('comment', { async: true, inverse: 'post' }) comments; + }`, + `import Model, { belongsTo, hasMany } from '@ember-data/model'; + + export default class extends Model { + @belongsTo('post', { async: false, inverse: 'comments' }) post; + @hasMany('user', { async: true, inverse: null }) owner; + }`, + ], + + invalid: [ + { + code: `import Model, { belongsTo } from '@ember-data/model'; + + export default class extends Model { + @belongsTo('post') post; + }`, + output: null, + errors: [ + { + message: 'The @belongsTo decorator requires an `async` property to be specified.', + type: 'CallExpression', + }, + { + message: 'The @belongsTo decorator requires an `inverse` property to be specified.', + type: 'CallExpression', + }, + ], + }, + { + code: `import Model, { belongsTo } from '@ember-data/model'; + + export default class extends Model { + @belongsTo('post', {}) post; + }`, + output: null, + errors: [ + { + message: 'The @belongsTo decorator requires an `async` property to be specified.', + type: 'CallExpression', + }, + { + message: 'The @belongsTo decorator requires an `inverse` property to be specified.', + type: 'CallExpression', + }, + ], + }, + { + code: `import Model, { belongsTo } from '@ember-data/model'; + + export default class extends Model { + @belongsTo('post', { async: 'comments'}) post; + }`, + output: null, + errors: [ + { + message: 'The @belongsTo decorator requires an `async` property to be specified as a boolean.', + type: 'CallExpression', + }, + { + message: 'The @belongsTo decorator requires an `inverse` property to be specified.', + type: 'CallExpression', + }, + ], + }, + { + code: `import Model, { belongsTo } from '@ember-data/model'; + + export default class extends Model { + @belongsTo('post', { async: true }) post; + }`, + output: null, + errors: [ + { + message: 'The @belongsTo decorator requires an `inverse` property to be specified.', + type: 'CallExpression', + }, + ], + }, + { + code: `import Model, { belongsTo } from '@ember-data/model'; + + export default class extends Model { + @belongsTo('post', { inverse: 'comments' }) post; + }`, + output: null, + errors: [ + { + message: 'The @belongsTo decorator requires an `async` property to be specified.', + type: 'CallExpression', + }, + ], + }, + { + code: `import Model, { hasMany } from '@ember-data/model'; + + export default class extends Model { + @hasMany('comment') comments; + }`, + output: null, + errors: [ + { + message: 'The @hasMany decorator requires an `async` property to be specified.', + type: 'CallExpression', + }, + { + message: 'The @hasMany decorator requires an `inverse` property to be specified.', + type: 'CallExpression', + }, + ], + }, + { + code: `import Model, { hasMany } from '@ember-data/model'; + + export default class extends Model { + @hasMany('comment', {}) comments; + }`, + output: null, + errors: [ + { + message: 'The @hasMany decorator requires an `async` property to be specified.', + type: 'CallExpression', + }, + { + message: 'The @hasMany decorator requires an `inverse` property to be specified.', + type: 'CallExpression', + }, + ], + }, + { + code: `import Model, { hasMany } from '@ember-data/model'; + + export default class extends Model { + @hasMany('comment', { async: 'comments'}) comments; + }`, + output: null, + errors: [ + { + message: 'The @hasMany decorator requires an `async` property to be specified as a boolean.', + type: 'CallExpression', + }, + { + message: 'The @hasMany decorator requires an `inverse` property to be specified.', + type: 'CallExpression', + }, + ], + }, + { + code: `import Model, { hasMany } from '@ember-data/model'; + + export default class extends Model { + @hasMany('comment', { async: true }) comments; + }`, + output: null, + errors: [ + { + message: 'The @hasMany decorator requires an `inverse` property to be specified.', + type: 'CallExpression', + }, + ], + }, + { + code: `import Model, { hasMany } from '@ember-data/model'; + + export default class extends Model { + @hasMany('comment', { inverse: 'post' }) comments; + }`, + output: null, + errors: [ + { + message: 'The @hasMany decorator requires an `async` property to be specified.', + type: 'CallExpression', + }, + ], + }, + ], +}); diff --git a/packages/eslint-plugin-warp-drive/tests/no-legacy-request-patterns.js b/packages/eslint-plugin-warp-drive/tests/no-legacy-request-patterns.js new file mode 100644 index 00000000000..81a352e1e83 --- /dev/null +++ b/packages/eslint-plugin-warp-drive/tests/no-legacy-request-patterns.js @@ -0,0 +1,133 @@ +// @ts-nocheck +const rule = require('../src/rules/no-legacy-request-patterns'); +const RuleTester = require('eslint').RuleTester; + +const eslintTester = new RuleTester({ + languageOptions: { + parser: require('@babel/eslint-parser'), + ecmaVersion: 'latest', + sourceType: 'module', + parserOptions: { + requireConfigFile: false, + babelOptions: { + babelrc: false, + configFile: false, + plugins: [[require.resolve('@babel/plugin-proposal-decorators'), { legacy: true }]], + }, + }, + }, +}); + +const errorId = 'warp-drive.no-legacy-request-patterns'; + +eslintTester.run('no-legacy-request-patterns', rule, { + valid: [ + { + code: ` + this.store.request(findRecord('user', '1')); + `, + }, + { + code: ` + store.request(findRecord('user', '1')); + `, + }, + { + code: ` + this.request('user', '1'); + `, + }, + { + code: ` + this.findRecord('user', '1'); + `, + }, + { + code: ` + findRecord('user', '1'); + `, + }, + { + code: ` + save(user); + `, + }, + { + code: ` + destroyRecord(user); + `, + }, + { + code: ` + reload(user); + `, + }, + { + code: ` + /expr/.test(val); + `, + }, + { + code: ` + // bad but we don't try to detect this + this[store].findRecord('user', '1'); + `, + }, + { + code: ` + // bad but we don't try to detect this + this.store[findRecord]('user', '1'); + `, + }, + ], + invalid: [ + { + code: ` + this.v2Store.findRecord('user', '1'); + `, + errors: [{ messageId: errorId }], + }, + { + code: ` + this.db.findRecord('user', '1'); + `, + errors: [{ messageId: errorId }], + }, + { + code: ` + store.findRecord('user', '1'); + `, + errors: [{ messageId: errorId }], + }, + { + code: ` + db.findRecord('user', '1'); + `, + errors: [{ messageId: errorId }], + }, + { + code: ` + anything.reload(); + `, + errors: [{ messageId: errorId }], + }, + { + code: ` + anything.save(); + `, + errors: [{ messageId: errorId }], + }, + { + code: ` + anything.destroyRecord(); + `, + errors: [{ messageId: errorId }], + }, + { + code: ` + this.destroyRecord(); + `, + errors: [{ messageId: errorId }], + }, + ], +}); diff --git a/packages/experiments/src/data-worker/fetch.ts b/packages/experiments/src/data-worker/fetch.ts index 6f9857827ca..469f7d10438 100644 --- a/packages/experiments/src/data-worker/fetch.ts +++ b/packages/experiments/src/data-worker/fetch.ts @@ -121,6 +121,7 @@ export class WorkerFetch { } send(event: RequestEventData | AbortEventData) { + // eslint-disable-next-line @typescript-eslint/no-unused-expressions this.worker instanceof SharedWorker ? this.worker.port.postMessage(event) : this.channel.port1.postMessage(event); } diff --git a/packages/experiments/src/image-worker/fetch.ts b/packages/experiments/src/image-worker/fetch.ts index a41b31833eb..9ed20fc6df9 100644 --- a/packages/experiments/src/image-worker/fetch.ts +++ b/packages/experiments/src/image-worker/fetch.ts @@ -68,6 +68,7 @@ export class ImageFetch { } _send(event: RequestEventData) { + // eslint-disable-next-line @typescript-eslint/no-unused-expressions this.worker instanceof SharedWorker ? this.worker.port.postMessage(event) : this.channel.port1.postMessage(event); } diff --git a/packages/graph/src/-private/debug/assert-polymorphic-type.ts b/packages/graph/src/-private/debug/assert-polymorphic-type.ts index 1855d91ea8f..db9cb188bc6 100644 --- a/packages/graph/src/-private/debug/assert-polymorphic-type.ts +++ b/packages/graph/src/-private/debug/assert-polymorphic-type.ts @@ -1,4 +1,4 @@ -/* eslint-disable no-inner-declarations, @typescript-eslint/no-shadow */ +/* eslint-disable @typescript-eslint/no-shadow */ import type { CacheCapabilitiesManager } from '@ember-data/store/types'; import { DEBUG } from '@warp-drive/build-config/env'; import { assert } from '@warp-drive/build-config/macros'; diff --git a/packages/json-api/src/-private/cache.ts b/packages/json-api/src/-private/cache.ts index 5be8a7feb9a..9ab95958189 100644 --- a/packages/json-api/src/-private/cache.ts +++ b/packages/json-api/src/-private/cache.ts @@ -357,7 +357,7 @@ export default class JSONAPICache implements Cache { const _data = JSON.parse(JSON.stringify(op)) as object; // eslint-disable-next-line no-console console.log(`EmberData | Operation - patch ${op.op}`, _data); - } catch (e) { + } catch { // eslint-disable-next-line no-console console.log(`EmberData | Operation - patch ${op.op}`, op); } @@ -386,7 +386,7 @@ export default class JSONAPICache implements Cache { const _data = JSON.parse(JSON.stringify(mutation)) as object; // eslint-disable-next-line no-console console.log(`EmberData | Mutation - update ${mutation.op}`, _data); - } catch (e) { + } catch { // eslint-disable-next-line no-console console.log(`EmberData | Mutation - update ${mutation.op}`, mutation); } @@ -513,7 +513,7 @@ export default class JSONAPICache implements Cache { upsert( identifier: StableRecordIdentifier, data: ExistingResourceObject, - calculateChanges?: boolean | undefined + calculateChanges?: boolean ): void | string[] { let changedKeys: string[] | undefined; const peeked = this.__safePeek(identifier, false); @@ -528,7 +528,7 @@ export default class JSONAPICache implements Cache { const _data = JSON.parse(JSON.stringify(data)) as object; // eslint-disable-next-line no-console console.log(`EmberData | Operation - upsert (${existed ? 'merge' : 'insert'})`, _data); - } catch (e) { + } catch { // eslint-disable-next-line no-console console.log(`EmberData | Operation - upsert (${existed ? 'merge' : 'insert'})`, data); } @@ -695,16 +695,13 @@ export default class JSONAPICache implements Cache { * @param identifier * @param createArgs */ - clientDidCreate( - identifier: StableRecordIdentifier, - options?: Record | undefined - ): Record { + clientDidCreate(identifier: StableRecordIdentifier, options?: Record): Record { if (LOG_MUTATIONS) { try { const _data = options ? (JSON.parse(JSON.stringify(options)) as object) : options; // eslint-disable-next-line no-console console.log(`EmberData | Mutation - clientDidCreate ${identifier.lid}`, _data); - } catch (e) { + } catch { // eslint-disable-next-line no-console console.log(`EmberData | Mutation - clientDidCreate ${identifier.lid}`, options); } @@ -975,7 +972,7 @@ export default class JSONAPICache implements Cache { * @param identifier * @param errors */ - commitWasRejected(identifier: StableRecordIdentifier, errors?: ApiError[] | undefined): void { + commitWasRejected(identifier: StableRecordIdentifier, errors?: ApiError[]): void { const cached = this.__peek(identifier, false); if (cached.inflightAttrs) { const keys = Object.keys(cached.inflightAttrs); @@ -1256,7 +1253,7 @@ export default class JSONAPICache implements Cache { delete cached.localAttrs[basePath]; delete cached.changes![basePath]; } - } catch (e) { + } catch { // noop } } diff --git a/packages/legacy-compat/src/legacy-network-handler/legacy-network-handler.ts b/packages/legacy-compat/src/legacy-network-handler/legacy-network-handler.ts index 82e50aae51f..baf9c53e612 100644 --- a/packages/legacy-compat/src/legacy-network-handler/legacy-network-handler.ts +++ b/packages/legacy-compat/src/legacy-network-handler/legacy-network-handler.ts @@ -194,7 +194,7 @@ function saveRecord(context: StoreRequestContext): Promise { const payloadCopy: unknown = payload ? JSON.parse(JSON.stringify(payload)) : payload; // eslint-disable-next-line no-console console.log(`EmberData | Payload - ${operation}`, payloadCopy); - } catch (e) { + } catch { // eslint-disable-next-line no-console console.log(`EmberData | Payload - ${operation}`, payload); } @@ -397,6 +397,7 @@ function findAll(context: StoreRequestContext): Promise { let fetch: Promise | undefined; if (shouldReload) { + // eslint-disable-next-line @typescript-eslint/no-unused-expressions maybeRecordArray && (maybeRecordArray.isUpdating = true); fetch = _findAll(adapter, store, type, snapshotArray, context.request, true); } else { @@ -407,6 +408,7 @@ function findAll(context: StoreRequestContext): Promise { (options.backgroundReload !== false && (!adapter.shouldBackgroundReloadAll || adapter.shouldBackgroundReloadAll(store, snapshotArray))) ) { + // eslint-disable-next-line @typescript-eslint/no-unused-expressions maybeRecordArray && (maybeRecordArray.isUpdating = true); void _findAll(adapter, store, type, snapshotArray, context.request, false); } diff --git a/packages/legacy-compat/src/legacy-network-handler/snapshot.ts b/packages/legacy-compat/src/legacy-network-handler/snapshot.ts index 06936856fe6..1198930fc9a 100644 --- a/packages/legacy-compat/src/legacy-network-handler/snapshot.ts +++ b/packages/legacy-compat/src/legacy-network-handler/snapshot.ts @@ -87,6 +87,7 @@ export class Snapshot { the values. */ if (hasRecord) { + // eslint-disable-next-line @typescript-eslint/no-unused-expressions this._attributes; } diff --git a/packages/model/src/-private/attr.type-test.ts b/packages/model/src/-private/attr.type-test.ts index 33b4c026475..f0e1fe4462f 100644 --- a/packages/model/src/-private/attr.type-test.ts +++ b/packages/model/src/-private/attr.type-test.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-unused-expressions */ import { expectTypeOf } from 'expect-type'; import type { TransformName } from '@warp-drive/core-types/symbols'; diff --git a/packages/model/src/-private/belongs-to.type-test.ts b/packages/model/src/-private/belongs-to.type-test.ts index af85ef8d246..9c66f43f19e 100644 --- a/packages/model/src/-private/belongs-to.type-test.ts +++ b/packages/model/src/-private/belongs-to.type-test.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-unused-expressions */ import { expectTypeOf } from 'expect-type'; import type { Type } from '@warp-drive/core-types/symbols'; diff --git a/packages/model/src/-private/has-many.type-test.ts b/packages/model/src/-private/has-many.type-test.ts index 6091cf8890b..70b7aa3a651 100644 --- a/packages/model/src/-private/has-many.type-test.ts +++ b/packages/model/src/-private/has-many.type-test.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-unused-expressions */ import { expectTypeOf } from 'expect-type'; import type { Type } from '@warp-drive/core-types/symbols'; diff --git a/packages/model/src/-private/model.ts b/packages/model/src/-private/model.ts index 222e8219535..c003b428c6a 100644 --- a/packages/model/src/-private/model.ts +++ b/packages/model/src/-private/model.ts @@ -112,7 +112,7 @@ function computeOnce(target: object, propertyName: string, desc: PropertyDescrip */ interface Model { - serialize(this: T, options?: Record | undefined): unknown; + serialize(this: T, options?: Record): unknown; destroyRecord(this: T, options?: Record): Promise; unloadRecord(this: T): void; changedAttributes(this: T): ChangedAttributesHash; diff --git a/packages/model/src/-private/model.type-test.ts b/packages/model/src/-private/model.type-test.ts index 851e3455eb4..cd2f2a9c09b 100644 --- a/packages/model/src/-private/model.type-test.ts +++ b/packages/model/src/-private/model.type-test.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-unused-expressions */ import { expectTypeOf } from 'expect-type'; import Store from '@ember-data/store'; diff --git a/packages/model/src/-private/promise-many-array.ts b/packages/model/src/-private/promise-many-array.ts index e153ed5c824..8aa0873ac0b 100644 --- a/packages/model/src/-private/promise-many-array.ts +++ b/packages/model/src/-private/promise-many-array.ts @@ -51,6 +51,7 @@ export class PromiseManyArray { // shouldn't be needed, but ends up being needed // for computed chains even in 4.x if (DEPRECATE_COMPUTED_CHAINS) { + // eslint-disable-next-line @typescript-eslint/no-unused-expressions this['[]']; } return this.content ? this.content.length : 0; @@ -222,7 +223,7 @@ if (DEPRECATE_COMPUTED_CHAINS) { // requires that the tag `'[]'` be notified // on the ArrayProxy in order for `{{#each}}` // to recompute. We entangle the '[]' tag from content - // eslint-disable-next-line @typescript-eslint/no-floating-promises + Object.defineProperty(PromiseManyArray.prototype, '[]', desc); } diff --git a/packages/model/src/-private/references/belongs-to.ts b/packages/model/src/-private/references/belongs-to.ts index dd21e8747e0..f5363c091f9 100644 --- a/packages/model/src/-private/references/belongs-to.ts +++ b/packages/model/src/-private/references/belongs-to.ts @@ -326,6 +326,7 @@ export default class BelongsToReference< } _resource() { + // eslint-disable-next-line @typescript-eslint/no-unused-expressions this._ref; // subscribe const cache = this.store.cache; return cache.getRelationship(this.___identifier, this.key) as SingleResourceRelationship< diff --git a/packages/model/src/-private/references/has-many.ts b/packages/model/src/-private/references/has-many.ts index 6c665c4b08f..2b13820b149 100644 --- a/packages/model/src/-private/references/has-many.ts +++ b/packages/model/src/-private/references/has-many.ts @@ -149,6 +149,7 @@ export default class HasManyReference< @cached @compat get identifiers(): StableRecordIdentifier>[] { + // eslint-disable-next-line @typescript-eslint/no-unused-expressions this._ref; // consume the tracked prop const resource = this._resource(); @@ -608,6 +609,7 @@ export default class HasManyReference< if (!loaded) { // subscribe to changes // for when we are not loaded yet + // eslint-disable-next-line @typescript-eslint/no-unused-expressions this._ref; return null; } diff --git a/packages/request/src/-private/utils.ts b/packages/request/src/-private/utils.ts index 04479bd24db..bb771672a13 100644 --- a/packages/request/src/-private/utils.ts +++ b/packages/request/src/-private/utils.ts @@ -195,6 +195,7 @@ export function executeNextHandler( if (_isCacheHandler) { setRequestResult(owner.requestId, { isError: true, result: ensureDoc(owner, e, true) }); } + // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors outcome = Promise.reject>(e); } const future = createFuture(owner); diff --git a/packages/request/src/fetch.ts b/packages/request/src/fetch.ts index d89671112e3..ed5ef6a6dd4 100644 --- a/packages/request/src/fetch.ts +++ b/packages/request/src/fetch.ts @@ -169,7 +169,6 @@ const Fetch = { context.setStream(stream!.readable); } - // eslint-disable-next-line no-constant-condition while (true) { // we manually read the stream instead of using `response.json()` // or `response.text()` because if we need to stream the body diff --git a/packages/store/src/-private/legacy-model-support/record-reference.ts b/packages/store/src/-private/legacy-model-support/record-reference.ts index 065e1b46fdc..fb7d8ea8ea1 100644 --- a/packages/store/src/-private/legacy-model-support/record-reference.ts +++ b/packages/store/src/-private/legacy-model-support/record-reference.ts @@ -69,6 +69,7 @@ export default class RecordReference { @return {String} The id of the record. */ id() { + // eslint-disable-next-line @typescript-eslint/no-unused-expressions this._ref; // consume the tracked prop return this.___identifier.id; } diff --git a/packages/store/src/-private/record-arrays/native-proxy-type-fix.ts b/packages/store/src/-private/record-arrays/native-proxy-type-fix.ts index e78e384d3ad..fc222a39c89 100644 --- a/packages/store/src/-private/record-arrays/native-proxy-type-fix.ts +++ b/packages/store/src/-private/record-arrays/native-proxy-type-fix.ts @@ -19,7 +19,7 @@ interface ProxyHandler { * @param newTarget The constructor that was originally called. * @internal */ - // eslint-disable-next-line @typescript-eslint/ban-types + // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type construct?(target: T, argArray: any[], newTarget: Function): object; /** diff --git a/packages/store/src/-private/store-service.ts b/packages/store/src/-private/store-service.ts index 05fdba7fd97..80f3e646edd 100644 --- a/packages/store/src/-private/store-service.ts +++ b/packages/store/src/-private/store-service.ts @@ -2255,7 +2255,7 @@ export class Store extends BaseClass { const data: unknown = JSON.parse(JSON.stringify(jsonApiDoc)) as unknown; // eslint-disable-next-line no-console console.log('EmberData | Payload - push', data); - } catch (e) { + } catch { // eslint-disable-next-line no-console console.log('EmberData | Payload - push', jsonApiDoc); } diff --git a/packages/tracking/src/-private.ts b/packages/tracking/src/-private.ts index cb6aac318d4..87b1a0bdcb5 100644 --- a/packages/tracking/src/-private.ts +++ b/packages/tracking/src/-private.ts @@ -78,6 +78,7 @@ export function subscribe(obj: Tag | Signal): void { } consumeTag(obj.tag); } else { + // eslint-disable-next-line @typescript-eslint/no-unused-expressions obj.ref; } } @@ -169,6 +170,7 @@ function flushTransaction() { } consumeTag(obj.tag); } else { + // eslint-disable-next-line @typescript-eslint/no-unused-expressions obj.ref; } }); @@ -415,7 +417,6 @@ export function createSignal(obj: T, key: string): Signal { }; if (DEBUG) { - // eslint-disable-next-line no-inner-declarations function tryGet(prop: string): T1 | undefined { try { return obj[prop as keyof typeof obj] as unknown as T1; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 00ee6d5b49d..863ebed8c5d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -131,6 +131,9 @@ importers: '@babel/core': specifier: ^7.24.5 version: 7.24.5(supports-color@8.1.1) + '@babel/eslint-parser': + specifier: 7.25.8 + version: 7.25.8(@babel/core@7.24.5)(eslint@9.12.0) '@embroider/addon-dev': specifier: ^4.3.1 version: 4.3.1(@glint/template@1.4.0)(rollup@4.22.4) @@ -141,35 +144,35 @@ importers: specifier: ^6.0.4 version: 6.0.4(@babel/core@7.24.5)(rollup@4.22.4) '@typescript-eslint/eslint-plugin': - specifier: ^7.13.0 - version: 7.13.0(@typescript-eslint/parser@7.13.0)(eslint@8.57.0)(typescript@5.4.5) + specifier: ^8.10.0 + version: 8.10.0(@typescript-eslint/parser@8.10.0)(eslint@9.12.0)(typescript@5.4.5) '@typescript-eslint/parser': - specifier: ^7.13.0 - version: 7.13.0(eslint@8.57.0)(typescript@5.4.5) + specifier: ^8.10.0 + version: 8.10.0(eslint@9.12.0)(typescript@5.4.5) ember-eslint-parser: - specifier: ^0.4.3 - version: 0.4.3(@babel/core@7.24.5)(@typescript-eslint/parser@7.13.0)(eslint@8.57.0) + specifier: ^0.5.2 + version: 0.5.2(@babel/core@7.24.5)(@typescript-eslint/parser@8.10.0)(eslint@9.12.0) eslint: - specifier: ^8.57.0 - version: 8.57.0 + specifier: ^9.12.0 + version: 9.12.0 eslint-config-prettier: specifier: ^9.1.0 - version: 9.1.0(eslint@8.57.0) + version: 9.1.0(eslint@9.12.0) eslint-plugin-import: - specifier: ^2.29.1 - version: 2.29.1(@typescript-eslint/parser@7.13.0)(eslint@8.57.0) + specifier: ^2.31.0 + version: 2.31.0(@typescript-eslint/parser@8.10.0)(eslint@9.12.0) eslint-plugin-mocha: - specifier: ^10.4.3 - version: 10.4.3(eslint@8.57.0) + specifier: ^10.5.0 + version: 10.5.0(eslint@9.12.0) eslint-plugin-n: - specifier: ^16.6.2 - version: 16.6.2(eslint@8.57.0) + specifier: ^17.11.0 + version: 17.11.1(eslint@9.12.0) eslint-plugin-qunit: - specifier: ^8.1.1 - version: 8.1.1(eslint@8.57.0) + specifier: ^8.1.2 + version: 8.1.2(eslint@9.12.0) eslint-plugin-simple-import-sort: - specifier: ^12.1.0 - version: 12.1.0(eslint@8.57.0) + specifier: ^12.1.1 + version: 12.1.1(eslint@9.12.0) globals: specifier: ^15.2.0 version: 15.3.0 @@ -180,8 +183,8 @@ importers: specifier: ^5.4.5 version: 5.4.5 typescript-eslint: - specifier: ^7.13.0 - version: 7.13.0(eslint@8.57.0)(typescript@5.4.5) + specifier: ^8.10.0 + version: 8.10.0(eslint@9.12.0)(typescript@5.4.5) vite: specifier: ^5.2.11 version: 5.2.14(@types/node@20.14.2) @@ -271,8 +274,8 @@ importers: specifier: ~5.8.0 version: 5.8.0(@babel/core@7.24.5)(@glimmer/component@1.1.2)(@glint/template@1.4.0) eslint: - specifier: ^8.57.0 - version: 8.57.0 + specifier: ^9.12.0 + version: 9.12.0 pnpm-sync-dependencies-meta-injected: specifier: 0.0.14 version: 0.0.14 @@ -611,8 +614,8 @@ importers: specifier: workspace:5.4.0-alpha.112 version: link:../../config eslint: - specifier: ^8.57.0 - version: 8.57.0 + specifier: ^9.12.0 + version: 9.12.0 pnpm-sync-dependencies-meta-injected: specifier: 0.0.14 version: 0.0.14 @@ -924,6 +927,28 @@ importers: specifier: workspace:5.4.0-alpha.112 version: link:../../config + packages/eslint-plugin-warp-drive: + dependencies: + requireindex: + specifier: ^1.2.0 + version: 1.2.0 + devDependencies: + '@babel/core': + specifier: ^7.24.5 + version: 7.24.5(supports-color@8.1.1) + '@babel/plugin-proposal-decorators': + specifier: 7.25.7 + version: 7.25.7(@babel/core@7.24.5) + '@warp-drive/internal-config': + specifier: workspace:5.4.0-alpha.112 + version: link:../../config + eslint: + specifier: ^9.12.0 + version: 9.12.0 + mocha: + specifier: ^10.4.0 + version: 10.4.0 + packages/experiments: dependencies: '@embroider/macros': @@ -2234,8 +2259,8 @@ importers: specifier: workspace:5.4.0-alpha.112 version: link:../../config eslint: - specifier: ^8.57.0 - version: 8.57.0 + specifier: ^9.12.0 + version: 9.12.0 pnpm-sync-dependencies-meta-injected: specifier: 0.0.14 version: 0.0.14 @@ -4629,6 +4654,13 @@ packages: '@babel/highlight': 7.24.5 picocolors: 1.1.0 + /@babel/code-frame@7.25.7: + resolution: {integrity: sha512-0xZJFNE5XMpENsgfHYTw8FbX4kv53mFLn2i3XPoq69LyhYSCBJtitaHx9QnsVTrsogI4Z3+HtEfZ2/GFPOtf5g==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/highlight': 7.25.7 + picocolors: 1.1.0 + /@babel/compat-data@7.24.4: resolution: {integrity: sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ==} engines: {node: '>=6.9.0'} @@ -4655,16 +4687,16 @@ packages: transitivePeerDependencies: - supports-color - /@babel/eslint-parser@7.23.10(@babel/core@7.24.5)(eslint@8.57.0): - resolution: {integrity: sha512-3wSYDPZVnhseRnxRJH6ZVTNknBz76AEnyC+AYYhasjP3Yy23qz0ERR7Fcd2SHmYuSFJ2kY9gaaDd3vyqU09eSw==} + /@babel/eslint-parser@7.25.8(@babel/core@7.24.5)(eslint@9.12.0): + resolution: {integrity: sha512-Po3VLMN7fJtv0nsOjBDSbO1J71UhzShE9MuOSkWEV9IZQXzhZklYtzKZ8ZD/Ij3a0JBv1AG3Ny2L3jvAHQVOGg==} engines: {node: ^10.13.0 || ^12.13.0 || >=14.0.0} peerDependencies: '@babel/core': ^7.11.0 - eslint: ^7.5.0 || ^8.0.0 + eslint: ^7.5.0 || ^8.0.0 || ^9.0.0 dependencies: '@babel/core': 7.24.5(supports-color@8.1.1) '@nicolo-ribaudo/eslint-scope-5-internals': 5.1.1-v1 - eslint: 8.57.0 + eslint: 9.12.0 eslint-visitor-keys: 2.1.0 semver: 6.3.1 dev: false @@ -4678,12 +4710,27 @@ packages: '@jridgewell/trace-mapping': 0.3.25 jsesc: 2.5.2 + /@babel/generator@7.25.7: + resolution: {integrity: sha512-5Dqpl5fyV9pIAD62yK9P7fcA768uVPUyrQmqpqstHWgMma4feF1x/oFysBCVZLY5wJ2GkMUCdsNDnGZrPoR6rA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.25.8 + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + jsesc: 3.0.2 + /@babel/helper-annotate-as-pure@7.22.5: resolution: {integrity: sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.24.5 + /@babel/helper-annotate-as-pure@7.25.7: + resolution: {integrity: sha512-4xwU8StnqnlIhhioZf1tqnVWeQ9pvH/ujS8hRfw/WOza+/a+1qv69BWNy+oY231maTCWgKWhfBU7kDpsds6zAA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.25.8 + /@babel/helper-builder-binary-assignment-operator-visitor@7.22.15: resolution: {integrity: sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==} engines: {node: '>=6.9.0'} @@ -4717,6 +4764,23 @@ packages: '@babel/helper-split-export-declaration': 7.24.5 semver: 6.3.1 + /@babel/helper-create-class-features-plugin@7.25.7(@babel/core@7.24.5): + resolution: {integrity: sha512-bD4WQhbkx80mAyj/WCm4ZHcF4rDxkoLFO6ph8/5/mQ3z4vAzltQXAmbc7GvVJx5H+lk5Mi5EmbTeox5nMGCsbw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.24.5(supports-color@8.1.1) + '@babel/helper-annotate-as-pure': 7.25.7 + '@babel/helper-member-expression-to-functions': 7.25.7 + '@babel/helper-optimise-call-expression': 7.25.7 + '@babel/helper-replace-supers': 7.25.7(@babel/core@7.24.5) + '@babel/helper-skip-transparent-expression-wrappers': 7.25.7 + '@babel/traverse': 7.25.7 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + /@babel/helper-create-regexp-features-plugin@7.22.15(@babel/core@7.24.5): resolution: {integrity: sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==} engines: {node: '>=6.9.0'} @@ -4765,6 +4829,15 @@ packages: dependencies: '@babel/types': 7.24.5 + /@babel/helper-member-expression-to-functions@7.25.7: + resolution: {integrity: sha512-O31Ssjd5K6lPbTX9AAYpSKrZmLeagt9uwschJd+Ixo6QiRyfpvgtVQp8qrDR9UNFjZ8+DO34ZkdrN+BnPXemeA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/traverse': 7.25.7 + '@babel/types': 7.25.8 + transitivePeerDependencies: + - supports-color + /@babel/helper-module-imports@7.24.3: resolution: {integrity: sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==} engines: {node: '>=6.9.0'} @@ -4790,10 +4863,20 @@ packages: dependencies: '@babel/types': 7.24.5 + /@babel/helper-optimise-call-expression@7.25.7: + resolution: {integrity: sha512-VAwcwuYhv/AT+Vfr28c9y6SHzTan1ryqrydSTFGjU0uDJHw3uZ+PduI8plCLkRsDnqK2DMEDmwrOQRsK/Ykjng==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.25.8 + /@babel/helper-plugin-utils@7.24.5: resolution: {integrity: sha512-xjNLDopRzW2o6ba0gKbkZq5YWEBaK3PCyTOY1K2P/O07LGMhMqlMXPxwN4S5/RhWuCobT8z0jrlKGlYmeR1OhQ==} engines: {node: '>=6.9.0'} + /@babel/helper-plugin-utils@7.25.7: + resolution: {integrity: sha512-eaPZai0PiqCi09pPs3pAFfl/zYgGaE6IdXtYvmf0qlcDTd3WCtO7JWCcRd64e0EQrcYgiHibEZnOGsSY4QSgaw==} + engines: {node: '>=6.9.0'} + /@babel/helper-remap-async-to-generator@7.22.20(@babel/core@7.24.5): resolution: {integrity: sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==} engines: {node: '>=6.9.0'} @@ -4816,6 +4899,19 @@ packages: '@babel/helper-member-expression-to-functions': 7.24.5 '@babel/helper-optimise-call-expression': 7.22.5 + /@babel/helper-replace-supers@7.25.7(@babel/core@7.24.5): + resolution: {integrity: sha512-iy8JhqlUW9PtZkd4pHM96v6BdJ66Ba9yWSE4z0W4TvSZwLBPkyDsiIU3ENe4SmrzRBs76F7rQXTy1lYC49n6Lw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.24.5(supports-color@8.1.1) + '@babel/helper-member-expression-to-functions': 7.25.7 + '@babel/helper-optimise-call-expression': 7.25.7 + '@babel/traverse': 7.25.7 + transitivePeerDependencies: + - supports-color + /@babel/helper-simple-access@7.24.5: resolution: {integrity: sha512-uH3Hmf5q5n7n8mz7arjUlDOCbttY/DW4DYhE6FUsjKJ/oYC1kQQUvwEQWxRwUpX9qQKRXeqLwWxrqilMrf32sQ==} engines: {node: '>=6.9.0'} @@ -4828,6 +4924,15 @@ packages: dependencies: '@babel/types': 7.24.5 + /@babel/helper-skip-transparent-expression-wrappers@7.25.7: + resolution: {integrity: sha512-pPbNbchZBkPMD50K0p3JGcFMNLVUCuU/ABybm/PGNj4JiHrpmNyqqCphBk4i19xXtNV0JhldQJJtbSW5aUvbyA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/traverse': 7.25.7 + '@babel/types': 7.25.8 + transitivePeerDependencies: + - supports-color + /@babel/helper-split-export-declaration@7.24.5: resolution: {integrity: sha512-5CHncttXohrHk8GWOFCcCl4oRD9fKosWlIRgWm4ql9VYioKm52Mk2xsmoohvm7f3JoiLSM5ZgJuRaf5QZZYd3Q==} engines: {node: '>=6.9.0'} @@ -4838,10 +4943,18 @@ packages: resolution: {integrity: sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==} engines: {node: '>=6.9.0'} + /@babel/helper-string-parser@7.25.7: + resolution: {integrity: sha512-CbkjYdsJNHFk8uqpEkpCvRs3YRp9tY6FmFY7wLMSYuGYkrdUi7r2lc4/wqsvlHoMznX3WJ9IP8giGPq68T/Y6g==} + engines: {node: '>=6.9.0'} + /@babel/helper-validator-identifier@7.24.5: resolution: {integrity: sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==} engines: {node: '>=6.9.0'} + /@babel/helper-validator-identifier@7.25.7: + resolution: {integrity: sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg==} + engines: {node: '>=6.9.0'} + /@babel/helper-validator-option@7.23.5: resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==} engines: {node: '>=6.9.0'} @@ -4873,6 +4986,15 @@ packages: js-tokens: 4.0.0 picocolors: 1.1.0 + /@babel/highlight@7.25.7: + resolution: {integrity: sha512-iYyACpW3iW8Fw+ZybQK+drQre+ns/tKpXbNESfrhNnPLIklLbXr7MYJ6gPEd0iETGLOK+SxMjVvKb/ffmk+FEw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.25.7 + chalk: 2.4.2 + js-tokens: 4.0.0 + picocolors: 1.1.0 + /@babel/parser@7.24.5: resolution: {integrity: sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg==} engines: {node: '>=6.0.0'} @@ -4880,6 +5002,13 @@ packages: dependencies: '@babel/types': 7.24.5 + /@babel/parser@7.25.8: + resolution: {integrity: sha512-HcttkxzdPucv3nNFmfOOMfFf64KgdJVqm1KaCm25dPGMLElo9nsLvXeJECQg8UzPuBGLyTSA0ZzqCtDSzKTEoQ==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.25.8 + /@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.24.5(@babel/core@7.24.5): resolution: {integrity: sha512-LdXRi1wEMTrHVR4Zc9F8OewC3vdm5h4QB6L71zy6StmYeqGi1b3ttIO8UC+BfZKcH9jdr4aI249rBkm+3+YvHw==} engines: {node: '>=6.9.0'} @@ -4931,16 +5060,18 @@ packages: '@babel/helper-create-class-features-plugin': 7.24.5(@babel/core@7.24.5) '@babel/helper-plugin-utils': 7.24.5 - /@babel/plugin-proposal-decorators@7.24.1(@babel/core@7.24.5): - resolution: {integrity: sha512-zPEvzFijn+hRvJuX2Vu3KbEBN39LN3f7tW3MQO2LsIs57B26KU+kUc82BdAktS1VCM6libzh45eKGI65lg0cpA==} + /@babel/plugin-proposal-decorators@7.25.7(@babel/core@7.24.5): + resolution: {integrity: sha512-q1mqqqH0e1lhmsEQHV5U8OmdueBC2y0RFr2oUzZoFRtN3MvPmt2fsFRcNQAoGLTSNdHBFUYGnlgcRFhkBbKjPw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.24.5(supports-color@8.1.1) - '@babel/helper-create-class-features-plugin': 7.24.5(@babel/core@7.24.5) - '@babel/helper-plugin-utils': 7.24.5 - '@babel/plugin-syntax-decorators': 7.24.1(@babel/core@7.24.5) + '@babel/helper-create-class-features-plugin': 7.25.7(@babel/core@7.24.5) + '@babel/helper-plugin-utils': 7.25.7 + '@babel/plugin-syntax-decorators': 7.25.7(@babel/core@7.24.5) + transitivePeerDependencies: + - supports-color /@babel/plugin-proposal-private-methods@7.18.6(@babel/core@7.24.5): resolution: {integrity: sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==} @@ -5008,6 +5139,15 @@ packages: '@babel/core': 7.24.5(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.24.5 + /@babel/plugin-syntax-decorators@7.25.7(@babel/core@7.24.5): + resolution: {integrity: sha512-oXduHo642ZhstLVYTe2z2GSJIruU0c/W3/Ghr6A5yGMsVrvdnxO1z+3pbTcT7f3/Clnt+1z8D/w1r1f1SHaCHw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.5(supports-color@8.1.1) + '@babel/helper-plugin-utils': 7.25.7 + /@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.24.5): resolution: {integrity: sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==} peerDependencies: @@ -5842,6 +5982,14 @@ packages: '@babel/parser': 7.24.5 '@babel/types': 7.24.5 + /@babel/template@7.25.7: + resolution: {integrity: sha512-wRwtAgI3bAS+JGU2upWNL9lSlDcRCqD05BZ1n3X2ONLH1WilFP6O1otQjeMK/1g0pvYcXC7b/qVUB1keofjtZA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.25.7 + '@babel/parser': 7.25.8 + '@babel/types': 7.25.8 + /@babel/traverse@7.24.5(supports-color@8.1.1): resolution: {integrity: sha512-7aaBLeDQ4zYcUFDUD41lJc1fG8+5IU9DaNSJAgal866FGvmD5EbWQgnEC6kO1gGLsX0esNkfnJSndbTXA3r7UA==} engines: {node: '>=6.9.0'} @@ -5859,6 +6007,20 @@ packages: transitivePeerDependencies: - supports-color + /@babel/traverse@7.25.7: + resolution: {integrity: sha512-jatJPT1Zjqvh/1FyJs6qAHL+Dzb7sTb+xr7Q+gM1b+1oBsMsQQ4FkVKb6dFlJvLlVssqkRzV05Jzervt9yhnzg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.25.7 + '@babel/generator': 7.25.7 + '@babel/parser': 7.25.8 + '@babel/template': 7.25.7 + '@babel/types': 7.25.8 + debug: 4.3.7(supports-color@8.1.1) + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + /@babel/types@7.24.5: resolution: {integrity: sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ==} engines: {node: '>=6.9.0'} @@ -5867,6 +6029,14 @@ packages: '@babel/helper-validator-identifier': 7.24.5 to-fast-properties: 2.0.0 + /@babel/types@7.25.8: + resolution: {integrity: sha512-JWtuCu8VQsMladxVz/P4HzHUGCAwpuqacmowgXFs5XjxIgKuNjnLokQzuVjlTvIzODaDmpjT3oxcC48vyk9EWg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.25.7 + '@babel/helper-validator-identifier': 7.25.7 + to-fast-properties: 2.0.0 + /@cnakazawa/watch@1.0.4: resolution: {integrity: sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ==} engines: {node: '>=0.1.95'} @@ -6403,27 +6573,46 @@ packages: requiresBuild: true optional: true - /@eslint-community/eslint-utils@4.4.0(eslint@8.57.0): + /@eslint-community/eslint-utils@4.4.0(eslint@9.12.0): resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 dependencies: - eslint: 8.57.0 + eslint: 9.12.0 eslint-visitor-keys: 3.4.3 /@eslint-community/regexpp@4.10.0: resolution: {integrity: sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + dev: false + + /@eslint-community/regexpp@4.11.1: + resolution: {integrity: sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - /@eslint/eslintrc@2.1.4: - resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /@eslint/config-array@0.18.0: + resolution: {integrity: sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + '@eslint/object-schema': 2.1.4 + debug: 4.3.7(supports-color@8.1.1) + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + /@eslint/core@0.6.0: + resolution: {integrity: sha512-8I2Q8ykA4J0x0o7cg67FPVnehcqWTBehu/lmY+bolPFHGjh49YzGBMXTvpqVgEbBdvNCSxj6iFgiIyHzf03lzg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + /@eslint/eslintrc@3.1.0: + resolution: {integrity: sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dependencies: ajv: 6.12.6 - debug: 4.3.5(supports-color@8.1.1) - espree: 9.6.1 - globals: 13.24.0 + debug: 4.3.7(supports-color@8.1.1) + espree: 10.2.0 + globals: 14.0.0 ignore: 5.3.1 import-fresh: 3.3.0 js-yaml: 4.1.0 @@ -6435,6 +6624,21 @@ packages: /@eslint/js@8.57.0: resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: false + + /@eslint/js@9.12.0: + resolution: {integrity: sha512-eohesHH8WFRUprDNyEREgqP6beG6htMeUYeCpkEgBCieCMme5r9zFWjzAJp//9S+Kub4rqE+jXe9Cp1a7IYIIA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + /@eslint/object-schema@2.1.4: + resolution: {integrity: sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + /@eslint/plugin-kit@0.2.0: + resolution: {integrity: sha512-vH9PiIMMwvhCx31Af3HiGzsVNULDbyVkHXwlemn/B0TFj/00ho3y55efXrUZTfQipxoHC5u4xq6zblww1zm1Ig==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + levn: 0.4.1 /@gar/promisify@1.1.3: resolution: {integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==} @@ -6798,24 +7002,24 @@ packages: - supports-color dev: true - /@humanwhocodes/config-array@0.11.14: - resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} - engines: {node: '>=10.10.0'} - deprecated: Use @eslint/config-array instead + /@humanfs/core@0.19.0: + resolution: {integrity: sha512-2cbWIHbZVEweE853g8jymffCA+NCMiuqeECeBBLm8dg2oFdjuGJhgN4UAbI+6v0CKbbhvtXA4qV8YR5Ji86nmw==} + engines: {node: '>=18.18.0'} + + /@humanfs/node@0.16.5: + resolution: {integrity: sha512-KSPA4umqSG4LHYRodq31VDwKAvaTF4xmVlzM8Aeh4PlU1JQ3IG0wiA8C25d3RQ9nJyM3mBHyI53K06VVL/oFFg==} + engines: {node: '>=18.18.0'} dependencies: - '@humanwhocodes/object-schema': 2.0.3 - debug: 4.3.5(supports-color@8.1.1) - minimatch: 3.1.2 - transitivePeerDependencies: - - supports-color + '@humanfs/core': 0.19.0 + '@humanwhocodes/retry': 0.3.1 /@humanwhocodes/module-importer@1.0.1: resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} engines: {node: '>=12.22'} - /@humanwhocodes/object-schema@2.0.3: - resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} - deprecated: Use @eslint/object-schema instead + /@humanwhocodes/retry@0.3.1: + resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==} + engines: {node: '>=18.18'} /@inquirer/figures@1.0.1: resolution: {integrity: sha512-mtup3wVKia3ZwULPHcbs4Mor8Voi+iIXEWD7wCNbIO6lYR62oPCTQyrddi5OMYVXHzeCSoneZwJuS8sBvlEwDw==} @@ -7613,6 +7817,10 @@ packages: requiresBuild: true optional: true + /@rtsao/scc@1.1.0: + resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} + dev: false + /@rushstack/node-core-library@4.0.2: resolution: {integrity: sha512-hyES82QVpkfQMeBMteQUnrhASL/KHPhd7iJ8euduwNJG4mu2GSOKybf0rOEjOm1Wz7CwJEUm9y0yD7jg2C1bfg==} peerDependencies: @@ -7981,24 +8189,24 @@ packages: '@types/yargs-parser': 21.0.3 dev: true - /@typescript-eslint/eslint-plugin@7.13.0(@typescript-eslint/parser@7.13.0)(eslint@8.57.0)(typescript@5.4.5): - resolution: {integrity: sha512-FX1X6AF0w8MdVFLSdqwqN/me2hyhuQg4ykN6ZpVhh1ij/80pTvDKclX1sZB9iqex8SjQfVhwMKs3JtnnMLzG9w==} - engines: {node: ^18.18.0 || >=20.0.0} + /@typescript-eslint/eslint-plugin@8.10.0(@typescript-eslint/parser@8.10.0)(eslint@9.12.0)(typescript@5.4.5): + resolution: {integrity: sha512-phuB3hoP7FFKbRXxjl+DRlQDuJqhpOnm5MmtROXyWi3uS/Xg2ZXqiQfcG2BJHiN4QKyzdOJi3NEn/qTnjUlkmQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^7.0.0 - eslint: ^8.56.0 + '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 + eslint: ^8.57.0 || ^9.0.0 typescript: '*' peerDependenciesMeta: typescript: optional: true dependencies: - '@eslint-community/regexpp': 4.10.0 - '@typescript-eslint/parser': 7.13.0(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/scope-manager': 7.13.0 - '@typescript-eslint/type-utils': 7.13.0(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/utils': 7.13.0(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/visitor-keys': 7.13.0 - eslint: 8.57.0 + '@eslint-community/regexpp': 4.11.1 + '@typescript-eslint/parser': 8.10.0(eslint@9.12.0)(typescript@5.4.5) + '@typescript-eslint/scope-manager': 8.10.0 + '@typescript-eslint/type-utils': 8.10.0(eslint@9.12.0)(typescript@5.4.5) + '@typescript-eslint/utils': 8.10.0(eslint@9.12.0)(typescript@5.4.5) + '@typescript-eslint/visitor-keys': 8.10.0 + eslint: 9.12.0 graphemer: 1.4.0 ignore: 5.3.1 natural-compare: 1.4.0 @@ -8008,75 +8216,74 @@ packages: - supports-color dev: false - /@typescript-eslint/parser@7.13.0(eslint@8.57.0)(typescript@5.4.5): - resolution: {integrity: sha512-EjMfl69KOS9awXXe83iRN7oIEXy9yYdqWfqdrFAYAAr6syP8eLEFI7ZE4939antx2mNgPRW/o1ybm2SFYkbTVA==} - engines: {node: ^18.18.0 || >=20.0.0} + /@typescript-eslint/parser@8.10.0(eslint@9.12.0)(typescript@5.4.5): + resolution: {integrity: sha512-E24l90SxuJhytWJ0pTQydFT46Nk0Z+bsLKo/L8rtQSL93rQ6byd1V/QbDpHUTdLPOMsBCcYXZweADNCfOCmOAg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^8.56.0 + eslint: ^8.57.0 || ^9.0.0 typescript: '*' peerDependenciesMeta: typescript: optional: true dependencies: - '@typescript-eslint/scope-manager': 7.13.0 - '@typescript-eslint/types': 7.13.0 - '@typescript-eslint/typescript-estree': 7.13.0(typescript@5.4.5) - '@typescript-eslint/visitor-keys': 7.13.0 - debug: 4.3.5(supports-color@8.1.1) - eslint: 8.57.0 + '@typescript-eslint/scope-manager': 8.10.0 + '@typescript-eslint/types': 8.10.0 + '@typescript-eslint/typescript-estree': 8.10.0(typescript@5.4.5) + '@typescript-eslint/visitor-keys': 8.10.0 + debug: 4.3.7(supports-color@8.1.1) + eslint: 9.12.0 typescript: 5.4.5 transitivePeerDependencies: - supports-color dev: false - /@typescript-eslint/scope-manager@7.13.0: - resolution: {integrity: sha512-ZrMCe1R6a01T94ilV13egvcnvVJ1pxShkE0+NDjDzH4nvG1wXpwsVI5bZCvE7AEDH1mXEx5tJSVR68bLgG7Dng==} - engines: {node: ^18.18.0 || >=20.0.0} + /@typescript-eslint/scope-manager@8.10.0: + resolution: {integrity: sha512-AgCaEjhfql9MDKjMUxWvH7HjLeBqMCBfIaBbzzIcBbQPZE7CPh1m6FF+L75NUMJFMLYhCywJXIDEMa3//1A0dw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dependencies: - '@typescript-eslint/types': 7.13.0 - '@typescript-eslint/visitor-keys': 7.13.0 + '@typescript-eslint/types': 8.10.0 + '@typescript-eslint/visitor-keys': 8.10.0 dev: false - /@typescript-eslint/type-utils@7.13.0(eslint@8.57.0)(typescript@5.4.5): - resolution: {integrity: sha512-xMEtMzxq9eRkZy48XuxlBFzpVMDurUAfDu5Rz16GouAtXm0TaAoTFzqWUFPPuQYXI/CDaH/Bgx/fk/84t/Bc9A==} - engines: {node: ^18.18.0 || >=20.0.0} + /@typescript-eslint/type-utils@8.10.0(eslint@9.12.0)(typescript@5.4.5): + resolution: {integrity: sha512-PCpUOpyQSpxBn230yIcK+LeCQaXuxrgCm2Zk1S+PTIRJsEfU6nJ0TtwyH8pIwPK/vJoA+7TZtzyAJSGBz+s/dg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^8.56.0 typescript: '*' peerDependenciesMeta: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 7.13.0(typescript@5.4.5) - '@typescript-eslint/utils': 7.13.0(eslint@8.57.0)(typescript@5.4.5) - debug: 4.3.5(supports-color@8.1.1) - eslint: 8.57.0 + '@typescript-eslint/typescript-estree': 8.10.0(typescript@5.4.5) + '@typescript-eslint/utils': 8.10.0(eslint@9.12.0)(typescript@5.4.5) + debug: 4.3.7(supports-color@8.1.1) ts-api-utils: 1.3.0(typescript@5.4.5) typescript: 5.4.5 transitivePeerDependencies: + - eslint - supports-color dev: false - /@typescript-eslint/types@7.13.0: - resolution: {integrity: sha512-QWuwm9wcGMAuTsxP+qz6LBBd3Uq8I5Nv8xb0mk54jmNoCyDspnMvVsOxI6IsMmway5d1S9Su2+sCKv1st2l6eA==} - engines: {node: ^18.18.0 || >=20.0.0} + /@typescript-eslint/types@8.10.0: + resolution: {integrity: sha512-k/E48uzsfJCRRbGLapdZgrX52csmWJ2rcowwPvOZ8lwPUv3xW6CcFeJAXgx4uJm+Ge4+a4tFOkdYvSpxhRhg1w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dev: false - /@typescript-eslint/typescript-estree@7.13.0(typescript@5.4.5): - resolution: {integrity: sha512-cAvBvUoobaoIcoqox1YatXOnSl3gx92rCZoMRPzMNisDiM12siGilSM4+dJAekuuHTibI2hVC2fYK79iSFvWjw==} - engines: {node: ^18.18.0 || >=20.0.0} + /@typescript-eslint/typescript-estree@8.10.0(typescript@5.4.5): + resolution: {integrity: sha512-3OE0nlcOHaMvQ8Xu5gAfME3/tWVDpb/HxtpUZ1WeOAksZ/h/gwrBzCklaGzwZT97/lBbbxJ16dMA98JMEngW4w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '*' peerDependenciesMeta: typescript: optional: true dependencies: - '@typescript-eslint/types': 7.13.0 - '@typescript-eslint/visitor-keys': 7.13.0 - debug: 4.3.5(supports-color@8.1.1) - globby: 11.1.0 + '@typescript-eslint/types': 8.10.0 + '@typescript-eslint/visitor-keys': 8.10.0 + debug: 4.3.7(supports-color@8.1.1) + fast-glob: 3.3.2 is-glob: 4.0.3 - minimatch: 9.0.4 + minimatch: 9.0.5 semver: 7.6.2 ts-api-utils: 1.3.0(typescript@5.4.5) typescript: 5.4.5 @@ -8084,33 +8291,30 @@ packages: - supports-color dev: false - /@typescript-eslint/utils@7.13.0(eslint@8.57.0)(typescript@5.4.5): - resolution: {integrity: sha512-jceD8RgdKORVnB4Y6BqasfIkFhl4pajB1wVxrF4akxD2QPM8GNYjgGwEzYS+437ewlqqrg7Dw+6dhdpjMpeBFQ==} - engines: {node: ^18.18.0 || >=20.0.0} + /@typescript-eslint/utils@8.10.0(eslint@9.12.0)(typescript@5.4.5): + resolution: {integrity: sha512-Oq4uZ7JFr9d1ZunE/QKy5egcDRXT/FrS2z/nlxzPua2VHFtmMvFNDvpq1m/hq0ra+T52aUezfcjGRIB7vNJF9w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^8.56.0 + eslint: ^8.57.0 || ^9.0.0 dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) - '@typescript-eslint/scope-manager': 7.13.0 - '@typescript-eslint/types': 7.13.0 - '@typescript-eslint/typescript-estree': 7.13.0(typescript@5.4.5) - eslint: 8.57.0 + '@eslint-community/eslint-utils': 4.4.0(eslint@9.12.0) + '@typescript-eslint/scope-manager': 8.10.0 + '@typescript-eslint/types': 8.10.0 + '@typescript-eslint/typescript-estree': 8.10.0(typescript@5.4.5) + eslint: 9.12.0 transitivePeerDependencies: - supports-color - typescript dev: false - /@typescript-eslint/visitor-keys@7.13.0: - resolution: {integrity: sha512-nxn+dozQx+MK61nn/JP+M4eCkHDSxSLDpgE3WcQo0+fkjEolnaB5jswvIKC4K56By8MMgIho7f1PVxERHEo8rw==} - engines: {node: ^18.18.0 || >=20.0.0} + /@typescript-eslint/visitor-keys@8.10.0: + resolution: {integrity: sha512-k8nekgqwr7FadWk548Lfph6V3r9OVqjzAIVskE7orMZR23cGJjAOVazsZSJW+ElyjfTM4wx/1g88Mi70DDtG9A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dependencies: - '@typescript-eslint/types': 7.13.0 + '@typescript-eslint/types': 8.10.0 eslint-visitor-keys: 3.4.3 dev: false - /@ungap/structured-clone@1.2.0: - resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} - /@volar/language-core@1.11.1: resolution: {integrity: sha512-dOcNn3i9GgZAcJt43wuaEykSluAuOkQgzni1cuxLxTV0nJKanQztp7FxyswdRILaKH+P2XZMPRp2S4MV/pElCw==} dependencies: @@ -8306,12 +8510,12 @@ packages: dependencies: acorn: 8.12.1 - /acorn-jsx@5.3.2(acorn@8.11.3): + /acorn-jsx@5.3.2(acorn@8.12.1): resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: - acorn: 8.11.3 + acorn: 8.12.1 /acorn-walk@7.2.0: resolution: {integrity: sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==} @@ -9693,11 +9897,6 @@ packages: base64-js: 1.5.1 ieee754: 1.2.1 - /builtin-modules@3.3.0: - resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} - engines: {node: '>=6'} - dev: false - /builtins@5.1.0: resolution: {integrity: sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg==} dependencies: @@ -11012,12 +11211,6 @@ packages: esutils: 2.0.3 dev: false - /doctrine@3.0.0: - resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} - engines: {node: '>=6.0.0'} - dependencies: - esutils: 2.0.3 - /dom-element-descriptors@0.5.0: resolution: {integrity: sha512-CVzntLid1oFVHTKdTp/Qu7Kz+wSm8uO30TSQyAJ6n4Dz09yTzVQn3S1oRhVhUubxdMuKs1DjDqt88pubHagbPw==} @@ -11076,7 +11269,7 @@ packages: dependencies: '@babel/core': 7.24.5(supports-color@8.1.1) '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.24.5) - '@babel/plugin-proposal-decorators': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-proposal-decorators': 7.25.7(@babel/core@7.24.5) '@babel/plugin-proposal-private-methods': 7.18.6(@babel/core@7.24.5) '@babel/plugin-transform-class-static-block': 7.24.4(@babel/core@7.24.5) '@babel/preset-env': 7.24.5(@babel/core@7.24.5)(supports-color@8.1.1) @@ -11162,7 +11355,7 @@ packages: '@babel/core': 7.24.5(supports-color@8.1.1) '@babel/helper-compilation-targets': 7.23.6 '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.24.5) - '@babel/plugin-proposal-decorators': 7.24.1(@babel/core@7.24.5) + '@babel/plugin-proposal-decorators': 7.25.7(@babel/core@7.24.5) '@babel/plugin-proposal-private-methods': 7.18.6(@babel/core@7.24.5) '@babel/plugin-proposal-private-property-in-object': 7.21.11(@babel/core@7.24.5) '@babel/plugin-transform-class-static-block': 7.24.4(@babel/core@7.24.5) @@ -11634,8 +11827,8 @@ packages: engines: {node: '>= 0.10.0'} dev: true - /ember-eslint-parser@0.4.3(@babel/core@7.24.5)(@typescript-eslint/parser@7.13.0)(eslint@8.57.0): - resolution: {integrity: sha512-wMPoaaA+i/F/tPPxURRON9XXJH5MRUOZ5x/9CVJTSpL+0n4EWphyztb20gR+ZJeShnOACQpAdFy6YSS1/JSHKw==} + /ember-eslint-parser@0.5.2(@babel/core@7.24.5)(@typescript-eslint/parser@8.10.0)(eslint@9.12.0): + resolution: {integrity: sha512-289KjJ08QxK1Ytf+aq04QMoQ8WvhXCInJixcGuS5SWBFNlVuEs9yAZ06VXzVSuZ9zMAqX24MTMvD7ICVFN7QSg==} engines: {node: '>=16.0.0'} peerDependencies: '@babel/core': ^7.23.6 @@ -11645,10 +11838,10 @@ packages: optional: true dependencies: '@babel/core': 7.24.5(supports-color@8.1.1) - '@babel/eslint-parser': 7.23.10(@babel/core@7.24.5)(eslint@8.57.0) + '@babel/eslint-parser': 7.25.8(@babel/core@7.24.5)(eslint@9.12.0) '@glimmer/syntax': 0.92.0 - '@typescript-eslint/parser': 7.13.0(eslint@8.57.0)(typescript@5.4.5) - content-tag: 1.2.2 + '@typescript-eslint/parser': 8.10.0(eslint@9.12.0)(typescript@5.4.5) + content-tag: 2.0.1 eslint-scope: 7.2.2 html-tags: 3.3.1 transitivePeerDependencies: @@ -12215,37 +12408,37 @@ packages: optionalDependencies: source-map: 0.6.1 - /eslint-compat-utils@0.5.0(eslint@8.57.0): + /eslint-compat-utils@0.5.0(eslint@9.12.0): resolution: {integrity: sha512-dc6Y8tzEcSYZMHa+CMPLi/hyo1FzNeonbhJL7Ol0ccuKQkwopJcJBA9YL/xmMTLU1eKigXo9vj9nALElWYSowg==} engines: {node: '>=12'} peerDependencies: eslint: '>=6.0.0' dependencies: - eslint: 8.57.0 + eslint: 9.12.0 semver: 7.6.2 dev: false - /eslint-config-prettier@9.1.0(eslint@8.57.0): + /eslint-config-prettier@9.1.0(eslint@9.12.0): resolution: {integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==} hasBin: true peerDependencies: eslint: '>=7.0.0' dependencies: - eslint: 8.57.0 + eslint: 9.12.0 dev: false /eslint-import-resolver-node@0.3.9: resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} dependencies: debug: 3.2.7 - is-core-module: 2.13.1 + is-core-module: 2.15.1 resolve: 1.22.8 transitivePeerDependencies: - supports-color dev: false - /eslint-module-utils@2.8.1(@typescript-eslint/parser@7.13.0)(eslint-import-resolver-node@0.3.9)(eslint@8.57.0): - resolution: {integrity: sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==} + /eslint-module-utils@2.12.0(@typescript-eslint/parser@8.10.0)(eslint-import-resolver-node@0.3.9)(eslint@9.12.0): + resolution: {integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==} engines: {node: '>=4'} peerDependencies: '@typescript-eslint/parser': '*' @@ -12265,54 +12458,56 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 7.13.0(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/parser': 8.10.0(eslint@9.12.0)(typescript@5.4.5) debug: 3.2.7 - eslint: 8.57.0 + eslint: 9.12.0 eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color dev: false - /eslint-plugin-es-x@7.6.0(eslint@8.57.0): + /eslint-plugin-es-x@7.6.0(eslint@9.12.0): resolution: {integrity: sha512-I0AmeNgevgaTR7y2lrVCJmGYF0rjoznpDvqV/kIkZSZbZ8Rw3eu4cGlvBBULScfkSOCzqKbff5LR4CNrV7mZHA==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: eslint: '>=8' dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@9.12.0) '@eslint-community/regexpp': 4.10.0 - eslint: 8.57.0 - eslint-compat-utils: 0.5.0(eslint@8.57.0) + eslint: 9.12.0 + eslint-compat-utils: 0.5.0(eslint@9.12.0) dev: false - /eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.13.0)(eslint@8.57.0): - resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==} + /eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.10.0)(eslint@9.12.0): + resolution: {integrity: sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==} engines: {node: '>=4'} peerDependencies: '@typescript-eslint/parser': '*' - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 peerDependenciesMeta: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 7.13.0(eslint@8.57.0)(typescript@5.4.5) + '@rtsao/scc': 1.1.0 + '@typescript-eslint/parser': 8.10.0(eslint@9.12.0)(typescript@5.4.5) array-includes: 3.1.8 array.prototype.findlastindex: 1.2.5 array.prototype.flat: 1.3.2 array.prototype.flatmap: 1.3.2 debug: 3.2.7 doctrine: 2.1.0 - eslint: 8.57.0 + eslint: 9.12.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.13.0)(eslint-import-resolver-node@0.3.9)(eslint@8.57.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.10.0)(eslint-import-resolver-node@0.3.9)(eslint@9.12.0) hasown: 2.0.2 - is-core-module: 2.13.1 + is-core-module: 2.15.1 is-glob: 4.0.3 minimatch: 3.1.2 object.fromentries: 2.0.8 object.groupby: 1.0.3 object.values: 1.2.0 semver: 6.3.1 + string.prototype.trimend: 1.0.8 tsconfig-paths: 3.15.0 transitivePeerDependencies: - eslint-import-resolver-typescript @@ -12320,54 +12515,51 @@ packages: - supports-color dev: false - /eslint-plugin-mocha@10.4.3(eslint@8.57.0): - resolution: {integrity: sha512-emc4TVjq5Ht0/upR+psftuz6IBG5q279p+1dSRDeHf+NS9aaerBi3lXKo1SEzwC29hFIW21gO89CEWSvRsi8IQ==} + /eslint-plugin-mocha@10.5.0(eslint@9.12.0): + resolution: {integrity: sha512-F2ALmQVPT1GoP27O1JTZGrV9Pqg8k79OeIuvw63UxMtQKREZtmkK1NFgkZQ2TW7L2JSSFKHFPTtHu5z8R9QNRw==} engines: {node: '>=14.0.0'} peerDependencies: eslint: '>=7.0.0' dependencies: - eslint: 8.57.0 - eslint-utils: 3.0.0(eslint@8.57.0) + eslint: 9.12.0 + eslint-utils: 3.0.0(eslint@9.12.0) globals: 13.24.0 rambda: 7.5.0 dev: false - /eslint-plugin-n@16.6.2(eslint@8.57.0): - resolution: {integrity: sha512-6TyDmZ1HXoFQXnhCTUjVFULReoBPOAjpuiKELMkeP40yffI/1ZRO+d9ug/VC6fqISo2WkuIBk3cvuRPALaWlOQ==} - engines: {node: '>=16.0.0'} + /eslint-plugin-n@17.11.1(eslint@9.12.0): + resolution: {integrity: sha512-93IUD82N6tIEgjztVI/l3ElHtC2wTa9boJHrD8iN+NyDxjxz/daZUZKfkedjBZNdg6EqDk4irybUsiPwDqXAEA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: '>=7.0.0' + eslint: '>=8.23.0' dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) - builtins: 5.1.0 - eslint: 8.57.0 - eslint-plugin-es-x: 7.6.0(eslint@8.57.0) + '@eslint-community/eslint-utils': 4.4.0(eslint@9.12.0) + enhanced-resolve: 5.17.1 + eslint: 9.12.0 + eslint-plugin-es-x: 7.6.0(eslint@9.12.0) get-tsconfig: 4.7.5 - globals: 13.24.0 + globals: 15.11.0 ignore: 5.3.1 - is-builtin-module: 3.2.1 - is-core-module: 2.13.1 - minimatch: 3.1.2 - resolve: 1.22.8 + minimatch: 9.0.5 semver: 7.6.2 dev: false - /eslint-plugin-qunit@8.1.1(eslint@8.57.0): - resolution: {integrity: sha512-j3xhiAf2Wvr8Dfwl5T6tlJ+F55vqYE9ZdAHUOTzq1lGerYrXzOS46RvK4SSWug2D8sl3ZYr2lA4/hgVXgLloxw==} + /eslint-plugin-qunit@8.1.2(eslint@9.12.0): + resolution: {integrity: sha512-2gDQdHlQW8GVXD7YYkO8vbm9Ldc60JeGMuQN5QlD48OeZ8znBvvoHWZZMeXjvoDPReGaLEvyuWrDtrI8bDbcqw==} engines: {node: ^16.0.0 || ^18.0.0 || >=20.0.0} dependencies: - eslint-utils: 3.0.0(eslint@8.57.0) + eslint-utils: 3.0.0(eslint@9.12.0) requireindex: 1.2.0 transitivePeerDependencies: - eslint dev: false - /eslint-plugin-simple-import-sort@12.1.0(eslint@8.57.0): - resolution: {integrity: sha512-Y2fqAfC11TcG/WP3TrI1Gi3p3nc8XJyEOJYHyEPEGI/UAgNx6akxxlX74p7SbAQdLcgASKhj8M0GKvH3vq/+ig==} + /eslint-plugin-simple-import-sort@12.1.1(eslint@9.12.0): + resolution: {integrity: sha512-6nuzu4xwQtE3332Uz0to+TxDQYRLTKRESSc2hefVT48Zc8JthmN23Gx9lnYhu0FtkRSL1oxny3kJ2aveVhmOVA==} peerDependencies: eslint: '>=5.0.0' dependencies: - eslint: 8.57.0 + eslint: 9.12.0 dev: false /eslint-scope@5.1.1: @@ -12383,14 +12575,22 @@ packages: dependencies: esrecurse: 4.3.0 estraverse: 5.3.0 + dev: false - /eslint-utils@3.0.0(eslint@8.57.0): + /eslint-scope@8.1.0: + resolution: {integrity: sha512-14dSvlhaVhKKsa9Fx1l8A17s7ah7Ef7wCakJ10LYk6+GYmP9yDti2oq2SEwcyndt6knfcZyhyxwY3i9yL78EQw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + /eslint-utils@3.0.0(eslint@9.12.0): resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} peerDependencies: eslint: '>=5' dependencies: - eslint: 8.57.0 + eslint: 9.12.0 eslint-visitor-keys: 2.1.0 dev: false @@ -12403,48 +12603,54 @@ packages: resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - /eslint@8.57.0: - resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /eslint-visitor-keys@4.1.0: + resolution: {integrity: sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + /eslint@9.12.0: + resolution: {integrity: sha512-UVIOlTEWxwIopRL1wgSQYdnVDcEvs2wyaO6DGo5mXqe3r16IoCNWkR29iHhyaP4cICWjbgbmFUGAhh0GJRuGZw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) - '@eslint-community/regexpp': 4.10.0 - '@eslint/eslintrc': 2.1.4 - '@eslint/js': 8.57.0 - '@humanwhocodes/config-array': 0.11.14 + '@eslint-community/eslint-utils': 4.4.0(eslint@9.12.0) + '@eslint-community/regexpp': 4.11.1 + '@eslint/config-array': 0.18.0 + '@eslint/core': 0.6.0 + '@eslint/eslintrc': 3.1.0 + '@eslint/js': 9.12.0 + '@eslint/plugin-kit': 0.2.0 + '@humanfs/node': 0.16.5 '@humanwhocodes/module-importer': 1.0.1 - '@nodelib/fs.walk': 1.2.8 - '@ungap/structured-clone': 1.2.0 + '@humanwhocodes/retry': 0.3.1 + '@types/estree': 1.0.6 + '@types/json-schema': 7.0.15 ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.3 - debug: 4.3.5(supports-color@8.1.1) - doctrine: 3.0.0 + debug: 4.3.7(supports-color@8.1.1) escape-string-regexp: 4.0.0 - eslint-scope: 7.2.2 - eslint-visitor-keys: 3.4.3 - espree: 9.6.1 + eslint-scope: 8.1.0 + eslint-visitor-keys: 4.1.0 + espree: 10.2.0 esquery: 1.5.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 - file-entry-cache: 6.0.1 + file-entry-cache: 8.0.0 find-up: 5.0.0 glob-parent: 6.0.2 - globals: 13.24.0 - graphemer: 1.4.0 ignore: 5.3.1 imurmurhash: 0.1.4 is-glob: 4.0.3 - is-path-inside: 3.0.3 - 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.4 - strip-ansi: 6.0.1 text-table: 0.2.0 transitivePeerDependencies: - supports-color @@ -12453,13 +12659,13 @@ packages: resolution: {integrity: sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==} engines: {node: '>=6'} - /espree@9.6.1: - resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /espree@10.2.0: + resolution: {integrity: sha512-upbkBJbckcCNBDBDXEbuhjbP68n+scUd3k/U2EkyM9nw+I/jPiL4cLF/Al06CF96wRltFda16sxDFrxsI1v0/g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} dependencies: - acorn: 8.11.3 - acorn-jsx: 5.3.2(acorn@8.11.3) - eslint-visitor-keys: 3.4.3 + acorn: 8.12.1 + acorn-jsx: 5.3.2(acorn@8.12.1) + eslint-visitor-keys: 4.1.0 /esprima@3.0.0: resolution: {integrity: sha512-xoBq/MIShSydNZOkjkoCEjqod963yHNXTLC40ypBhop6yPqflPz/vTinmCfSrGcywVLnSftRf6a0kJLdFdzemw==} @@ -12910,7 +13116,7 @@ packages: dependencies: chalk: 4.1.2 cookie: 0.4.2 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.7(supports-color@8.1.1) jsdom: 19.0.0 resolve: 1.22.8 simple-dom: 1.4.0 @@ -12964,11 +13170,11 @@ packages: is-unicode-supported: 2.0.0 dev: true - /file-entry-cache@6.0.1: - resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} - engines: {node: ^10.12.0 || >=12.0.0} + /file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} dependencies: - flat-cache: 3.2.0 + flat-cache: 4.0.1 /filesize@10.1.1: resolution: {integrity: sha512-L0cdwZrKlwZQkMSFnCflJ6J2Y+5egO/p3vgRSDQGxQt++QbUZe5gMbRO6kg6gzwQDPvq2Fk9AmoxUNfZ5gdqaQ==} @@ -13170,13 +13376,12 @@ packages: matcher-collection: 2.0.1 walk-sync: 2.2.0 - /flat-cache@3.2.0: - resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} - engines: {node: ^10.12.0 || >=12.0.0} + /flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} dependencies: flatted: 3.3.1 keyv: 4.5.4 - rimraf: 3.0.2 /flat@5.0.2: resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} @@ -13687,6 +13892,16 @@ packages: engines: {node: '>=8'} dependencies: type-fest: 0.20.2 + dev: false + + /globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} + + /globals@15.11.0: + resolution: {integrity: sha512-yeyNSjdbyVaWurlwCpcA6XNBrHTMIeDdj0/hnvX/OLJ9ekOXYbLsLinH/MucQyGvNnXhidTdNhTtJaffL2sMfw==} + engines: {node: '>=18'} + dev: false /globals@15.3.0: resolution: {integrity: sha512-cCdyVjIUVTtX8ZsPkq1oCsOsLmGIswqnjZYMJJTGaNApj1yHtLSymKhwH51ttirREn75z3p4k051clwg7rvNKA==} @@ -13792,6 +14007,7 @@ packages: /graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + dev: false /growly@1.3.0: resolution: {integrity: sha512-+xGQY0YyAWCnqy7Cd++hc2JqMYzlm0dG30Jd0beaA64sROr8C4nt8Yc9V5Ro3avlSUDTN0ulqP/VBKi1/lLygw==} @@ -14339,13 +14555,6 @@ packages: /is-buffer@1.1.6: resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==} - /is-builtin-module@3.2.1: - resolution: {integrity: sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==} - engines: {node: '>=6'} - dependencies: - builtin-modules: 3.3.0 - dev: false - /is-callable@1.2.7: resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} engines: {node: '>= 0.4'} @@ -14355,6 +14564,13 @@ packages: dependencies: hasown: 2.0.2 + /is-core-module@2.15.1: + resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==} + engines: {node: '>= 0.4'} + dependencies: + hasown: 2.0.2 + dev: false + /is-data-descriptor@1.0.1: resolution: {integrity: sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw==} engines: {node: '>= 0.4'} @@ -14812,6 +15028,11 @@ packages: engines: {node: '>=4'} hasBin: true + /jsesc@3.0.2: + resolution: {integrity: sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==} + engines: {node: '>=6'} + hasBin: true + /json-buffer@3.0.0: resolution: {integrity: sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==} dev: true @@ -15488,6 +15709,13 @@ packages: dependencies: brace-expansion: 2.0.1 + /minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + brace-expansion: 2.0.1 + dev: false + /minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} @@ -18836,22 +19064,21 @@ packages: dependencies: is-typedarray: 1.0.0 - /typescript-eslint@7.13.0(eslint@8.57.0)(typescript@5.4.5): - resolution: {integrity: sha512-upO0AXxyBwJ4BbiC6CRgAJKtGYha2zw4m1g7TIVPSonwYEuf7vCicw3syjS1OxdDMTz96sZIXl3Jx3vWJLLKFw==} - engines: {node: ^18.18.0 || >=20.0.0} + /typescript-eslint@8.10.0(eslint@9.12.0)(typescript@5.4.5): + resolution: {integrity: sha512-YIu230PeN7z9zpu/EtqCIuRVHPs4iSlqW6TEvjbyDAE3MZsSl2RXBo+5ag+lbABCG8sFM1WVKEXhlQ8Ml8A3Fw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^8.56.0 typescript: '*' peerDependenciesMeta: typescript: optional: true dependencies: - '@typescript-eslint/eslint-plugin': 7.13.0(@typescript-eslint/parser@7.13.0)(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/parser': 7.13.0(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/utils': 7.13.0(eslint@8.57.0)(typescript@5.4.5) - eslint: 8.57.0 + '@typescript-eslint/eslint-plugin': 8.10.0(@typescript-eslint/parser@8.10.0)(eslint@9.12.0)(typescript@5.4.5) + '@typescript-eslint/parser': 8.10.0(eslint@9.12.0)(typescript@5.4.5) + '@typescript-eslint/utils': 8.10.0(eslint@9.12.0)(typescript@5.4.5) typescript: 5.4.5 transitivePeerDependencies: + - eslint - supports-color dev: false diff --git a/release/strategy.json b/release/strategy.json index c6d799fceca..3fa6ae166fd 100644 --- a/release/strategy.json +++ b/release/strategy.json @@ -71,6 +71,12 @@ "typesPublish": false, "mirrorPublish": false }, + "eslint-plugin-warp-drive": { + "stage": "alpha", + "types": "private", + "typesPublish": false, + "mirrorPublish": false + }, "@warp-drive/core-types": { "stage": "alpha", "types": "alpha" diff --git a/tests/codemods/package.json b/tests/codemods/package.json index 5ed6e96de45..c448c733111 100644 --- a/tests/codemods/package.json +++ b/tests/codemods/package.json @@ -36,7 +36,7 @@ "@types/bun": "^1.1.4", "@types/jscodeshift": "0.11.11", "@warp-drive/internal-config": "workspace:5.4.0-alpha.112", - "eslint": "^8.57.0", + "eslint": "^9.12.0", "pnpm-sync-dependencies-meta-injected": "0.0.14", "qunit": "^2.20.1", "tsx": "^4.10.4" diff --git a/tests/ember-data__request/tests/integration/response-currying-test.ts b/tests/ember-data__request/tests/integration/response-currying-test.ts index 4c9f1d6d27e..ee440640d89 100644 --- a/tests/ember-data__request/tests/integration/response-currying-test.ts +++ b/tests/ember-data__request/tests/integration/response-currying-test.ts @@ -18,7 +18,7 @@ module('RequestManager | Response Currying', function () { async request(context: RequestContext, next: NextFn) { const response = await fetch(context.request.url!, context.request); context.setResponse(response); - return response.json(); + return response.json() as Promise; }, }; manager.use([handler1, handler2]); @@ -65,7 +65,7 @@ module('RequestManager | Response Currying', function () { async request(context: RequestContext, next: NextFn) { const response = await fetch(context.request.url!, context.request); context.setResponse(response); - return response.json(); + return response.json() as Promise; }, }; manager.use([handler1, handler2]); @@ -86,7 +86,7 @@ module('RequestManager | Response Currying', function () { async request(context: RequestContext, next: NextFn) { const response = await fetch(context.request.url!, context.request); context.setResponse(response); - return response.json(); + return response.json() as Promise; }, }; manager.use([handler1, handler2]); @@ -136,7 +136,7 @@ module('RequestManager | Response Currying', function () { async request(context: RequestContext, next: NextFn) { const response = await fetch(context.request.url!, context.request); context.setResponse(response); - return response.json(); + return response.json() as Promise; }, }; manager.use([handler1, handler2]); @@ -181,14 +181,14 @@ module('RequestManager | Response Currying', function () { // @ts-expect-error doc.response!.ok = false; assert.ok(false, 'we should be immutable'); - } catch (e) { + } catch { assert.ok(true, 'we are immutable'); } try { doc.response!.headers.append('foo', 'bar'); assert.ok(false, 'we should be immutable'); - } catch (e) { + } catch { assert.ok(true, 'we are immutable'); } @@ -199,7 +199,7 @@ module('RequestManager | Response Currying', function () { async request(context: RequestContext, next: NextFn) { const response = await fetch(context.request.url!, context.request); context.setResponse(response); - return response.json(); + return response.json() as Promise; }, }; manager.use([handler1, handler2]); @@ -248,7 +248,7 @@ module('RequestManager | Response Currying', function () { async request(context: RequestContext, next: NextFn) { const response = await fetch(context.request.url!, context.request); context.setResponse(response); - return response.json(); + return response.json() as Promise; }, }; manager.use([handler1, handler2]); diff --git a/tests/ember-data__request/tests/integration/response-test.ts b/tests/ember-data__request/tests/integration/response-test.ts index 1881b4a5f3b..df3e033eaf4 100644 --- a/tests/ember-data__request/tests/integration/response-test.ts +++ b/tests/ember-data__request/tests/integration/response-test.ts @@ -12,7 +12,7 @@ module('RequestManager | Response', function () { async request(context: RequestContext, next: NextFn) { const response = await fetch(context.request.url!, context.request); context.setResponse(response); - return response.json(); + return response.json() as Promise; }, }; manager.use([handler]); diff --git a/tests/fastboot/config/fastboot.js b/tests/fastboot/config/fastboot.js index cfe3df120da..ce797e71f04 100644 --- a/tests/fastboot/config/fastboot.js +++ b/tests/fastboot/config/fastboot.js @@ -1,3 +1,4 @@ +/* eslint-disable n/no-unsupported-features/node-builtins */ module.exports = function (environment) { return { buildSandboxGlobals(defaultGlobals) { diff --git a/tests/fastboot/package.json b/tests/fastboot/package.json index fd9b4b5f5c5..ba01c0261b6 100644 --- a/tests/fastboot/package.json +++ b/tests/fastboot/package.json @@ -100,7 +100,7 @@ "typescript": "^5.4.5" }, "engines": { - "node": ">= 18.20.3" + "node": ">= 22" }, "ember": { "edition": "octane" diff --git a/tests/main/tests/integration/adapter/find-test.js b/tests/main/tests/integration/adapter/find-test.js index e45e47f1ef6..30cdd8774e9 100644 --- a/tests/main/tests/integration/adapter/find-test.js +++ b/tests/main/tests/integration/adapter/find-test.js @@ -122,7 +122,7 @@ module('integration/adapter - Finding Records', function (hooks) { try { await store.findRecord('person', '1'); assert.ok(false, 'We expected to throw but did not'); - } catch (e) { + } catch { assert.ok(true, 'The rejection handler was called'); } }); @@ -149,7 +149,7 @@ module('integration/adapter - Finding Records', function (hooks) { try { await store.findRecord('person', '1'); assert.ok(false, 'We expected to throw but did not'); - } catch (e) { + } catch { assert.ok(true, 'The rejection handler was called'); assert.strictEqual(store.peekRecord('person', '1'), null, 'The record has been unloaded'); } diff --git a/tests/main/tests/integration/adapter/rest-adapter-test.js b/tests/main/tests/integration/adapter/rest-adapter-test.js index 4e3aaac3743..aaff89f28be 100644 --- a/tests/main/tests/integration/adapter/rest-adapter-test.js +++ b/tests/main/tests/integration/adapter/rest-adapter-test.js @@ -2520,7 +2520,7 @@ module('integration/adapter/rest_adapter - REST Adapter', function (hooks) { try { await store.findRecord('post', '1'); - } catch (error) { + } catch { assert.ok(true, 'Unexpected error is captured by the promise chain'); } }); @@ -2549,7 +2549,7 @@ module('integration/adapter/rest_adapter - REST Adapter', function (hooks) { try { await store.findRecord('post', '1'); - } catch (error) { + } catch { assert.ok(true, 'Unexpected error is captured by the promise chain'); } }); diff --git a/tests/main/tests/integration/adapter/store-adapter-test.js b/tests/main/tests/integration/adapter/store-adapter-test.js index 263099a9309..c363f623a9d 100644 --- a/tests/main/tests/integration/adapter/store-adapter-test.js +++ b/tests/main/tests/integration/adapter/store-adapter-test.js @@ -434,7 +434,7 @@ module('integration/adapter/store-adapter - DS.Store and DS.Adapter integration try { await tom.save(); assert.ok(false, 'We should throw during save'); - } catch (e) { + } catch { assert.true(tom.isError, 'Tom is now errored'); assert.strictEqual(tom.adapterError, error, 'error object is exposed'); @@ -478,7 +478,7 @@ module('integration/adapter/store-adapter - DS.Store and DS.Adapter integration try { await yehuda.save(); assert.ok(false, 'We should have erred'); - } catch (e) { + } catch { assert.false(yehuda.isValid, 'the record is invalid'); assert.ok(get(yehuda, 'errors.name'), 'The errors.name property exists'); diff --git a/tests/main/tests/integration/cache/cache-capabilities-manager-test.ts b/tests/main/tests/integration/cache/cache-capabilities-manager-test.ts index fec878e3556..e73721b7a53 100644 --- a/tests/main/tests/integration/cache/cache-capabilities-manager-test.ts +++ b/tests/main/tests/integration/cache/cache-capabilities-manager-test.ts @@ -61,6 +61,7 @@ module('integration/cache-capabilities', function (hooks) { owner.register('service:store', TestStore); const store = owner.lookup('service:store') as unknown as Store; + // eslint-disable-next-line @typescript-eslint/no-unused-expressions store.cache; assert.strictEqual(capabilities.schema, store.schema, 'capabilities exposes the schema service'); diff --git a/tests/main/tests/integration/cache/spec-cache-errors-test.ts b/tests/main/tests/integration/cache/spec-cache-errors-test.ts index 7a603a16881..2bf29f0871c 100644 --- a/tests/main/tests/integration/cache/spec-cache-errors-test.ts +++ b/tests/main/tests/integration/cache/spec-cache-errors-test.ts @@ -111,7 +111,7 @@ class TestCache implements Cache { upsert( identifier: StableRecordIdentifier, data: ExistingResourceObject, - calculateChanges?: boolean | undefined + calculateChanges?: boolean ): void | string[] { if (!this._data.has(identifier)) { this.wrapper.notifyChange(identifier, 'added'); @@ -120,10 +120,7 @@ class TestCache implements Cache { this.wrapper.notifyChange(identifier, 'attributes'); this.wrapper.notifyChange(identifier, 'relationships'); } - clientDidCreate( - identifier: StableRecordIdentifier, - options?: Record | undefined - ): Record { + clientDidCreate(identifier: StableRecordIdentifier, options?: Record): Record { this._isNew = true; return {}; } @@ -134,7 +131,7 @@ class TestCache implements Cache { ): SingleResourceDataDocument { return { data: identifier as StableExistingRecordIdentifier }; } - commitWasRejected(identifier: StableRecordIdentifier, errors?: ApiError[] | undefined): void { + commitWasRejected(identifier: StableRecordIdentifier, errors?: ApiError[]): void { this._errors = errors; } unloadRecord(identifier: StableRecordIdentifier): void {} @@ -163,7 +160,7 @@ class TestCache implements Cache { identifier: StableRecordIdentifier, propertyName: string, value: StableRecordIdentifier[], - idx?: number | undefined + idx?: number ): void { throw new Error('Method not implemented.'); } @@ -213,6 +210,7 @@ module('integration/record-data Custom Cache (v2) Errors', function (hooks) { } class TestAdapter extends EmberObject { updateRecord() { + // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors return Promise.reject( // @ts-expect-error Constructor of class 'InvalidError' is private new InvalidError([ @@ -251,7 +249,7 @@ module('integration/record-data Custom Cache (v2) Errors', function (hooks) { try { await person.save(); assert.ok(false, 'we should error'); - } catch (error) { + } catch { assert.ok(true, 'we erred'); } }); @@ -274,6 +272,7 @@ module('integration/record-data Custom Cache (v2) Errors', function (hooks) { } class TestAdapter extends EmberObject { updateRecord() { + // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors return Promise.reject(); } @@ -301,7 +300,7 @@ module('integration/record-data Custom Cache (v2) Errors', function (hooks) { try { await person.save(); assert.ok(false, 'we should error'); - } catch (error) { + } catch { assert.ok(true, 'we erred'); } }); diff --git a/tests/main/tests/integration/cache/spec-cache-state-test.ts b/tests/main/tests/integration/cache/spec-cache-state-test.ts index 6d209fe45e4..cc83fe7f1f8 100644 --- a/tests/main/tests/integration/cache/spec-cache-state-test.ts +++ b/tests/main/tests/integration/cache/spec-cache-state-test.ts @@ -126,7 +126,7 @@ class TestCache implements Cache { upsert( identifier: StableRecordIdentifier, data: ExistingResourceObject, - calculateChanges?: boolean | undefined + calculateChanges?: boolean ): void | string[] { if (!this._data.has(identifier)) { this._storeWrapper.notifyChange(identifier, 'added'); @@ -143,10 +143,7 @@ class TestCache implements Cache { _errors?: ApiError[]; _isNew = false; - clientDidCreate( - identifier: StableRecordIdentifier, - options?: Record | undefined - ): Record { + clientDidCreate(identifier: StableRecordIdentifier, options?: Record): Record { this._isNew = true; this._storeWrapper.notifyChange(identifier, 'added'); return {}; @@ -155,7 +152,7 @@ class TestCache implements Cache { didCommit(identifier: StableRecordIdentifier, result: StructuredDataDocument): SingleResourceDataDocument { return { data: identifier as StableExistingRecordIdentifier }; } - commitWasRejected(identifier: StableRecordIdentifier, errors?: ApiError[] | undefined): void { + commitWasRejected(identifier: StableRecordIdentifier, errors?: ApiError[]): void { this._errors = errors; } unloadRecord(identifier: StableRecordIdentifier): void {} @@ -184,7 +181,7 @@ class TestCache implements Cache { identifier: StableRecordIdentifier, propertyName: string, value: StableRecordIdentifier[], - idx?: number | undefined + idx?: number ): void { throw new Error('Method not implemented.'); } diff --git a/tests/main/tests/integration/cache/spec-cache-test.ts b/tests/main/tests/integration/cache/spec-cache-test.ts index f5ad8a0758a..8ee29368750 100644 --- a/tests/main/tests/integration/cache/spec-cache-test.ts +++ b/tests/main/tests/integration/cache/spec-cache-test.ts @@ -140,7 +140,7 @@ class TestCache implements Cache { upsert( identifier: StableRecordIdentifier, data: ExistingResourceObject, - calculateChanges?: boolean | undefined + calculateChanges?: boolean ): void | string[] { if (!this._data.has(identifier)) { this._storeWrapper.notifyChange(identifier, 'added'); @@ -150,10 +150,7 @@ class TestCache implements Cache { this._storeWrapper.notifyChange(identifier, 'relationships'); } - clientDidCreate( - identifier: StableRecordIdentifier, - options?: Record | undefined - ): Record { + clientDidCreate(identifier: StableRecordIdentifier, options?: Record): Record { this._isNew = true; return {}; } @@ -161,7 +158,7 @@ class TestCache implements Cache { didCommit(identifier: StableRecordIdentifier, result: StructuredDataDocument): SingleResourceDataDocument { return { data: identifier as StableExistingRecordIdentifier }; } - commitWasRejected(identifier: StableRecordIdentifier, errors?: ApiError[] | undefined): void { + commitWasRejected(identifier: StableRecordIdentifier, errors?: ApiError[]): void { this._errors = errors; } unloadRecord(identifier: StableRecordIdentifier): void {} @@ -296,7 +293,7 @@ module('integration/record-data - Custom Cache Implementations', function (hooks override clientDidCreate( identifier: StableRecordIdentifier, - options?: Record | undefined + options?: Record ): Record { calledClientDidCreate++; isNew = true; @@ -348,6 +345,7 @@ module('integration/record-data - Custom Cache Implementations', function (hooks if (called === 1) { return Promise.resolve(); } else if (called > 1) { + // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors return Promise.reject(); } }, diff --git a/tests/main/tests/integration/records/error-test.js b/tests/main/tests/integration/records/error-test.js index 639d90caffd..c2ca0e07be3 100644 --- a/tests/main/tests/integration/records/error-test.js +++ b/tests/main/tests/integration/records/error-test.js @@ -215,7 +215,7 @@ module('integration/records/error', function (hooks) { try { person = await person.save(); - } catch (_error) { + } catch { const errors = person.errors; assert.strictEqual(errors.length, 2, 'Adds two errors to the model'); diff --git a/tests/main/tests/integration/records/new-record-unload-test.js b/tests/main/tests/integration/records/new-record-unload-test.js index d0441099380..4020433e3c3 100644 --- a/tests/main/tests/integration/records/new-record-unload-test.js +++ b/tests/main/tests/integration/records/new-record-unload-test.js @@ -204,7 +204,7 @@ module('Integration | Records | New Record Unload', function (hooks) { try { await Pat.save(); assert.ok(false, 'save failed'); - } catch (e) { + } catch { assert.ok(true, 'save failed'); } @@ -254,7 +254,7 @@ module('Integration | Records | New Record Unload', function (hooks) { try { await Pat.save(); assert.ok(false, 'save failed'); - } catch (e) { + } catch { assert.ok(true, 'save failed'); } @@ -304,7 +304,7 @@ module('Integration | Records | New Record Unload', function (hooks) { try { await Pat.save(); assert.ok(false, 'save failed'); - } catch (e) { + } catch { assert.ok(true, 'save failed'); } @@ -354,7 +354,7 @@ module('Integration | Records | New Record Unload', function (hooks) { try { await Pat.save(); assert.ok(true, 'save succeeded'); - } catch (e) { + } catch { assert.ok(false, 'save succeeded'); } @@ -409,7 +409,7 @@ module('Integration | Records | New Record Unload', function (hooks) { try { await Pat.save(); assert.ok(true, 'save succeeded'); - } catch (e) { + } catch { assert.ok(false, 'save succeeded'); } diff --git a/tests/main/tests/integration/records/save-test.js b/tests/main/tests/integration/records/save-test.js index 83bb9adfc15..ddb5a31555d 100644 --- a/tests/main/tests/integration/records/save-test.js +++ b/tests/main/tests/integration/records/save-test.js @@ -57,7 +57,7 @@ module('integration/records/save - Save Record', function (hooks) { try { await post.save(); assert.ok(false, 'we should err'); - } catch (error) { + } catch { assert.ok(true, 'we errored during save'); } }); diff --git a/tests/main/tests/integration/relationships/has-many-test.js b/tests/main/tests/integration/relationships/has-many-test.js index 948bef0f0be..a6a9326c048 100644 --- a/tests/main/tests/integration/relationships/has-many-test.js +++ b/tests/main/tests/integration/relationships/has-many-test.js @@ -2896,7 +2896,7 @@ If using this relationship in a polymorphic manner is desired, the relationships store.destroy(); await settled(); assert.ok(true, 'store destroyed correctly'); - } catch (error) { + } catch { assert.ok(false, 'store prevented from being destroyed'); } }); diff --git a/tests/main/tests/integration/store-test.js b/tests/main/tests/integration/store-test.js index 3de4d68a3db..5d3b619e371 100644 --- a/tests/main/tests/integration/store-test.js +++ b/tests/main/tests/integration/store-test.js @@ -1174,7 +1174,7 @@ module('integration/store - findAll', function (hooks) { const applicationAdapter = store.adapterFor('application'); assert.ok(applicationAdapter); - } catch (_error) { + } catch { assert.ok(false, 'An error was thrown while looking for application adapter'); } }); @@ -1192,7 +1192,7 @@ module('integration/store - findAll', function (hooks) { const applicationSerializer = store.serializerFor('application'); assert.ok(applicationSerializer); - } catch (_error) { + } catch { assert.ok(false, 'An error was thrown while looking for application serializer'); } }); @@ -1238,7 +1238,7 @@ module('integration/store - deleteRecord', function (hooks) { try { store.push({ data: null }); - } catch (_error) { + } catch { assert.ok(false, 'push null value for `data` to store throws an error'); } }); diff --git a/tests/main/tests/unit/custom-class-support/custom-class-model-test.ts b/tests/main/tests/unit/custom-class-support/custom-class-model-test.ts index d83f92b9b3e..541a185c354 100644 --- a/tests/main/tests/unit/custom-class-support/custom-class-model-test.ts +++ b/tests/main/tests/unit/custom-class-support/custom-class-model-test.ts @@ -55,6 +55,7 @@ module('unit/model - Custom Class Model', function (hooks: NestedHooks) { 'adapter:application', JSONAPIAdapter.extend({ shouldBackgroundReloadRecord: () => false, + // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors createRecord: () => Promise.reject(), }) ); @@ -327,6 +328,7 @@ module('unit/model - Custom Class Model', function (hooks: NestedHooks) { JSONAPIAdapter.extend({ shouldBackgroundReloadRecord: () => false, createRecord: (store, type, snapshot) => { + // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors return Promise.reject(); }, }) diff --git a/tests/main/tests/unit/model-test.js b/tests/main/tests/unit/model-test.js index b5ca7af2b87..5102cb856e9 100644 --- a/tests/main/tests/unit/model-test.js +++ b/tests/main/tests/unit/model-test.js @@ -324,7 +324,7 @@ module('unit/model - Model', function (hooks) { try { person.set('id', 'john'); assert.ok(false, 'we should have thrown an error during mutation'); - } catch (e) { + } catch { assert.ok(true, 'we did throw'); } diff --git a/tests/main/tests/unit/model/merge-test.js b/tests/main/tests/unit/model/merge-test.js index 3c1ba15e70e..951cfcddde8 100644 --- a/tests/main/tests/unit/model/merge-test.js +++ b/tests/main/tests/unit/model/merge-test.js @@ -202,7 +202,7 @@ module('unit/model/merge - Merging', function (hooks) { try { await person.save(); assert.ok(false, 'We should throw during save'); - } catch (e) { + } catch { assert.ok(true, 'We rejected the save'); } assert.false(person.isValid, 'the person is currently invalid'); diff --git a/tests/warp-drive__ember/tests/integration/get-promise-state-test.gts b/tests/warp-drive__ember/tests/integration/get-promise-state-test.gts index a73d4946eef..283139f0767 100644 --- a/tests/warp-drive__ember/tests/integration/get-promise-state-test.gts +++ b/tests/warp-drive__ember/tests/integration/get-promise-state-test.gts @@ -8,7 +8,7 @@ import { getPromiseState } from '@warp-drive/ember'; type PromiseState = ReturnType>; const SecretSymbol = Symbol.for('LegacyPromiseProxy'); -// eslint-disable-next-line @typescript-eslint/no-unused-vars +// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-object-type interface PromiseProxy extends Promise {} class PromiseProxy { [SecretSymbol]: true; @@ -20,8 +20,8 @@ class PromiseProxy { } then( - onFulfilled?: ((value: T) => unknown) | undefined | null, - onRejected?: ((error: E) => T2 | Promise) | undefined | null + onFulfilled?: ((value: T) => unknown) | null, + onRejected?: ((error: E) => T2 | Promise) | null ): Promise { return this.promise.then(onFulfilled!, onRejected!) as Promise; } diff --git a/tests/warp-drive__ember/tests/integration/get-request-state-test.gts b/tests/warp-drive__ember/tests/integration/get-request-state-test.gts index 756d0e49e4d..2ec05bbb3a8 100644 --- a/tests/warp-drive__ember/tests/integration/get-request-state-test.gts +++ b/tests/warp-drive__ember/tests/integration/get-request-state-test.gts @@ -422,7 +422,7 @@ module('Integration | get-request-state', function (hooks) { try { await request; - } catch (e) { + } catch { // ignore the error } let state1: RequestState; diff --git a/tests/warp-drive__ember/tests/integration/request-component-test.gts b/tests/warp-drive__ember/tests/integration/request-component-test.gts index a09b82d2a91..fc996b14851 100644 --- a/tests/warp-drive__ember/tests/integration/request-component-test.gts +++ b/tests/warp-drive__ember/tests/integration/request-component-test.gts @@ -741,7 +741,7 @@ module('Integration | ', function (hooks) { try { await request; - } catch (e) { + } catch { // ignore the error } const state = getRequestState(request); diff --git a/tests/warp-drive__schema-record/tests/legacy/mode-test.ts b/tests/warp-drive__schema-record/tests/legacy/mode-test.ts index dcbc978dfa7..cb10b21583b 100644 --- a/tests/warp-drive__schema-record/tests/legacy/mode-test.ts +++ b/tests/warp-drive__schema-record/tests/legacy/mode-test.ts @@ -93,6 +93,7 @@ module('Legacy Mode', function (hooks) { assert.true(record[Editable], 'record is editable'); try { + // eslint-disable-next-line @typescript-eslint/no-unused-expressions record.$type; assert.ok(false, 'record.$type should throw'); } catch (e) { @@ -128,6 +129,7 @@ module('Legacy Mode', function (hooks) { assert.false(record[Legacy], 'record is in legacy mode'); try { + // eslint-disable-next-line @typescript-eslint/no-unused-expressions (record.constructor as { modelName?: string }).modelName; assert.ok(false, 'record.constructor.modelName should throw'); } catch (e) { @@ -235,6 +237,7 @@ module('Legacy Mode', function (hooks) { assert.true(record[Legacy], 'record is in legacy mode'); try { + // eslint-disable-next-line @typescript-eslint/no-unused-expressions record.name; assert.ok(false, 'record.name should throw'); } catch (e) { @@ -302,6 +305,7 @@ module('Legacy Mode', function (hooks) { assert.true(record[Legacy], 'record is in legacy mode'); try { + // eslint-disable-next-line @typescript-eslint/no-unused-expressions record.bestFriend; assert.ok(false, 'record.bestFriend should throw'); } catch (e) { diff --git a/tests/warp-drive__schema-record/tests/legacy/reads/basic-fields-test.ts b/tests/warp-drive__schema-record/tests/legacy/reads/basic-fields-test.ts index 93e77934ec3..c6b18492832 100644 --- a/tests/warp-drive__schema-record/tests/legacy/reads/basic-fields-test.ts +++ b/tests/warp-drive__schema-record/tests/legacy/reads/basic-fields-test.ts @@ -60,6 +60,7 @@ module('Legacy | Reads | basic fields', function (hooks) { try { // @ts-expect-error intentionally accessing unknown field + // eslint-disable-next-line @typescript-eslint/no-unused-expressions record.lastName; assert.ok(false, 'should error when accessing unknown field'); } catch (e) { diff --git a/tests/warp-drive__schema-record/tests/reads/basic-fields-test.ts b/tests/warp-drive__schema-record/tests/reads/basic-fields-test.ts index 0777e2e85d3..8879f5e30bc 100644 --- a/tests/warp-drive__schema-record/tests/reads/basic-fields-test.ts +++ b/tests/warp-drive__schema-record/tests/reads/basic-fields-test.ts @@ -50,6 +50,7 @@ module('Reads | basic fields', function (hooks) { try { // @ts-expect-error intentionally accessing unknown field + // eslint-disable-next-line @typescript-eslint/no-unused-expressions record.lastName; assert.ok(false, 'should error when accessing unknown field'); } catch (e) { @@ -145,6 +146,7 @@ module('Reads | basic fields', function (hooks) { try { // @ts-expect-error intentionally have not typed the property on the record + // eslint-disable-next-line @typescript-eslint/no-unused-expressions record.lastName; assert.ok(false, 'should error when accessing a field with an unknown transform'); } catch (e) { diff --git a/tests/warp-drive__schema-record/tests/reads/derivation-test.ts b/tests/warp-drive__schema-record/tests/reads/derivation-test.ts index 196cfcb5a51..6cbf2e44d2a 100644 --- a/tests/warp-drive__schema-record/tests/reads/derivation-test.ts +++ b/tests/warp-drive__schema-record/tests/reads/derivation-test.ts @@ -109,6 +109,7 @@ module('Reads | derivation', function (hooks) { }) as User; try { + // eslint-disable-next-line @typescript-eslint/no-unused-expressions record.fullName; assert.ok(false, 'record.fullName should throw'); } catch (e) {