From 6886f1e9ed7f45fbc23f03bb4529553a56bf9083 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oscar=20Chaco=CC=81n?= Date: Tue, 31 Mar 2026 19:52:45 -0600 Subject: [PATCH 1/2] Migrate ESLint config from .eslintrc.json to flat config --- lint/src/util/theme-support.ts | 4 +- lint/src/util/typescript.ts | 3 +- package-lock.json | 493 ++++++++++++++++++++++++++++++--- package.json | 11 +- 4 files changed, 473 insertions(+), 38 deletions(-) diff --git a/lint/src/util/theme-support.ts b/lint/src/util/theme-support.ts index 6434b5eec11..c92df5c4c06 100644 --- a/lint/src/util/theme-support.ts +++ b/lint/src/util/theme-support.ts @@ -152,7 +152,7 @@ class ThemeableComponentRegistry { } // note: this outputs Unix-style paths on Windows - const wrappers: string[] = globSync(prefix + 'src/app/**/themed-*.component.ts', { ignore: 'node_modules/**' }); + const wrappers: string[] = globSync(prefix + 'src/app/**/themed-*.component.ts', { ignore: 'node_modules/**' }).map(toUnixStylePath); for (const wrapper of wrappers) { registerWrapper(wrapper); @@ -271,7 +271,7 @@ export function fixSelectors(text: string): string { */ export function getFileTheme(context: RuleContext): string | undefined { // note: shouldn't use plain .filename (doesn't work in DSpace Angular 7.4) - const m = context.getFilename()?.match(/\/src\/themes\/([^/]+)\//); + const m = toUnixStylePath(context.getFilename())?.match(/\/src\/themes\/([^/]+)\//); if (m?.length === 2) { return m[1]; diff --git a/lint/src/util/typescript.ts b/lint/src/util/typescript.ts index 7c8446b4fcd..6ff3f1445c2 100644 --- a/lint/src/util/typescript.ts +++ b/lint/src/util/typescript.ts @@ -97,7 +97,8 @@ export function isPartOfClassDeclaration(node: TSESTree.Identifier): boolean { } function fromSrc(path: string): string { - const m = path.match(/^.*(src\/.+)(\.(ts|json|js)?)$/); + const normalized = toUnixStylePath(path); + const m = normalized.match(/^.*(src\/.+)(\.(ts|json|js)?)$/); if (m) { return m[1]; diff --git a/package-lock.json b/package-lock.json index 38ecc1a7d59..78e6c1e3d70 100644 --- a/package-lock.json +++ b/package-lock.json @@ -96,6 +96,7 @@ "@angular/cli": "^20.3.19", "@angular/compiler-cli": "^20.3.17", "@cypress/schematic": "^1.5.0", + "@eslint/js": "^9.39.4", "@fortawesome/fontawesome-free": "^6.7.2", "@ngrx/store-devtools": "^20.1.0", "@ngtools/webpack": "^20.3.10", @@ -113,6 +114,7 @@ "@typescript-eslint/parser": "^8.56.1", "@typescript-eslint/rule-tester": "^8.56.1", "@typescript-eslint/utils": "^8.47.0", + "angular-eslint": "^20.7.0", "axe-core": "^4.11.1", "commander": "^14.0.2", "compression-webpack-plugin": "^9.2.0", @@ -121,7 +123,7 @@ "cypress": "^13.17.0", "cypress-axe": "^1.7.0", "deep-freeze": "0.0.1", - "eslint": "^9.39.3", + "eslint": "^9.39.4", "eslint-plugin-dspace-angular-html": "file:./lint/dist/src/rules/html", "eslint-plugin-dspace-angular-ts": "file:./lint/dist/src/rules/ts", "eslint-plugin-import": "^2.32.0", @@ -156,6 +158,7 @@ "ts-node": "^8.10.2", "tsconfig-paths": "^4.2.0", "typescript": "~5.9.3", + "typescript-eslint": "^8.58.0", "webpack": "^5.54.0", "webpack-cli": "^6.0.1" }, @@ -5720,15 +5723,15 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.21.1", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", - "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz", + "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", "dev": true, "license": "Apache-2.0", "dependencies": { "@eslint/object-schema": "^2.1.7", "debug": "^4.3.1", - "minimatch": "^3.1.2" + "minimatch": "^3.1.5" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -5761,20 +5764,20 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", - "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.5.tgz", + "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==", "dev": true, "license": "MIT", "dependencies": { - "ajv": "^6.12.4", + "ajv": "^6.14.0", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.5", "strip-json-comments": "^3.1.1" }, "engines": { @@ -5785,9 +5788,9 @@ } }, "node_modules/@eslint/eslintrc/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", "dev": true, "license": "MIT", "dependencies": { @@ -5819,9 +5822,9 @@ "license": "MIT" }, "node_modules/@eslint/js": { - "version": "9.39.3", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.3.tgz", - "integrity": "sha512-1B1VkCq6FuUNlQvlBYb+1jDu/gV297TIs/OeiaSR9l1H27SVW55ONE1e1Vp16NqP683+xEGzxYtv4XCiDPaQiw==", + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.4.tgz", + "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==", "dev": true, "license": "MIT", "engines": { @@ -10819,6 +10822,121 @@ "linux" ] }, + "node_modules/angular-eslint": { + "version": "20.7.0", + "resolved": "https://registry.npmjs.org/angular-eslint/-/angular-eslint-20.7.0.tgz", + "integrity": "sha512-BCiTCLO3dr8pGPaM7qLcCruWNcoNNHnLn4DPqE5tHk1TAnTx5TcGy0p/FygharZw5RjWfDHLBjFfpeh4XWLMmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/core": ">= 20.0.0 < 21.0.0", + "@angular-devkit/schematics": ">= 20.0.0 < 21.0.0", + "@angular-eslint/builder": "20.7.0", + "@angular-eslint/eslint-plugin": "20.7.0", + "@angular-eslint/eslint-plugin-template": "20.7.0", + "@angular-eslint/schematics": "20.7.0", + "@angular-eslint/template-parser": "20.7.0", + "@typescript-eslint/types": "^8.0.0", + "@typescript-eslint/utils": "^8.0.0" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": "*", + "typescript-eslint": "^8.0.0" + } + }, + "node_modules/angular-eslint/node_modules/@angular-devkit/core": { + "version": "20.3.22", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-20.3.22.tgz", + "integrity": "sha512-1vZnZTAjGcCM+86v2al+2eiROiSw0uAWeVllfHSQe0KsKOP1FE8UUUiWChhxVn7vIxypphlfGunkeeIn1C/ZFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "8.18.0", + "ajv-formats": "3.0.1", + "jsonc-parser": "3.3.1", + "picomatch": "4.0.4", + "rxjs": "7.8.2", + "source-map": "0.7.6" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^4.0.0" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/angular-eslint/node_modules/ajv": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/angular-eslint/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/angular-eslint/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/angular-eslint/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/angulartics2": { "version": "12.2.1", "resolved": "https://registry.npmjs.org/angulartics2/-/angulartics2-12.2.1.tgz", @@ -14123,25 +14241,25 @@ } }, "node_modules/eslint": { - "version": "9.39.3", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.3.tgz", - "integrity": "sha512-VmQ+sifHUbI/IcSopBCF/HO3YiHQx/AVd3UVyYL6weuwW+HvON9VYn5l6Zl1WZzPWXPNZrSQpxwkkZ/VuvJZzg==", + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz", + "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.21.1", + "@eslint/config-array": "^0.21.2", "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", - "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.39.3", + "@eslint/eslintrc": "^3.3.5", + "@eslint/js": "9.39.4", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", - "ajv": "^6.12.4", + "ajv": "^6.14.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", @@ -14160,7 +14278,7 @@ "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", + "minimatch": "^3.1.5", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, @@ -14548,9 +14666,9 @@ } }, "node_modules/eslint/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", "dev": true, "license": "MIT", "dependencies": { @@ -24911,9 +25029,9 @@ } }, "node_modules/ts-api-utils": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", - "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", "dev": true, "license": "MIT", "engines": { @@ -25141,6 +25259,319 @@ "typescript-logic": "^0.0.0" } }, + "node_modules/typescript-eslint": { + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.58.0.tgz", + "integrity": "sha512-e2TQzKfaI85fO+F3QywtX+tCTsu/D3WW5LVU6nz8hTFKFZ8yBJ6mSYRpXqdR3mFjPWmO0eWsTa5f+UpAOe/FMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.58.0", + "@typescript-eslint/parser": "8.58.0", + "@typescript-eslint/typescript-estree": "8.58.0", + "@typescript-eslint/utils": "8.58.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.58.0.tgz", + "integrity": "sha512-RLkVSiNuUP1C2ROIWfqX+YcUfLaSnxGE/8M+Y57lopVwg9VTYYfhuz15Yf1IzCKgZj6/rIbYTmJCUSqr76r0Wg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.58.0", + "@typescript-eslint/type-utils": "8.58.0", + "@typescript-eslint/utils": "8.58.0", + "@typescript-eslint/visitor-keys": "8.58.0", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.58.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/parser": { + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.58.0.tgz", + "integrity": "sha512-rLoGZIf9afaRBYsPUMtvkDWykwXwUPL60HebR4JgTI8mxfFe2cQTu3AGitANp4b9B2QlVru6WzjgB2IzJKiCSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.58.0", + "@typescript-eslint/types": "8.58.0", + "@typescript-eslint/typescript-estree": "8.58.0", + "@typescript-eslint/visitor-keys": "8.58.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/project-service": { + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.58.0.tgz", + "integrity": "sha512-8Q/wBPWLQP1j16NxoPNIKpDZFMaxl7yWIoqXWYeWO+Bbd2mjgvoF0dxP2jKZg5+x49rgKdf7Ck473M8PC3V9lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.58.0", + "@typescript-eslint/types": "^8.58.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/scope-manager": { + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.58.0.tgz", + "integrity": "sha512-W1Lur1oF50FxSnNdGp3Vs6P+yBRSmZiw4IIjEeYxd8UQJwhUF0gDgDD/W/Tgmh73mxgEU3qX0Bzdl/NGuSPEpQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.58.0", + "@typescript-eslint/visitor-keys": "8.58.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.58.0.tgz", + "integrity": "sha512-doNSZEVJsWEu4htiVC+PR6NpM+pa+a4ClH9INRWOWCUzMst/VA9c4gXq92F8GUD1rwhNvRLkgjfYtFXegXQF7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/type-utils": { + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.58.0.tgz", + "integrity": "sha512-aGsCQImkDIqMyx1u4PrVlbi/krmDsQUs4zAcCV6M7yPcPev+RqVlndsJy9kJ8TLihW9TZ0kbDAzctpLn5o+lOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.58.0", + "@typescript-eslint/typescript-estree": "8.58.0", + "@typescript-eslint/utils": "8.58.0", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/types": { + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.58.0.tgz", + "integrity": "sha512-O9CjxypDT89fbHxRfETNoAnHj/i6IpRK0CvbVN3qibxlLdo5p5hcLmUuCCrHMpxiWSwKyI8mCP7qRNYuOJ0Uww==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.58.0.tgz", + "integrity": "sha512-7vv5UWbHqew/dvs+D3e1RvLv1v2eeZ9txRHPnEEBUgSNLx5ghdzjHa0sgLWYVKssH+lYmV0JaWdoubo0ncGYLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.58.0", + "@typescript-eslint/tsconfig-utils": "8.58.0", + "@typescript-eslint/types": "8.58.0", + "@typescript-eslint/visitor-keys": "8.58.0", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/utils": { + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.58.0.tgz", + "integrity": "sha512-RfeSqcFeHMHlAWzt4TBjWOAtoW9lnsAGiP3GbaX9uVgTYYrMbVnGONEfUCiSss+xMHFl+eHZiipmA8WkQ7FuNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.58.0", + "@typescript-eslint/types": "8.58.0", + "@typescript-eslint/typescript-estree": "8.58.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.58.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.58.0.tgz", + "integrity": "sha512-XJ9UD9+bbDo4a4epraTwG3TsNPeiB9aShrUneAVXy8q4LuwowN+qu89/6ByLMINqvIMeI9H9hOHQtg/ijrYXzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.58.0", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/typescript-eslint/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/typescript-eslint/node_modules/brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/typescript-eslint/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/typescript-eslint/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/typescript-eslint/node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, "node_modules/typescript-logic": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/typescript-logic/-/typescript-logic-0.0.0.tgz", diff --git a/package.json b/package.json index 4aa4eb4e18b..178ed4be354 100644 --- a/package.json +++ b/package.json @@ -77,6 +77,8 @@ } }, "dependencies": { + "@4science_ng-dynamic-forms/core": "^19.1.0", + "@4science_ng-dynamic-forms/ui-ng-bootstrap": "^19.1.0", "@angular/animations": "^20.3.17", "@angular/cdk": "^20.2.14", "@angular/common": "^20.3.17", @@ -91,8 +93,6 @@ "@angular/ssr": "^20.3.19", "@kolkov/ngx-gallery": "^2.0.1", "@ng-bootstrap/ng-bootstrap": "^15.1.2", - "@4science_ng-dynamic-forms/core": "^19.1.0", - "@4science_ng-dynamic-forms/ui-ng-bootstrap": "^19.1.0", "@ngrx/effects": "^20.1.0", "@ngrx/router-store": "^20.1.0", "@ngrx/store": "^20.1.0", @@ -164,9 +164,11 @@ "@angular/cli": "^20.3.19", "@angular/compiler-cli": "^20.3.17", "@cypress/schematic": "^1.5.0", + "@eslint/js": "^9.39.4", "@fortawesome/fontawesome-free": "^6.7.2", "@ngrx/store-devtools": "^20.1.0", "@ngtools/webpack": "^20.3.10", + "@smarttools/eslint-plugin-rxjs": "^1.0.22", "@stylistic/eslint-plugin": "^3.1.0", "@types/deep-freeze": "0.1.5", "@types/ejs": "^3.1.2", @@ -180,6 +182,7 @@ "@typescript-eslint/parser": "^8.56.1", "@typescript-eslint/rule-tester": "^8.56.1", "@typescript-eslint/utils": "^8.47.0", + "angular-eslint": "^20.7.0", "axe-core": "^4.11.1", "commander": "^14.0.2", "compression-webpack-plugin": "^9.2.0", @@ -188,7 +191,7 @@ "cypress": "^13.17.0", "cypress-axe": "^1.7.0", "deep-freeze": "0.0.1", - "eslint": "^9.39.3", + "eslint": "^9.39.4", "eslint-plugin-dspace-angular-html": "file:./lint/dist/src/rules/html", "eslint-plugin-dspace-angular-ts": "file:./lint/dist/src/rules/ts", "eslint-plugin-import": "^2.32.0", @@ -196,7 +199,6 @@ "eslint-plugin-jsdoc": "^61.7.1", "eslint-plugin-jsonc": "^2.21.1", "eslint-plugin-lodash": "^7.4.0", - "@smarttools/eslint-plugin-rxjs": "^1.0.22", "eslint-plugin-simple-import-sort": "^12.1.1", "eslint-plugin-unused-imports": "^4.4.1", "express-static-gzip": "^2.2.0", @@ -224,6 +226,7 @@ "ts-node": "^8.10.2", "tsconfig-paths": "^4.2.0", "typescript": "~5.9.3", + "typescript-eslint": "^8.58.0", "webpack": "^5.54.0", "webpack-cli": "^6.0.1" }, From cc5735c03bca9f70f6ecfafa6bd52d72d9810a52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oscar=20Chaco=CC=81n?= Date: Tue, 31 Mar 2026 19:53:18 -0600 Subject: [PATCH 2/2] hotfix: updated file config structure --- .eslintrc.json | 388 -------------------------------------------- eslint.config.mjs | 405 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 405 insertions(+), 388 deletions(-) delete mode 100644 .eslintrc.json create mode 100644 eslint.config.mjs diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 3d38f3bc4da..00000000000 --- a/.eslintrc.json +++ /dev/null @@ -1,388 +0,0 @@ -{ - "root": true, - "plugins": [ - "@typescript-eslint", - "@angular-eslint/eslint-plugin", - "eslint-plugin-import", - "eslint-plugin-jsdoc", - "unused-imports", - "eslint-plugin-lodash", - "eslint-plugin-jsonc", - "@smarttools/rxjs", - "eslint-plugin-simple-import-sort", - "eslint-plugin-import-newlines", - "@stylistic", - "dspace-angular-ts", - "dspace-angular-html" - ], - "ignorePatterns": [ - "lint/test/fixture" - ], - "overrides": [ - { - "files": [ - "*.ts" - ], - "parserOptions": { - "project": [ - "./tsconfig.json", - "./cypress/tsconfig.json", - "./lint/tsconfig.json" - ], - "createDefaultProgram": true - }, - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/recommended", - "plugin:@typescript-eslint/recommended-requiring-type-checking", - "plugin:@angular-eslint/recommended", - "plugin:@angular-eslint/template/process-inline-templates", - "plugin:@smarttools/rxjs/recommended-legacy" - ], - "rules": { - "indent": [ - "error", - 2, - { - "SwitchCase": 1, - "ignoredNodes": [ - "ClassBody.body > PropertyDefinition[decorators.length > 0] > .key" - ] - } - ], - "max-classes-per-file": [ - "error", - 1 - ], - "comma-dangle": [ - "error", - "always-multiline" - ], - "object-curly-spacing": [ - "error", - "always" - ], - "eol-last": [ - "error", - "always" - ], - "no-console": [ - "error", - { - "allow": [ - "log", - "warn", - "dir", - "timeLog", - "assert", - "clear", - "count", - "countReset", - "group", - "groupEnd", - "table", - "debug", - "info", - "dirxml", - "error", - "groupCollapsed", - "Console", - "profile", - "profileEnd", - "timeStamp", - "context" - ] - } - ], - "curly": "error", - "brace-style": [ - "error", - "1tbs", - { - "allowSingleLine": true - } - ], - "eqeqeq": [ - "error", - "always", - { - "null": "ignore" - } - ], - "radix": "error", - "guard-for-in": "error", - "no-bitwise": "error", - "no-restricted-imports": "error", - "no-caller": "error", - "no-debugger": "error", - "no-redeclare": "error", - "no-eval": "error", - "no-fallthrough": "error", - "no-trailing-spaces": "error", - "space-infix-ops": "error", - "keyword-spacing": "error", - "no-var": "error", - "no-unused-expressions": [ - "error", - { - "allowTernary": true - } - ], - "prefer-const": "error", - "no-case-declarations": "error", - "no-extra-boolean-cast": "error", - "prefer-spread": "off", - "no-underscore-dangle": "off", - "no-prototype-builtins": "off", - "no-useless-escape": "off", - - "@angular-eslint/directive-selector": [ - "error", - { - "type": "attribute", - "prefix": "ds", - "style": "camelCase" - } - ], - "@angular-eslint/component-selector": [ - "error", - { - "type": "element", - "prefix": "ds", - "style": "kebab-case" - } - ], - "@angular-eslint/pipe-prefix": [ - "error", - { - "prefixes": [ - "ds" - ] - } - ], - "@angular-eslint/prefer-standalone": [ - "error" - ], - "@angular-eslint/no-attribute-decorator": "error", - "@angular-eslint/no-output-native": "warn", - "@angular-eslint/no-output-on-prefix": "warn", - "@angular-eslint/no-conflicting-lifecycle": "warn", - "@angular-eslint/use-lifecycle-interface": "error", - - "@typescript-eslint/no-inferrable-types":[ - "error", - { - "ignoreParameters": true - } - ], - "@angular-eslint/prefer-inject": "off", - "@stylistic/quotes": [ - "error", - "single", - { - "avoidEscape": true, - "allowTemplateLiterals": true - } - ], - "@stylistic/semi": "error", - "@typescript-eslint/no-shadow": "error", - "@typescript-eslint/dot-notation": "error", - "@typescript-eslint/consistent-type-definitions": "error", - "@typescript-eslint/prefer-function-type": "error", - "@typescript-eslint/naming-convention": [ - "error", - { - "selector": "property", - "format": null - } - ], - "@typescript-eslint/member-ordering": [ - "error", - { - "default": [ - "static-field", - "instance-field", - "static-method", - "instance-method" - ] - } - ], - "@stylistic/type-annotation-spacing": "error", - "@typescript-eslint/unified-signatures": "error", - "@typescript-eslint/no-restricted-types": "error", - "@typescript-eslint/no-floating-promises": "warn", - "@typescript-eslint/no-misused-promises": "warn", - "@typescript-eslint/restrict-plus-operands": "warn", - "@typescript-eslint/unbound-method": "off", - "@typescript-eslint/ban-ts-comment": "off", - "@typescript-eslint/no-var-requires": "off", - "@typescript-eslint/no-unused-vars": "off", - "@typescript-eslint/no-unnecessary-type-assertion": "off", - "@typescript-eslint/no-explicit-any": "off", - "@typescript-eslint/no-unsafe-assignment": "off", - "@typescript-eslint/no-unsafe-member-access": "off", - "@typescript-eslint/no-unsafe-call": "off", - "@typescript-eslint/no-unsafe-argument": "off", - "@typescript-eslint/no-unsafe-return": "off", - "@typescript-eslint/no-redundant-type-constituents": "off", - "@typescript-eslint/restrict-template-expressions": "off", - "@typescript-eslint/require-await": "off", - "@typescript-eslint/no-base-to-string": [ - "error", - { - "ignoredTypeNames": [ - "ResourceType", - "Error" - ] - } - ], - - "@typescript-eslint/no-deprecated": "warn", - - "simple-import-sort/imports": "error", - "simple-import-sort/exports": "error", - "import/order": "off", - "import/first": "error", - "import/newline-after-import": "error", - "import/no-duplicates": "error", - "import/no-deprecated": "warn", - "import/no-namespace": "error", - "import-newlines/enforce": [ - "error", - { - "items": 1, - "semi": true, - "forceSingleLine": true - } - ], - "import/enforce-node-protocol-usage": [ - "error", - "always" - ], - - "unused-imports/no-unused-imports": "error", - "lodash/import-scope": [ - "error", - "method" - ], - - "@smarttools/rxjs/no-nested-subscribe": "off", // todo: go over _all_ cases - - // Custom DSpace Angular rules - "dspace-angular-ts/alias-imports": [ - "error", - { - "aliases": [ - { - "package": "rxjs", - "imported": "of", - "local": "of" - } - ] - } - ], - "dspace-angular-ts/no-default-standalone-value": "error", - "dspace-angular-ts/themed-component-selectors": "error", - "dspace-angular-ts/themed-component-usages": "error", - "dspace-angular-ts/themed-decorators": [ - "off", - { - "decorators": { - "listableObjectComponent": 3, - "rendersSectionForMenu": 2 - } - } - ], - "dspace-angular-ts/themed-wrapper-no-input-defaults": "error", - "dspace-angular-ts/unique-decorators": [ - "off", - { - "decorators": [ - "listableObjectComponent" - ] - } - ], - "dspace-angular-ts/sort-standalone-imports": [ - "error", - { - "locale": "en-US", - "maxItems": 0, - "indent": 2, - "trailingComma": true - } - ] - } - }, - { - "files": [ - "*.spec.ts" - ], - "parserOptions": { - "project": [ - "./tsconfig.json", - "./cypress/tsconfig.json" - ], - "createDefaultProgram": true - }, - "rules": { - "prefer-const": "off", - - // Custom DSpace Angular rules - "dspace-angular-ts/themed-component-usages": "error" - } - }, - { - "files": [ - "*.html" - ], - "extends": [ - "plugin:@angular-eslint/template/recommended" - ], - "rules": { - // Custom DSpace Angular rules - "dspace-angular-html/themed-component-usages": "error", - "dspace-angular-html/no-disabled-attribute-on-button": "error", - "@angular-eslint/template/prefer-control-flow": "error" - } - }, - { - "files": [ - "*.json5" - ], - "extends": [ - "plugin:jsonc/recommended-with-json5" - ], - "rules": { - // The ESLint core no-irregular-whitespace rule doesn't work well in JSON - // See: https://ota-meshi.github.io/eslint-plugin-jsonc/rules/no-irregular-whitespace.html - "no-irregular-whitespace": "off", - "jsonc/no-irregular-whitespace": "error", - "no-trailing-spaces": "error", - "jsonc/comma-dangle": [ - "error", - "always-multiline" - ], - "jsonc/indent": [ - "error", - 2 - ], - "jsonc/key-spacing": [ - "error", - { - "beforeColon": false, - "afterColon": true, - "mode": "strict" - } - ], - "jsonc/no-dupe-keys": "off", - "jsonc/quotes": [ - "error", - "double", - { - "avoidEscape": false - } - ] - } - } - ] -} diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 00000000000..696c48445b9 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,405 @@ +// @ts-check +import js from '@eslint/js'; +import tseslint from 'typescript-eslint'; +import angular from 'angular-eslint'; +import rxjs from '@smarttools/eslint-plugin-rxjs'; +import stylistic from '@stylistic/eslint-plugin'; +import importPlugin from 'eslint-plugin-import'; +import simpleImportSort from 'eslint-plugin-simple-import-sort'; +import importNewlines from 'eslint-plugin-import-newlines'; +import unusedImports from 'eslint-plugin-unused-imports'; +import lodash from 'eslint-plugin-lodash'; +import jsdoc from 'eslint-plugin-jsdoc'; +import jsonc from 'eslint-plugin-jsonc'; +import dspaceTs from 'eslint-plugin-dspace-angular-ts'; +import dspaceHtml from 'eslint-plugin-dspace-angular-html'; + +export default tseslint.config( + // ── Global ignores (replaces ignorePatterns) ────────────── + { + ignores: ['lint/test/fixture/**'], + }, + + // ── TypeScript files ────────────────────────────────────── + { + files: ['**/*.ts'], + extends: [ + js.configs.recommended, + ...tseslint.configs.recommended, + ...tseslint.configs.recommendedTypeChecked, + ...angular.configs.tsRecommended, + ], + processor: angular.processInlineTemplates, + languageOptions: { + parserOptions: { + project: [ + './tsconfig.json', + './cypress/tsconfig.json', + './lint/tsconfig.json', + ], + createDefaultProgram: true, + }, + }, + plugins: { + '@stylistic': stylistic, + 'import': importPlugin, + 'simple-import-sort': simpleImportSort, + 'import-newlines': importNewlines, + 'unused-imports': unusedImports, + 'lodash': lodash, + 'jsdoc': jsdoc, + '@smarttools/rxjs': rxjs, + 'dspace-angular-ts': dspaceTs, + }, + rules: { + 'indent': [ + 'error', + 2, + { + 'SwitchCase': 1, + 'ignoredNodes': [ + 'ClassBody.body > PropertyDefinition[decorators.length > 0] > .key', + ], + }, + ], + 'max-classes-per-file': [ + 'error', + 1, + ], + 'comma-dangle': [ + 'error', + 'always-multiline', + ], + 'object-curly-spacing': [ + 'error', + 'always', + ], + 'eol-last': [ + 'error', + 'always', + ], + 'no-console': [ + 'error', + { + 'allow': [ + 'log', + 'warn', + 'dir', + 'timeLog', + 'assert', + 'clear', + 'count', + 'countReset', + 'group', + 'groupEnd', + 'table', + 'debug', + 'info', + 'dirxml', + 'error', + 'groupCollapsed', + 'Console', + 'profile', + 'profileEnd', + 'timeStamp', + 'context', + ], + }, + ], + 'curly': 'error', + 'brace-style': [ + 'error', + '1tbs', + { + 'allowSingleLine': true, + }, + ], + 'eqeqeq': [ + 'error', + 'always', + { + 'null': 'ignore', + }, + ], + 'radix': 'error', + 'guard-for-in': 'error', + 'no-bitwise': 'error', + 'no-restricted-imports': 'error', + 'no-caller': 'error', + 'no-debugger': 'error', + 'no-redeclare': 'error', + 'no-eval': 'error', + 'no-fallthrough': 'error', + 'no-trailing-spaces': 'error', + 'space-infix-ops': 'error', + 'keyword-spacing': 'error', + 'no-var': 'error', + 'no-unused-expressions': [ + 'error', + { + 'allowTernary': true, + }, + ], + 'prefer-const': 'error', + 'no-case-declarations': 'error', + 'no-extra-boolean-cast': 'error', + 'prefer-spread': 'off', + 'no-underscore-dangle': 'off', + 'no-prototype-builtins': 'off', + 'no-useless-escape': 'off', + + '@angular-eslint/directive-selector': [ + 'error', + { + 'type': 'attribute', + 'prefix': 'ds', + 'style': 'camelCase', + }, + ], + '@angular-eslint/component-selector': [ + 'error', + { + 'type': 'element', + 'prefix': 'ds', + 'style': 'kebab-case', + }, + ], + '@angular-eslint/pipe-prefix': [ + 'error', + { + 'prefixes': [ + 'ds', + ], + }, + ], + '@angular-eslint/prefer-standalone': [ + 'error', + ], + '@angular-eslint/no-attribute-decorator': 'error', + '@angular-eslint/no-output-native': 'warn', + '@angular-eslint/no-output-on-prefix': 'warn', + '@angular-eslint/no-conflicting-lifecycle': 'warn', + '@angular-eslint/use-lifecycle-interface': 'error', + + '@typescript-eslint/no-inferrable-types': [ + 'error', + { + 'ignoreParameters': true, + }, + ], + '@angular-eslint/prefer-inject': 'off', + '@stylistic/quotes': [ + 'error', + 'single', + { + 'avoidEscape': true, + 'allowTemplateLiterals': true, + }, + ], + '@stylistic/semi': 'error', + '@typescript-eslint/no-shadow': 'error', + '@typescript-eslint/dot-notation': 'error', + '@typescript-eslint/consistent-type-definitions': 'error', + '@typescript-eslint/prefer-function-type': 'error', + '@typescript-eslint/naming-convention': [ + 'error', + { + 'selector': 'property', + 'format': null, + }, + ], + '@typescript-eslint/member-ordering': [ + 'error', + { + 'default': [ + 'static-field', + 'instance-field', + 'static-method', + 'instance-method', + ], + }, + ], + '@stylistic/type-annotation-spacing': 'error', + '@typescript-eslint/unified-signatures': 'error', + '@typescript-eslint/no-restricted-types': 'error', + '@typescript-eslint/no-floating-promises': 'warn', + '@typescript-eslint/no-misused-promises': 'warn', + '@typescript-eslint/restrict-plus-operands': 'warn', + '@typescript-eslint/unbound-method': 'off', + '@typescript-eslint/ban-ts-comment': 'off', + '@typescript-eslint/no-var-requires': 'off', + '@typescript-eslint/no-unused-vars': 'off', + '@typescript-eslint/no-unnecessary-type-assertion': 'off', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-unsafe-assignment': 'off', + '@typescript-eslint/no-unsafe-member-access': 'off', + '@typescript-eslint/no-unsafe-call': 'off', + '@typescript-eslint/no-unsafe-argument': 'off', + '@typescript-eslint/no-unsafe-return': 'off', + '@typescript-eslint/no-redundant-type-constituents': 'off', + '@typescript-eslint/restrict-template-expressions': 'off', + '@typescript-eslint/require-await': 'off', + '@typescript-eslint/no-base-to-string': [ + 'error', + { + 'ignoredTypeNames': [ + 'ResourceType', + 'Error', + ], + }, + ], + + '@typescript-eslint/no-deprecated': 'warn', + + 'simple-import-sort/imports': 'error', + 'simple-import-sort/exports': 'error', + 'import/order': 'off', + 'import/first': 'error', + 'import/newline-after-import': 'error', + 'import/no-duplicates': 'error', + 'import/no-deprecated': 'warn', + 'import/no-namespace': 'error', + 'import-newlines/enforce': [ + 'error', + { + 'items': 1, + 'semi': true, + 'forceSingleLine': true, + }, + ], + 'import/enforce-node-protocol-usage': [ + 'error', + 'always', + ], + + 'unused-imports/no-unused-imports': 'error', + 'lodash/import-scope': [ + 'error', + 'method', + ], + + // todo: go over _all_ cases + '@smarttools/rxjs/no-nested-subscribe': 'off', + + // Custom DSpace Angular rules + 'dspace-angular-ts/alias-imports': [ + 'error', + { + 'aliases': [ + { + 'package': 'rxjs', + 'imported': 'of', + 'local': 'of', + }, + ], + }, + ], + 'dspace-angular-ts/no-default-standalone-value': 'error', + 'dspace-angular-ts/themed-component-selectors': 'error', + 'dspace-angular-ts/themed-component-usages': 'error', + 'dspace-angular-ts/themed-decorators': [ + 'off', + { + 'decorators': { + 'listableObjectComponent': 3, + 'rendersSectionForMenu': 2, + }, + }, + ], + 'dspace-angular-ts/themed-wrapper-no-input-defaults': 'error', + 'dspace-angular-ts/unique-decorators': [ + 'off', + { + 'decorators': [ + 'listableObjectComponent', + ], + }, + ], + 'dspace-angular-ts/sort-standalone-imports': [ + 'error', + { + 'locale': 'en-US', + 'maxItems': 0, + 'indent': 2, + 'trailingComma': true, + }, + ], + }, + }, + + // ── Spec files (overrides for test files) ───────────────── + { + files: ['**/*.spec.ts'], + languageOptions: { + parserOptions: { + project: [ + './tsconfig.json', + './cypress/tsconfig.json', + ], + createDefaultProgram: true, + }, + }, + rules: { + 'prefer-const': 'off', + + // Custom DSpace Angular rules + 'dspace-angular-ts/themed-component-usages': 'error', + }, + }, + + // ── HTML template files ─────────────────────────────────── + { + files: ['**/*.html'], + extends: [ + ...angular.configs.templateRecommended, + ], + plugins: { + 'dspace-angular-html': dspaceHtml, + }, + rules: { + // Custom DSpace Angular rules + 'dspace-angular-html/themed-component-usages': 'error', + 'dspace-angular-html/no-disabled-attribute-on-button': 'error', + '@angular-eslint/template/prefer-control-flow': 'error', + }, + }, + + // ── JSON5 files ─────────────────────────────────────────── + { + files: ['**/*.json5'], + extends: [ + ...jsonc.configs['flat/recommended-with-json5'], + ], + rules: { + // The ESLint core no-irregular-whitespace rule doesn't work well in JSON + // See: https://ota-meshi.github.io/eslint-plugin-jsonc/rules/no-irregular-whitespace.html + 'no-irregular-whitespace': 'off', + 'jsonc/no-irregular-whitespace': 'error', + 'no-trailing-spaces': 'error', + 'jsonc/comma-dangle': [ + 'error', + 'always-multiline', + ], + 'jsonc/indent': [ + 'error', + 2, + ], + 'jsonc/key-spacing': [ + 'error', + { + 'beforeColon': false, + 'afterColon': true, + 'mode': 'strict', + }, + ], + 'jsonc/no-dupe-keys': 'off', + 'jsonc/quotes': [ + 'error', + 'double', + { + 'avoidEscape': false, + }, + ], + }, + }, +); \ No newline at end of file