From bdda5dcf01e90e74018fd423de8459fed29b43b6 Mon Sep 17 00:00:00 2001 From: Valtteri Kantanen <91893789+valtterikantanen@users.noreply.github.com> Date: Mon, 11 Nov 2024 16:08:16 +0200 Subject: [PATCH] Migrate ESLint to v9 (#4676) --- .eslintrc.json | 122 +- .github/actions/lint/action.yaml | 2 +- .github/workflows/updater.yaml | 2 +- eslint.config.mjs | 175 +++ package-lock.json | 1003 +++++++++-------- package.json | 24 +- services/backend/src/database/connection.ts | 2 +- .../backend/src/middleware/accessLogger.ts | 6 +- services/backend/src/middleware/auth.ts | 2 +- .../backend/src/middleware/currentUser.ts | 6 +- services/backend/src/models/SISStudyRight.ts | 1 - .../src/models/SISStudyRightElement.ts | 1 - services/backend/src/models/course.ts | 1 - services/backend/src/models/courseProvider.ts | 1 - services/backend/src/models/courseType.ts | 1 - services/backend/src/models/credit.ts | 1 - services/backend/src/models/creditTeacher.ts | 1 - services/backend/src/models/creditType.ts | 1 - services/backend/src/models/enrollment.ts | 1 - services/backend/src/models/index.ts | 1 - services/backend/src/models/kone/tag.ts | 1 - .../backend/src/models/kone/tagStudent.ts | 1 - services/backend/src/models/organization.ts | 1 - .../backend/src/models/programmeModule.ts | 1 - .../src/models/programmeModuleChild.ts | 1 - services/backend/src/models/student.ts | 1 - services/backend/src/models/studyplan.ts | 1 - .../backend/src/models/studyrightExtent.ts | 1 - services/backend/src/models/teacher.ts | 1 - services/backend/src/models/user.ts | 1 - services/backend/src/rapodiff/creditsDiff.js | 7 +- services/backend/src/routes.ts | 5 +- services/backend/src/routes/courses.ts | 2 +- services/backend/src/routes/login.ts | 2 +- services/backend/src/routes/population.ts | 7 +- services/backend/src/routes/studyProgramme.ts | 6 +- services/backend/src/routes/tags.ts | 1 - services/backend/src/routes/updater.ts | 10 +- services/backend/src/routes/users.ts | 2 +- .../src/services/completedCoursesSearch.ts | 4 +- .../services/courses/courseStatsCounter.ts | 33 +- .../backend/src/services/courses/index.ts | 6 +- .../src/services/faculty/facultyService.ts | 6 +- .../faculty/facultyStudentProgress.ts | 2 +- .../src/services/faculty/facultyStudents.ts | 2 +- .../services/openUni/openUniManageSearches.ts | 2 +- .../src/services/openUni/openUniStats.ts | 4 +- .../src/services/populations/bottlenecksOf.ts | 8 +- .../services/populations/closeToGraduation.ts | 2 +- .../populations/optimizedStatisticsOf.ts | 4 +- .../src/services/populations/shared.ts | 32 +- .../backend/src/services/providerCredits.ts | 14 +- services/backend/src/services/providers.ts | 2 +- .../studyProgramme/studyProgrammeCourses.ts | 6 +- .../studyProgrammeGraduations.ts | 10 +- services/backend/src/services/teachers/top.ts | 5 +- services/backend/src/services/userService.ts | 4 +- services/backend/src/types/course.ts | 1 - services/backend/src/types/index.ts | 1 - services/backend/src/types/user.ts | 1 - services/backend/src/util/index.ts | 6 +- services/backend/src/util/jami.ts | 23 +- services/backend/src/util/mami.js | 1 - services/backend/src/util/semester.ts | 11 +- services/backend/src/worker/worker.js | 1 + services/frontend/.eslintrc.json | 108 -- .../CourseStatistics/CourseTable/index.jsx | 2 +- .../CourseStatistics/ResultTabs/panes/util.ts | 36 +- .../index.jsx | 1 - .../TimesAndPaths/MedianBarChart.jsx | 18 +- .../FacultyStatistics/facultyHelpers.ts | 20 +- .../FilterView/filters/date/index.jsx | 1 - .../src/components/LanguagePicker/index.jsx | 31 - .../components/PopulationStudents/index.jsx | 2 +- .../components/SortableTable/columnHeader.jsx | 1 - .../SortableTable/visitors/DataVisitor.js | 1 - .../StudyProgramme/MedianTimeBarChart.tsx | 6 +- .../StudyTrackOverview/BarChart.tsx | 2 +- .../StudyTrackOverview/BasicDataTable.tsx | 2 +- .../TeacherLeaderBoard/LeaderForm.jsx | 4 +- services/frontend/src/conf.js | 8 - services/frontend/src/main.jsx | 1 + services/frontend/tsconfig.node.json | 3 +- services/frontend/vite.config.ts | 2 +- .../sis-updater-scheduler/src/scheduler.js | 1 + .../migrations/20200306_00_fix_constraints.js | 18 +- ...00_remove_studyright_id_from_studyplans.js | 2 + .../src/updater/updateMeta.js | 2 +- .../src/updater/updateStudents/attainments.js | 3 +- 89 files changed, 886 insertions(+), 986 deletions(-) create mode 100644 eslint.config.mjs delete mode 100644 services/frontend/.eslintrc.json delete mode 100644 services/frontend/src/components/LanguagePicker/index.jsx diff --git a/.eslintrc.json b/.eslintrc.json index 9f71cd6af6..52fe1f9f6e 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,120 +1,6 @@ +// ! If we don't have this file, running ESLint will fail because of the import/no-unused-modules rule +// ! See: https://github.com/import-js/eslint-plugin-import/issues/3079 +// ! When this issue is resolved, this file can be removed { - "env": { - "commonjs": true, - "es2021": true, - "node": true - }, - "parserOptions": { - "ecmaVersion": "latest", - "sourceType": "commonjs" - }, - "extends": [ - "eslint:recommended", - "airbnb", - "plugin:cypress/recommended", - "plugin:import/recommended", - "plugin:prettier/recommended" - ], - "overrides": [ - { - "files": ["**/*.ts"], - "env": { - "es2021": true, - "node": true - }, - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/recommended", - "airbnb-typescript", - "plugin:prettier/recommended" - ], - "parser": "@typescript-eslint/parser", - "parserOptions": { - "ecmaVersion": 2021, - "sourceType": "module", - "project": true - }, - "rules": { - "import/prefer-default-export": "off", - "@typescript-eslint/lines-between-class-members": "off", - "@typescript-eslint/no-explicit-any": "off", - "@typescript-eslint/no-shadow": "off", - "@typescript-eslint/return-await": "off", - "@typescript-eslint/no-unnecessary-type-assertion": "error" - } - }, - { - "files": ["services/backend/src/rapodiff/**/*"], - "rules": { - "no-console": "off" - } - } - ], - "rules": { - "camelcase": "off", - "consistent-return": "off", - "cypress/no-assigning-return-values": "off", - "cypress/unsafe-to-chain-command": "off", - "default-param-last": "off", - "id-denylist": ["error", "c", "d", "e", "err", "t"], - "import/extensions": ["error", "never"], - "import/order": [ - "error", - { - "alphabetize": { "order": "asc", "caseInsensitive": true }, - "groups": [["builtin", "external"], ["internal"], ["parent"], ["sibling", "index"]], - "pathGroups": [ - { - "pattern": "../../../**", - "group": "internal", - "position": "before" - }, - { - "pattern": "../../**", - "group": "internal", - "position": "after" - }, - { - "pattern": "../**", - "group": "parent", - "position": "before" - }, - { - "pattern": "./**", - "group": "sibling", - "position": "before" - } - ], - "pathGroupsExcludedImportTypes": ["builtin", "external"] - } - ], - "no-async-promise-executor": "off", - "no-await-in-loop": "off", - "no-console": "error", - "no-continue": "off", - "no-param-reassign": "off", - "no-plusplus": "off", - "no-promise-executor-return": "off", - "no-restricted-syntax": [ - "error", - { - "selector": "ForInStatement", - "message": "for..in loops iterate over the entire prototype chain, which is virtually never what you want. Use Object.{keys,values,entries}, and iterate over the resulting array." - }, - "LabeledStatement", - "WithStatement" - ], - "no-return-await": "off", - "no-shadow": "off", - "prettier/prettier": "error", - "quotes": ["error", "single", { "avoidEscape": true }] - }, - "settings": { - "import/resolver": { - "node": { - "extensions": [".js", ".jsx", ".ts", ".tsx"] - } - } - }, - "ignorePatterns": ["build/", "dist/", "instrumented/", "node_modules/", "**/*migrations*/**"] + "ignorePatterns": ["**/node_modules/", "**/dist/", "**/build/"] } diff --git a/.github/actions/lint/action.yaml b/.github/actions/lint/action.yaml index 5f3789b132..d0d87e2d54 100644 --- a/.github/actions/lint/action.yaml +++ b/.github/actions/lint/action.yaml @@ -18,4 +18,4 @@ runs: run: npm run stylelint "services/frontend/src/**/*.css" - name: 'Run ESLint for JS and TS files' shell: bash - run: npm run eslint -- --ext .js,.jsx,.ts,.tsx services --report-unused-disable-directives + run: npm run eslint -- services diff --git a/.github/workflows/updater.yaml b/.github/workflows/updater.yaml index efb2375996..b717ff1324 100644 --- a/.github/workflows/updater.yaml +++ b/.github/workflows/updater.yaml @@ -27,7 +27,7 @@ jobs: - name: 'Install dependencies' run: npm ci && cd updater/sis-updater-scheduler && npm ci && cd ../sis-updater-worker && npm ci - name: 'Run linter' - run: npm run eslint updater -- --report-unused-disable-directives + run: npm run eslint -- updater build_worker: name: 'Build Updater worker' diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000000..94f78e8ba1 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,175 @@ +import pluginJs from '@eslint/js' +import globals from 'globals' +import pluginCypress from 'eslint-plugin-cypress/flat' +import pluginImport from 'eslint-plugin-import' +import pluginPrettierRecommended from 'eslint-plugin-prettier/recommended' +import pluginReact from 'eslint-plugin-react' +import pluginReactHooks from 'eslint-plugin-react-hooks' +import tsEslint from 'typescript-eslint' + +/** @type {import('eslint').Linter.Config[]} */ +export default [ + { + files: ['**/*.{js,ts,jsx,tsx}'], + }, + { + ignores: ['eslint.config.mjs', '**/build/', '**/dist/', '**/node_modules/'], + }, + { + languageOptions: { + globals: { + ...globals.browser, + ...globals.node, + }, + }, + }, + { + linterOptions: { + reportUnusedDisableDirectives: 'error', + }, + }, + { + files: ['**/*.{ts,tsx}'], + languageOptions: { + parserOptions: { + project: [ + 'services/frontend/tsconfig.json', + 'services/frontend/tsconfig.node.json', + 'services/backend/tsconfig.json', + 'services/shared/tsconfig.json', + ], + }, + }, + }, + pluginJs.configs.recommended, + ...tsEslint.configs.recommendedTypeChecked, + ...tsEslint.configs.stylisticTypeChecked, + pluginCypress.configs.recommended, + pluginReact.configs.flat.recommended, + pluginReact.configs.flat['jsx-runtime'], + pluginImport.flatConfigs.recommended, + pluginImport.flatConfigs.typescript, + pluginPrettierRecommended, // This must be the last plugin so it can override other configs + { + plugins: { + 'react-hooks': pluginReactHooks, + }, + }, + { + rules: { + camelcase: 'off', // TODO: Enable this rule (at least for frontend) + 'class-methods-use-this': 'error', + 'consistent-return': 'error', + 'id-denylist': ['error', 'c', 'd', 'e', 'err', 't'], + 'import/no-commonjs': 'error', + 'import/no-default-export': 'error', + 'import/no-extraneous-dependencies': ['error', { devDependencies: false }], + 'import/no-unused-modules': ['error', { missingExports: true, unusedExports: true }], + 'import/order': [ + 'error', + { + alphabetize: { order: 'asc', caseInsensitive: true }, + groups: [['builtin', 'external'], ['internal'], ['parent'], ['sibling', 'index']], + }, + ], + 'no-alert': 'error', + 'no-async-promise-executor': 'error', + 'no-await-in-loop': 'error', + 'no-console': 'error', + 'no-implied-eval': 'error', + 'no-param-reassign': ['error', { props: false }], + 'no-promise-executor-return': 'error', + 'no-return-assign': 'error', + 'no-return-await': 'error', + 'object-shorthand': ['error', 'always'], + 'prefer-destructuring': ['error', { VariableDeclarator: { object: true } }], + quotes: ['error', 'single', { avoidEscape: true, allowTemplateLiterals: false }], + 'react/display-name': 'off', // TODO: Delete this override + 'react/function-component-definition': [ + 'error', + { namedComponents: 'arrow-function', unnamedComponents: 'arrow-function' }, + ], + 'react/jsx-filename-extension': ['error', { allow: 'as-needed', extensions: ['.jsx', '.tsx'] }], + 'react/jsx-sort-props': ['error', { reservedFirst: false }], + 'react/no-array-index-key': 'error', + 'react/no-this-in-sfc': 'error', + 'react/no-unescaped-entities': 'off', + 'react/no-unknown-property': 'off', // TODO: Delete this override + 'react/prefer-stateless-function': 'error', + 'react/prop-types': 'off', + ...pluginReactHooks.configs.recommended.rules, + 'react-hooks/exhaustive-deps': 'off', // TODO: Delete this override + '@typescript-eslint/array-type': 'off', + '@typescript-eslint/consistent-indexed-object-style': 'off', + '@typescript-eslint/consistent-type-definitions': 'off', + '@typescript-eslint/no-empty-function': 'off', + '@typescript-eslint/no-empty-object-type': ['error', { allowInterfaces: 'with-single-extends' }], + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-misused-promises': 'off', // Most of these errors come from Express route handlers that are handled correctly by express-async-errors + '@typescript-eslint/no-unsafe-argument': 'off', + '@typescript-eslint/no-unsafe-assignment': 'off', + '@typescript-eslint/no-unsafe-call': 'off', + '@typescript-eslint/no-unsafe-member-access': 'off', + '@typescript-eslint/no-unsafe-return': 'off', + '@typescript-eslint/no-unused-vars': [ + 'error', + { argsIgnorePattern: '^_', caughtErrors: 'none', ignoreRestSiblings: true, varsIgnorePattern: '^_' }, + ], + '@typescript-eslint/restrict-template-expressions': 'off', + }, + }, + { + files: ['**/*.{js,jsx}'], + rules: { + ...tsEslint.configs.disableTypeChecked.rules, + 'dot-notation': 'error', + }, + }, + { + files: ['services/backend/src/rapodiff/**/*'], + rules: { + 'no-console': 'off', + }, + }, + { + files: ['cypress/**/*.js', 'services/backend/**/*.js', 'updater/**/*.js'], + languageOptions: { + sourceType: 'commonjs', + }, + rules: { + '@typescript-eslint/no-require-imports': 'off', + 'import/no-commonjs': 'off', + }, + }, + { + files: ['services/backend/**/*.{js,ts}', 'updater/**/*.js'], + rules: { + // TODO: Most of these overrides should probably be removed + 'consistent-return': 'off', + 'import/no-default-export': 'off', + 'import/no-unused-modules': 'off', + 'no-await-in-loop': 'off', + 'no-param-reassign': 'off', + 'no-promise-executor-return': 'off', + 'no-return-await': 'off', + }, + }, + { + settings: { + 'import/internal-regex': '^@/shared/', + 'import/resolver': { + typescript: { + project: [ + 'services/frontend/tsconfig.json', + 'services/frontend/tsconfig.node.json', + 'services/backend/tsconfig.json', + 'services/shared/tsconfig.json', + ], + }, + }, + react: { + version: '18.3', + }, + }, + }, +] diff --git a/package-lock.json b/package-lock.json index 49ae51a7ac..ac5cb2adda 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,37 +12,26 @@ }, "devDependencies": { "@cypress/code-coverage": "^3.12.39", + "@eslint/js": "^9.14.0", "@istanbuljs/schema": "^0.1.3", - "@typescript-eslint/eslint-plugin": "^7.16.1", - "@typescript-eslint/parser": "^7.16.1", "cypress": "^13.2.0", - "eslint": "^8.56.0", - "eslint-config-airbnb": "^19.0.4", - "eslint-config-airbnb-typescript": "^18.0.0", + "eslint": "^9.14.0", "eslint-config-prettier": "^9.1.0", - "eslint-import-resolver-custom-alias": "^1.3.2", - "eslint-plugin-cypress": "^3.0.0", - "eslint-plugin-import": "^2.29.1", - "eslint-plugin-jsx-a11y": "^6.8.0", + "eslint-import-resolver-typescript": "^3.6.3", + "eslint-plugin-cypress": "^4.1.0", + "eslint-plugin-import": "^2.31.0", "eslint-plugin-prettier": "^5.2.1", - "eslint-plugin-react": "^7.33.2", - "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react": "^7.37.2", + "eslint-plugin-react-hooks": "^5.0.0", + "globals": "^15.12.0", "husky": "^9.0.0", "lint-staged": "^15.0.0", "node-actionlint": "^1.2.2", "nyc": "^17.0.0", "prettier": "3.3.3", "stylelint": "^16.2.1", - "stylelint-config-standard": "^36.0.0" - } - }, - "node_modules/@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" + "stylelint-config-standard": "^36.0.0", + "typescript-eslint": "^8.13.0" } }, "node_modules/@ampproject/remapping": { @@ -2217,39 +2206,83 @@ } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", + "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", "dev": true, + "license": "MIT", "dependencies": { - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.3" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, + "funding": { + "url": "https://opencollective.com/eslint" + }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@eslint-community/regexpp": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", - "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", "dev": true, + "license": "MIT", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, + "node_modules/@eslint/config-array": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.18.0.tgz", + "integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.4", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.7.0.tgz", + "integrity": "sha512-xp5Jirz5DyPYlPiKat8jaq0EmYvDXKKpzTbxXMpT9eqlRJkRKIz9AGMdlvYjih+im+QlhWrpvVjl8IPC/lHlUw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", + "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", "dev": true, + "license": "MIT", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", + "espree": "^10.0.1", + "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", @@ -2257,36 +2290,94 @@ "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@eslint/js": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", - "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "version": "9.14.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.14.0.tgz", + "integrity": "sha512-pFoEtFWCPyDOl+C6Ift+wC7Ro89otjigCf5vcuWqWgqNSQbRrpjSvdeE6ofLz4dHmyxD5f7gIdGT4+p36L6Twg==", "dev": true, "license": "MIT", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", - "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", - "deprecated": "Use @eslint/config-array instead", + "node_modules/@eslint/object-schema": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", + "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.2.tgz", + "integrity": "sha512-CXtq5nR4Su+2I47WPOlWud98Y5Lv8Kyxp2ukhgFx/eW6Blm18VXJO5WuQylPugRo8nbluoi6GvvxBLqHcvqUUw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@humanwhocodes/object-schema": "^2.0.3", - "debug": "^4.3.1", - "minimatch": "^3.0.5" + "levn": "^0.4.1" }, "engines": { - "node": ">=10.10.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, "node_modules/@humanwhocodes/module-importer": { @@ -2294,6 +2385,7 @@ "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=12.22" }, @@ -2302,13 +2394,19 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "deprecated": "Use @eslint/object-schema instead", + "node_modules/@humanwhocodes/retry": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.1.tgz", + "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==", "dev": true, - "license": "BSD-3-Clause" + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", @@ -2460,11 +2558,22 @@ "node": ">= 8" } }, + "node_modules/@nolyfill/is-core-module": { + "version": "1.0.39", + "resolved": "https://registry.npmjs.org/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz", + "integrity": "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.4.0" + } + }, "node_modules/@pkgr/core": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", "dev": true, + "license": "MIT", "engines": { "node": "^12.20.0 || ^14.18.0 || >=16.0.0" }, @@ -2479,37 +2588,25 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/eslint": { - "version": "8.56.10", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz", - "integrity": "sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", "dev": true, - "peer": true + "license": "MIT" }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true, - "peer": true + "dev": true }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/node": { "version": "18.19.17", @@ -2543,32 +2640,32 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz", - "integrity": "sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==", + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.13.0.tgz", + "integrity": "sha512-nQtBLiZYMUPkclSeC3id+x4uVd1SGtHuElTxL++SfP47jR0zfkZBJHc+gL4qPsgTuypz0k8Y2GheaDYn6Gy3rg==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.18.0", - "@typescript-eslint/type-utils": "7.18.0", - "@typescript-eslint/utils": "7.18.0", - "@typescript-eslint/visitor-keys": "7.18.0", + "@typescript-eslint/scope-manager": "8.13.0", + "@typescript-eslint/type-utils": "8.13.0", + "@typescript-eslint/utils": "8.13.0", + "@typescript-eslint/visitor-keys": "8.13.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "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" }, "peerDependenciesMeta": { "typescript": { @@ -2577,27 +2674,27 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.18.0.tgz", - "integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==", + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.13.0.tgz", + "integrity": "sha512-w0xp+xGg8u/nONcGw1UXAr6cjCPU1w0XVyBs6Zqaj5eLmxkKQAByTdV/uGgNN5tVvN/kKpoQlP2cL7R+ajZZIQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/scope-manager": "7.18.0", - "@typescript-eslint/types": "7.18.0", - "@typescript-eslint/typescript-estree": "7.18.0", - "@typescript-eslint/visitor-keys": "7.18.0", + "@typescript-eslint/scope-manager": "8.13.0", + "@typescript-eslint/types": "8.13.0", + "@typescript-eslint/typescript-estree": "8.13.0", + "@typescript-eslint/visitor-keys": "8.13.0", "debug": "^4.3.4" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.56.0" + "eslint": "^8.57.0 || ^9.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -2606,17 +2703,17 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", - "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==", + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.13.0.tgz", + "integrity": "sha512-XsGWww0odcUT0gJoBZ1DeulY1+jkaHUciUq4jKNv4cpInbvvrtDoyBH9rE/n2V29wQJPk8iCH1wipra9BhmiMA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.18.0", - "@typescript-eslint/visitor-keys": "7.18.0" + "@typescript-eslint/types": "8.13.0", + "@typescript-eslint/visitor-keys": "8.13.0" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -2624,27 +2721,24 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz", - "integrity": "sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==", + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.13.0.tgz", + "integrity": "sha512-Rqnn6xXTR316fP4D2pohZenJnp+NwQ1mo7/JM+J1LWZENSLkJI8ID8QNtlvFeb0HnFSK94D6q0cnMX6SbE5/vA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "7.18.0", - "@typescript-eslint/utils": "7.18.0", + "@typescript-eslint/typescript-estree": "8.13.0", + "@typescript-eslint/utils": "8.13.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, - "peerDependencies": { - "eslint": "^8.56.0" - }, "peerDependenciesMeta": { "typescript": { "optional": true @@ -2652,13 +2746,13 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", - "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.13.0.tgz", + "integrity": "sha512-4cyFErJetFLckcThRUFdReWJjVsPCqyBlJTi6IDEpc1GWCIIZRFxVppjWLIMcQhNGhdWJJRYFHpHoDWvMlDzng==", "dev": true, "license": "MIT", "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -2666,23 +2760,23 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz", - "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==", + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.13.0.tgz", + "integrity": "sha512-v7SCIGmVsRK2Cy/LTLGN22uea6SaUIlpBcO/gnMGT/7zPtxp90bphcGf4fyrCQl3ZtiBKqVTG32hb668oIYy1g==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "7.18.0", - "@typescript-eslint/visitor-keys": "7.18.0", + "@typescript-eslint/types": "8.13.0", + "@typescript-eslint/visitor-keys": "8.13.0", "debug": "^4.3.4", - "globby": "^11.1.0", + "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -2734,51 +2828,58 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz", - "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==", + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.13.0.tgz", + "integrity": "sha512-A1EeYOND6Uv250nybnLZapeXpYMl8tkzYUxqmoKAWnI4sei3ihf2XdZVd+vVOmHGcp3t+P7yRrNsyyiXTvShFQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.18.0", - "@typescript-eslint/types": "7.18.0", - "@typescript-eslint/typescript-estree": "7.18.0" + "@typescript-eslint/scope-manager": "8.13.0", + "@typescript-eslint/types": "8.13.0", + "@typescript-eslint/typescript-estree": "8.13.0" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.56.0" + "eslint": "^8.57.0 || ^9.0.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz", - "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==", + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.13.0.tgz", + "integrity": "sha512-7N/+lztJqH4Mrf0lb10R/CbI1EaAMMGyF5y0oJvFoAhafwgiRA7TXyd8TFn8FC8k5y2dTsYogg238qavRGNnlw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.18.0", + "@typescript-eslint/types": "8.13.0", "eslint-visitor-keys": "^3.4.3" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } }, "node_modules/@webassemblyjs/ast": { "version": "1.12.1", @@ -2956,10 +3057,11 @@ "peer": true }, "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", "dev": true, + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -2983,6 +3085,7 @@ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, + "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } @@ -3157,21 +3260,12 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, - "node_modules/aria-query": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", - "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">= 0.4" - } - }, "node_modules/array-buffer-byte-length": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.5", "is-array-buffer": "^3.0.4" @@ -3260,6 +3354,7 @@ "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -3278,6 +3373,7 @@ "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -3313,6 +3409,7 @@ "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", "dev": true, + "license": "MIT", "dependencies": { "array-buffer-byte-length": "^1.0.1", "call-bind": "^1.0.5", @@ -3350,12 +3447,6 @@ "node": ">=0.8" } }, - "node_modules/ast-types-flow": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", - "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", - "dev": true - }, "node_modules/astral-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", @@ -3420,26 +3511,6 @@ "dev": true, "license": "MIT" }, - "node_modules/axe-core": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.10.0.tgz", - "integrity": "sha512-Mr2ZakwQ7XUAjp7pAwQWRhhK8mQQ6JAaNWSjmjxil0R8BPioMtQsTLOolGYkji1rcL++3dCqZA3zWqpT+9Ew6g==", - "dev": true, - "license": "MPL-2.0", - "engines": { - "node": ">=4" - } - }, - "node_modules/axobject-query": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", - "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">= 0.4" - } - }, "node_modules/babel-loader": { "version": "9.1.3", "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.3.tgz", @@ -4091,12 +4162,6 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, - "node_modules/confusing-browser-globals": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz", - "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==", - "dev": true - }, "node_modules/convert-source-map": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", @@ -4364,12 +4429,6 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/damerau-levenshtein": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", - "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", - "dev": true - }, "node_modules/dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", @@ -4475,7 +4534,8 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/default-require-extensions": { "version": "3.0.1", @@ -4523,6 +4583,7 @@ "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", "dev": true, + "license": "MIT", "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", @@ -4558,15 +4619,16 @@ } }, "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, + "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" }, "engines": { - "node": ">=6.0.0" + "node": ">=0.10.0" } }, "node_modules/ecc-jsbn": { @@ -4586,12 +4648,6 @@ "integrity": "sha512-ubp5+Ev/VV8KuRoWnfP2QF2Bg+O2ZFdb49DiiNbz2VmgkIqrnyYaqIOqj8A6K/3p1xV0QcU5hBQ1+BmB6ot1OA==", "dev": true }, - "node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true - }, "node_modules/end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -4607,7 +4663,6 @@ "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -4742,9 +4797,9 @@ } }, "node_modules/es-iterator-helpers": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.1.0.tgz", - "integrity": "sha512-/SurEfycdyssORP/E+bj4sEu1CWw4EmLDsHynHwSXQ7utgbrMRWW195pTrCjFgFCddf/UkYm3oqKPRq5i8bJbw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.0.tgz", + "integrity": "sha512-tpxqxncxnpw3c93u8n3VOzACmRFoVmWJqbWXvX/JfKbkhBw1oslgPrUfeSt2psuqyEJFD6N/9lg5i7bsKpoq+Q==", "dev": true, "license": "MIT", "dependencies": { @@ -4756,6 +4811,7 @@ "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", "globalthis": "^1.0.4", + "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2", "has-proto": "^1.0.3", "has-symbols": "^1.0.3", @@ -4807,6 +4863,7 @@ "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", "dev": true, + "license": "MIT", "dependencies": { "hasown": "^2.0.0" } @@ -4816,6 +4873,7 @@ "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", "dev": true, + "license": "MIT", "dependencies": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", @@ -4853,113 +4911,64 @@ } }, "node_modules/eslint": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", - "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "version": "9.14.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.14.0.tgz", + "integrity": "sha512-c2FHsVBr87lnUtjP4Yhvk4yEhKrQavGafRA/Se1ouse8PfbfC/Qh9Mxa00yWsZRlqeUB9raXip0aiiUZkgnr9g==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.1", - "@humanwhocodes/config-array": "^0.13.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.18.0", + "@eslint/core": "^0.7.0", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "9.14.0", + "@eslint/plugin-kit": "^0.2.0", + "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", + "@humanwhocodes/retry": "^0.4.0", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", - "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", + "eslint-scope": "^8.2.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "esquery": "^1.5.0", "esutils": "^2.0.2", "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.19.0", - "graphemer": "^1.4.0", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "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.3", - "strip-ansi": "^6.0.1", "text-table": "^0.2.0" }, "bin": { "eslint": "bin/eslint.js" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-config-airbnb": { - "version": "19.0.4", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-19.0.4.tgz", - "integrity": "sha512-T75QYQVQX57jiNgpF9r1KegMICE94VYwoFQyMGhrvc+lB8YF2E/M/PYDaQe1AJcWaEgqLE+ErXV1Og/+6Vyzew==", - "dev": true, - "dependencies": { - "eslint-config-airbnb-base": "^15.0.0", - "object.assign": "^4.1.2", - "object.entries": "^1.1.5" - }, - "engines": { - "node": "^10.12.0 || ^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^7.32.0 || ^8.2.0", - "eslint-plugin-import": "^2.25.3", - "eslint-plugin-jsx-a11y": "^6.5.1", - "eslint-plugin-react": "^7.28.0", - "eslint-plugin-react-hooks": "^4.3.0" - } - }, - "node_modules/eslint-config-airbnb-base": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz", - "integrity": "sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==", - "dev": true, - "dependencies": { - "confusing-browser-globals": "^1.0.10", - "object.assign": "^4.1.2", - "object.entries": "^1.1.5", - "semver": "^6.3.0" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" + "url": "https://eslint.org/donate" }, "peerDependencies": { - "eslint": "^7.32.0 || ^8.2.0", - "eslint-plugin-import": "^2.25.2" - } - }, - "node_modules/eslint-config-airbnb-typescript": { - "version": "18.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb-typescript/-/eslint-config-airbnb-typescript-18.0.0.tgz", - "integrity": "sha512-oc+Lxzgzsu8FQyFVa4QFaVKiitTYiiW3frB9KYW5OWdPrqFc7FzxgB20hP4cHMlr+MBzGcLl3jnCOVOydL9mIg==", - "dev": true, - "dependencies": { - "eslint-config-airbnb-base": "^15.0.0" + "jiti": "*" }, - "peerDependencies": { - "@typescript-eslint/eslint-plugin": "^7.0.0", - "@typescript-eslint/parser": "^7.0.0", - "eslint": "^8.56.0" + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, "node_modules/eslint-config-prettier": { @@ -4967,6 +4976,7 @@ "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", "dev": true, + "license": "MIT", "bin": { "eslint-config-prettier": "bin/cli.js" }, @@ -4974,36 +4984,12 @@ "eslint": ">=7.0.0" } }, - "node_modules/eslint-import-resolver-custom-alias": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-custom-alias/-/eslint-import-resolver-custom-alias-1.3.2.tgz", - "integrity": "sha512-wBPcZA2k6/IXaT8FsLMyiyVSG6WVEuaYIAbeKLXeGwr523BmeB9lKAAoLJWSqp3txsnU4gpkgD2x1q6K8k0uDQ==", - "dev": true, - "dependencies": { - "glob-parent": "^6.0.2", - "resolve": "^1.22.2" - }, - "peerDependencies": { - "eslint-plugin-import": ">=2.2.0" - } - }, - "node_modules/eslint-import-resolver-custom-alias/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, "node_modules/eslint-import-resolver-node": { "version": "0.3.9", "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", "dev": true, + "license": "MIT", "dependencies": { "debug": "^3.2.7", "is-core-module": "^2.13.0", @@ -5015,10 +5001,47 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, + "license": "MIT", "dependencies": { "ms": "^2.1.1" } }, + "node_modules/eslint-import-resolver-typescript": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.3.tgz", + "integrity": "sha512-ud9aw4szY9cCT1EWWdGv1L1XR6hh2PaRWif0j2QjQ0pgTY/69iw+W0Z4qZv5wHahOl8isEr+k/JnyAqNQkLkIA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@nolyfill/is-core-module": "1.0.39", + "debug": "^4.3.5", + "enhanced-resolve": "^5.15.0", + "eslint-module-utils": "^2.8.1", + "fast-glob": "^3.3.2", + "get-tsconfig": "^4.7.5", + "is-bun-module": "^1.0.2", + "is-glob": "^4.0.3" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts/projects/eslint-import-resolver-ts" + }, + "peerDependencies": { + "eslint": "*", + "eslint-plugin-import": "*", + "eslint-plugin-import-x": "*" + }, + "peerDependenciesMeta": { + "eslint-plugin-import": { + "optional": true + }, + "eslint-plugin-import-x": { + "optional": true + } + } + }, "node_modules/eslint-module-utils": { "version": "2.12.0", "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz", @@ -5042,21 +5065,22 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, + "license": "MIT", "dependencies": { "ms": "^2.1.1" } }, "node_modules/eslint-plugin-cypress": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-cypress/-/eslint-plugin-cypress-3.6.0.tgz", - "integrity": "sha512-7IAMcBbTVu5LpWeZRn5a9mQ30y4hKp3AfTz+6nSD/x/7YyLMoBI6X7XjDLYI6zFvuy4Q4QVGl563AGEXGW/aSA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-cypress/-/eslint-plugin-cypress-4.1.0.tgz", + "integrity": "sha512-JhqkMY02mw74USwK9OFhectx3YSj6Co1NgWBxlGdKvlqiAp9vdEuQqt33DKGQFvvGS/NWtduuhWXWNnU29xDSg==", "dev": true, "license": "MIT", "dependencies": { - "globals": "^13.20.0" + "globals": "^15.11.0" }, "peerDependencies": { - "eslint": ">=7" + "eslint": ">=9" } }, "node_modules/eslint-plugin-import": { @@ -5103,54 +5127,12 @@ "ms": "^2.1.1" } }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-jsx-a11y": { - "version": "6.10.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz", - "integrity": "sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "aria-query": "^5.3.2", - "array-includes": "^3.1.8", - "array.prototype.flatmap": "^1.3.2", - "ast-types-flow": "^0.0.8", - "axe-core": "^4.10.0", - "axobject-query": "^4.1.0", - "damerau-levenshtein": "^1.0.8", - "emoji-regex": "^9.2.2", - "hasown": "^2.0.2", - "jsx-ast-utils": "^3.3.5", - "language-tags": "^1.0.9", - "minimatch": "^3.1.2", - "object.fromentries": "^2.0.8", - "safe-regex-test": "^1.0.3", - "string.prototype.includes": "^2.0.1" - }, - "engines": { - "node": ">=4.0" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9" - } - }, "node_modules/eslint-plugin-prettier": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.1.tgz", "integrity": "sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw==", "dev": true, + "license": "MIT", "dependencies": { "prettier-linter-helpers": "^1.0.0", "synckit": "^0.9.1" @@ -5210,29 +5192,16 @@ } }, "node_modules/eslint-plugin-react-hooks": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz", - "integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.0.0.tgz", + "integrity": "sha512-hIOwI+5hYGpJEc4uPRmz2ulCjAGD/N13Lukkh8cLV0i2IRk/bdZDYjgLVHj+U9Z704kLIdIO6iueGvxNur0sgw==", "dev": true, "license": "MIT", "engines": { "node": ">=10" }, "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" - } - }, - "node_modules/eslint-plugin-react/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" } }, "node_modules/eslint-plugin-react/node_modules/resolve": { @@ -5254,28 +5223,30 @@ } }, "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz", + "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", "dev": true, + "license": "Apache-2.0", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -5449,17 +5420,18 @@ } }, "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", + "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "acorn": "^8.9.0", + "acorn": "^8.14.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" + "eslint-visitor-keys": "^4.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -5479,10 +5451,11 @@ } }, "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" }, @@ -5622,10 +5595,11 @@ "dev": true }, "node_modules/fast-diff": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", - "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", - "dev": true + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true, + "license": "Apache-2.0" }, "node_modules/fast-glob": { "version": "3.3.2", @@ -5653,7 +5627,8 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fastest-levenshtein": { "version": "1.0.16", @@ -5698,15 +5673,16 @@ } }, "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, + "license": "MIT", "dependencies": { - "flat-cache": "^3.0.4" + "flat-cache": "^4.0.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16.0.0" } }, "node_modules/fill-range": { @@ -5753,16 +5729,17 @@ } }, "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, + "license": "MIT", "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" + "flatted": "^3.2.9", + "keyv": "^4.5.4" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16" } }, "node_modules/flatted": { @@ -5777,6 +5754,7 @@ "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", "dev": true, + "license": "MIT", "dependencies": { "is-callable": "^1.1.3" } @@ -5875,6 +5853,7 @@ "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -5893,6 +5872,7 @@ "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -5976,6 +5956,7 @@ "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.5", "es-errors": "^1.3.0", @@ -5988,6 +5969,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-tsconfig": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.8.1.tgz", + "integrity": "sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, "node_modules/getos": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/getos/-/getos-3.2.1.tgz", @@ -6106,27 +6100,13 @@ } }, "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globals/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "version": "15.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.12.0.tgz", + "integrity": "sha512-1+gLErljJFhbOVyaetcwJiJ4+eLe45S2E7P5UiZ9xGfeq3ATQf5DOv9G7MH3gGbKQLkzmNh2DxfZwLdw+j6oTQ==", "dev": true, + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -6197,13 +6177,15 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/has-bigints": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -6259,6 +6241,7 @@ "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dev": true, + "license": "MIT", "dependencies": { "has-symbols": "^1.0.3" }, @@ -6459,6 +6442,7 @@ "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", "dev": true, + "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "hasown": "^2.0.0", @@ -6473,6 +6457,7 @@ "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.2.1" @@ -6511,6 +6496,7 @@ "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", "dev": true, + "license": "MIT", "dependencies": { "has-bigints": "^1.0.1" }, @@ -6523,6 +6509,7 @@ "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -6534,11 +6521,35 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-bun-module": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-1.2.1.tgz", + "integrity": "sha512-AmidtEM6D6NmUiLOvvU7+IePxjEjOzra2h0pSrsfSAcXwl/83zLLXDByafUJy9k/rKK0pvXMLdwKwGHlX2Ke6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.6.3" + } + }, + "node_modules/is-bun-module/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/is-callable": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -6595,6 +6606,7 @@ "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", "dev": true, + "license": "MIT", "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -6721,6 +6733,7 @@ "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", "dev": true, + "license": "MIT", "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -6754,6 +6767,7 @@ "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -6811,6 +6825,7 @@ "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", "dev": true, + "license": "MIT", "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -6826,6 +6841,7 @@ "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", "dev": true, + "license": "MIT", "dependencies": { "has-symbols": "^1.0.2" }, @@ -6888,6 +6904,7 @@ "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2" }, @@ -6925,7 +6942,8 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/isexe": { "version": "2.0.0", @@ -7218,7 +7236,8 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-stringify-safe": { "version": "5.0.1", @@ -7232,6 +7251,7 @@ "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, + "license": "MIT", "dependencies": { "minimist": "^1.2.0" }, @@ -7272,6 +7292,7 @@ "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", "dev": true, + "license": "MIT", "dependencies": { "array-includes": "^3.1.6", "array.prototype.flat": "^1.3.1", @@ -7307,24 +7328,6 @@ "dev": true, "license": "MIT" }, - "node_modules/language-subtag-registry": { - "version": "0.3.22", - "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", - "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==", - "dev": true - }, - "node_modules/language-tags": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", - "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", - "dev": true, - "dependencies": { - "language-subtag-registry": "^0.3.20" - }, - "engines": { - "node": ">=0.10" - } - }, "node_modules/lazy-ass": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz", @@ -7339,6 +7342,7 @@ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -7900,7 +7904,8 @@ "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash.once": { "version": "4.1.1", @@ -8087,6 +8092,7 @@ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", "dev": true, + "license": "MIT", "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, @@ -8267,7 +8273,8 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/neo-async": { "version": "2.6.2", @@ -8529,6 +8536,7 @@ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -8547,6 +8555,7 @@ "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" } @@ -8556,6 +8565,7 @@ "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.5", "define-properties": "^1.2.1", @@ -8661,17 +8671,18 @@ } }, "node_modules/optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, + "license": "MIT", "dependencies": { - "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" }, "engines": { "node": ">= 0.8.0" @@ -8984,6 +8995,7 @@ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8.0" } @@ -9008,6 +9020,7 @@ "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", "dev": true, + "license": "MIT", "dependencies": { "fast-diff": "^1.1.2" }, @@ -9053,6 +9066,7 @@ "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", "dev": true, + "license": "MIT", "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", @@ -9148,7 +9162,8 @@ "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/reflect.getprototypeof": { "version": "1.0.6", @@ -9210,15 +9225,16 @@ } }, "node_modules/regexp.prototype.flags": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", - "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.3.tgz", + "integrity": "sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.6", + "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-errors": "^1.3.0", - "set-function-name": "^2.0.1" + "set-function-name": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -9346,6 +9362,16 @@ "node": ">=4" } }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, "node_modules/restore-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", @@ -9467,6 +9493,7 @@ "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.6", "es-errors": "^1.3.0", @@ -9812,21 +9839,6 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, - "node_modules/string.prototype.includes": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz", - "integrity": "sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.3" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/string.prototype.matchall": { "version": "4.0.11", "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", @@ -9934,6 +9946,7 @@ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -9952,6 +9965,7 @@ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -10194,10 +10208,11 @@ "dev": true }, "node_modules/synckit": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.1.tgz", - "integrity": "sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A==", + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.2.tgz", + "integrity": "sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==", "dev": true, + "license": "MIT", "dependencies": { "@pkgr/core": "^0.1.0", "tslib": "^2.6.2" @@ -10304,7 +10319,6 @@ "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=6" } @@ -10407,7 +10421,8 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/throttleit": { "version": "1.0.0", @@ -10490,10 +10505,11 @@ } }, "node_modules/ts-api-utils": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", - "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.0.tgz", + "integrity": "sha512-032cPxaEKwM+GT3vA5JXNzIaizx388rhsSW79vGRNGXfRRAdEAn2mvk36PvK5HnOchyWZ7afLEXqYCvPCrzuzQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=16" }, @@ -10506,6 +10522,7 @@ "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", "dev": true, + "license": "MIT", "dependencies": { "@types/json5": "^0.0.29", "json5": "^1.0.2", @@ -10544,6 +10561,7 @@ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1" }, @@ -10663,11 +10681,36 @@ "node": ">=14.17" } }, + "node_modules/typescript-eslint": { + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.13.0.tgz", + "integrity": "sha512-vIMpDRJrQd70au2G8w34mPps0ezFSPMEX4pXkTzUkrNbRX+36ais2ksGWN0esZL+ZMaFJEneOBHzCgSqle7DHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.13.0", + "@typescript-eslint/parser": "8.13.0", + "@typescript-eslint/utils": "8.13.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/unbox-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "has-bigints": "^1.0.2", @@ -10961,6 +11004,7 @@ "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", "dev": true, + "license": "MIT", "dependencies": { "is-bigint": "^1.0.1", "is-boolean-object": "^1.1.0", @@ -11044,6 +11088,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -11194,6 +11248,7 @@ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, diff --git a/package.json b/package.json index 41b0de61e0..8e8c8c13fd 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "cypress:run": "cypress run --browser chrome", "instrument": "./scripts/instrument.sh", "eslint": "eslint", - "lint:all": "eslint --ext .js,.jsx,.ts,.tsx services/ updater/ --report-unused-disable-directives", + "lint:all": "eslint services/ updater/", "stylelint": "stylelint", "actionlint": "node-actionlint", "prettier": "prettier", @@ -39,28 +39,26 @@ "homepage": "https://github.com/UniversityOfHelsinkiCS/oodikone#readme", "devDependencies": { "@cypress/code-coverage": "^3.12.39", + "@eslint/js": "^9.14.0", "@istanbuljs/schema": "^0.1.3", - "@typescript-eslint/eslint-plugin": "^7.16.1", - "@typescript-eslint/parser": "^7.16.1", "cypress": "^13.2.0", - "eslint": "^8.56.0", - "eslint-config-airbnb": "^19.0.4", - "eslint-config-airbnb-typescript": "^18.0.0", + "eslint": "^9.14.0", "eslint-config-prettier": "^9.1.0", - "eslint-import-resolver-custom-alias": "^1.3.2", - "eslint-plugin-cypress": "^3.0.0", - "eslint-plugin-import": "^2.29.1", - "eslint-plugin-jsx-a11y": "^6.8.0", + "eslint-import-resolver-typescript": "^3.6.3", + "eslint-plugin-cypress": "^4.1.0", + "eslint-plugin-import": "^2.31.0", "eslint-plugin-prettier": "^5.2.1", - "eslint-plugin-react": "^7.33.2", - "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react": "^7.37.2", + "eslint-plugin-react-hooks": "^5.0.0", + "globals": "^15.12.0", "husky": "^9.0.0", "lint-staged": "^15.0.0", "node-actionlint": "^1.2.2", "nyc": "^17.0.0", "prettier": "3.3.3", "stylelint": "^16.2.1", - "stylelint-config-standard": "^36.0.0" + "stylelint-config-standard": "^36.0.0", + "typescript-eslint": "^8.13.0" }, "dependencies": { "lodash": "^4.17.21", diff --git a/services/backend/src/database/connection.ts b/services/backend/src/database/connection.ts index 622c380e8e..c5d2db621d 100644 --- a/services/backend/src/database/connection.ts +++ b/services/backend/src/database/connection.ts @@ -118,7 +118,7 @@ const sequelizeKone = new Sequelize(conf.DB_URL_KONE!, { ], }) -sequelizeKone.query(`SET SESSION search_path to ${conf.DB_SCHEMA_KONE}`) +void sequelizeKone.query(`SET SESSION search_path to ${conf.DB_SCHEMA_KONE}`) const sequelizeUser = new Sequelize(conf.DB_URL_USER!, { logging: false, diff --git a/services/backend/src/middleware/accessLogger.ts b/services/backend/src/middleware/accessLogger.ts index 99cd478c20..1615149f79 100644 --- a/services/backend/src/middleware/accessLogger.ts +++ b/services/backend/src/middleware/accessLogger.ts @@ -40,15 +40,15 @@ const accessLogger = morgan((tokens, req: Request, res: Response): undefined => const message = [ `${user.mockedBy ? '(mocking) ' : ''}${user.name}`, - `${(tokens['response-time'](req, res) || '0').split('.')[0]} ms`.padEnd(8, ' '), + `${(tokens['response-time'](req, res) ?? '0').split('.')[0]} ms`.padEnd(8, ' '), tokens.status(req, res), tokens.method(req, res), - decodeURIComponent(tokens.url(req, res) as string), + decodeURIComponent(tokens.url(req, res)!), ].join(' ') const fullStudyProgrammeRights = getFullStudyProgrammeRights(user.programmeRights) const iamBasedRights = user.programmeRights.filter(right => right.isIamBased) - const usingIamRights = iamBasedRights.some(right => (tokens.url(req, res) as string).includes(right.code)) + const usingIamRights = iamBasedRights.some(right => tokens.url(req, res)!.includes(right.code)) const onlyIamRights = !user.isAdmin && fullStudyProgrammeRights.length === 0 logger.info(message, { diff --git a/services/backend/src/middleware/auth.ts b/services/backend/src/middleware/auth.ts index 1cdaca29f3..aaa21c85a6 100644 --- a/services/backend/src/middleware/auth.ts +++ b/services/backend/src/middleware/auth.ts @@ -2,7 +2,7 @@ import { NextFunction, Request, Response } from 'express' import { Role } from '../types' -export const roles = (requiredRoles: Role[]) => async (req: Request, res: Response, next: NextFunction) => { +export const roles = (requiredRoles: Role[]) => (req: Request, res: Response, next: NextFunction) => { const { roles } = req.user if (requiredRoles.some(role => roles.includes(role)) || roles.includes('admin')) { return next() diff --git a/services/backend/src/middleware/currentUser.ts b/services/backend/src/middleware/currentUser.ts index af7aa38ccb..2dd5018777 100644 --- a/services/backend/src/middleware/currentUser.ts +++ b/services/backend/src/middleware/currentUser.ts @@ -73,8 +73,8 @@ const toskaUserMiddleware = async (req: Request, _res: Response, next: NextFunct ) } - const iamGroups = parseIamGroups(hygroupcn as string) - const { iamAccess = {}, specialGroup = {} } = await getOrganizationAccess(sisId as string, iamGroups) + const iamGroups = parseIamGroups(hygroupcn!) + const { iamAccess = {}, specialGroup = {} } = await getOrganizationAccess(sisId!, iamGroups) const iamRights = Object.keys(iamAccess) if (!hasRequiredIamGroup(iamGroups, iamRights)) { @@ -93,7 +93,7 @@ const toskaUserMiddleware = async (req: Request, _res: Response, next: NextFunct Sentry.setUser({ username: user.mockedBy ?? username! }) req.user = user - req.logoutUrl = logoutUrl as string + req.logoutUrl = logoutUrl! next() } diff --git a/services/backend/src/models/SISStudyRight.ts b/services/backend/src/models/SISStudyRight.ts index 2b45a44f76..78b2e2e400 100644 --- a/services/backend/src/models/SISStudyRight.ts +++ b/services/backend/src/models/SISStudyRight.ts @@ -1,4 +1,3 @@ -/* eslint-disable import/no-cycle */ import { InferAttributes } from 'sequelize' import { BelongsTo, diff --git a/services/backend/src/models/SISStudyRightElement.ts b/services/backend/src/models/SISStudyRightElement.ts index d64d189167..4af7f9b718 100644 --- a/services/backend/src/models/SISStudyRightElement.ts +++ b/services/backend/src/models/SISStudyRightElement.ts @@ -1,4 +1,3 @@ -/* eslint-disable import/no-cycle */ import { InferAttributes } from 'sequelize' import { BelongsTo, diff --git a/services/backend/src/models/course.ts b/services/backend/src/models/course.ts index ff50694edb..65d0a9d809 100644 --- a/services/backend/src/models/course.ts +++ b/services/backend/src/models/course.ts @@ -1,4 +1,3 @@ -/* eslint-disable import/no-cycle */ import { InferAttributes } from 'sequelize' import { BelongsTo, diff --git a/services/backend/src/models/courseProvider.ts b/services/backend/src/models/courseProvider.ts index e6363b080a..00f68b9b4e 100644 --- a/services/backend/src/models/courseProvider.ts +++ b/services/backend/src/models/courseProvider.ts @@ -1,4 +1,3 @@ -/* eslint-disable import/no-cycle */ import { InferAttributes } from 'sequelize' import { Column, CreatedAt, DataType, ForeignKey, Model, Table, UpdatedAt } from 'sequelize-typescript' diff --git a/services/backend/src/models/courseType.ts b/services/backend/src/models/courseType.ts index 65b3d0e250..ff110f00ab 100644 --- a/services/backend/src/models/courseType.ts +++ b/services/backend/src/models/courseType.ts @@ -1,4 +1,3 @@ -/* eslint-disable import/no-cycle */ import { InferAttributes } from 'sequelize' import { Column, CreatedAt, DataType, HasMany, Model, PrimaryKey, Table, UpdatedAt } from 'sequelize-typescript' diff --git a/services/backend/src/models/credit.ts b/services/backend/src/models/credit.ts index 6151bf9b2d..e52c2f3524 100644 --- a/services/backend/src/models/credit.ts +++ b/services/backend/src/models/credit.ts @@ -1,4 +1,3 @@ -/* eslint-disable import/no-cycle */ import { InferAttributes } from 'sequelize' import { BelongsTo, diff --git a/services/backend/src/models/creditTeacher.ts b/services/backend/src/models/creditTeacher.ts index dd88cc8e76..bafe03ab94 100644 --- a/services/backend/src/models/creditTeacher.ts +++ b/services/backend/src/models/creditTeacher.ts @@ -1,4 +1,3 @@ -/* eslint-disable import/no-cycle */ import { InferAttributes } from 'sequelize' import { Column, CreatedAt, DataType, ForeignKey, Model, Table, UpdatedAt } from 'sequelize-typescript' diff --git a/services/backend/src/models/creditType.ts b/services/backend/src/models/creditType.ts index 83ad94fdbf..87e1e5d19f 100644 --- a/services/backend/src/models/creditType.ts +++ b/services/backend/src/models/creditType.ts @@ -1,4 +1,3 @@ -/* eslint-disable import/no-cycle */ import { InferAttributes } from 'sequelize' import { Column, CreatedAt, DataType, Model, PrimaryKey, Table, UpdatedAt } from 'sequelize-typescript' diff --git a/services/backend/src/models/enrollment.ts b/services/backend/src/models/enrollment.ts index 96986c4584..d43b366327 100644 --- a/services/backend/src/models/enrollment.ts +++ b/services/backend/src/models/enrollment.ts @@ -1,4 +1,3 @@ -/* eslint-disable import/no-cycle */ import { InferAttributes } from 'sequelize' import { BelongsTo, diff --git a/services/backend/src/models/index.ts b/services/backend/src/models/index.ts index 610b5b818e..c68afdda8a 100644 --- a/services/backend/src/models/index.ts +++ b/services/backend/src/models/index.ts @@ -1,4 +1,3 @@ -/* eslint-disable import/no-cycle */ import { CreditTypeCode } from '../types' import { Course } from './course' import { CourseProvider } from './courseProvider' diff --git a/services/backend/src/models/kone/tag.ts b/services/backend/src/models/kone/tag.ts index 92b70cca56..52e5265502 100644 --- a/services/backend/src/models/kone/tag.ts +++ b/services/backend/src/models/kone/tag.ts @@ -1,4 +1,3 @@ -/* eslint-disable import/no-cycle */ import { CreationOptional, InferAttributes, InferCreationAttributes } from 'sequelize' import { AutoIncrement, BelongsTo, Column, DataType, ForeignKey, Model, PrimaryKey, Table } from 'sequelize-typescript' diff --git a/services/backend/src/models/kone/tagStudent.ts b/services/backend/src/models/kone/tagStudent.ts index 61abac0329..0db3aefcd7 100644 --- a/services/backend/src/models/kone/tagStudent.ts +++ b/services/backend/src/models/kone/tagStudent.ts @@ -1,4 +1,3 @@ -/* eslint-disable import/no-cycle */ import { CreationOptional, InferAttributes, InferCreationAttributes } from 'sequelize' import { AutoIncrement, BelongsTo, Column, DataType, ForeignKey, Model, PrimaryKey, Table } from 'sequelize-typescript' diff --git a/services/backend/src/models/organization.ts b/services/backend/src/models/organization.ts index af86760669..ef22226f34 100644 --- a/services/backend/src/models/organization.ts +++ b/services/backend/src/models/organization.ts @@ -1,4 +1,3 @@ -/* eslint-disable import/no-cycle */ import { InferAttributes } from 'sequelize' import { BelongsToMany, diff --git a/services/backend/src/models/programmeModule.ts b/services/backend/src/models/programmeModule.ts index 5a495b3417..a3204561ca 100644 --- a/services/backend/src/models/programmeModule.ts +++ b/services/backend/src/models/programmeModule.ts @@ -1,4 +1,3 @@ -/* eslint-disable import/no-cycle */ import { InferAttributes } from 'sequelize' import { BelongsTo, diff --git a/services/backend/src/models/programmeModuleChild.ts b/services/backend/src/models/programmeModuleChild.ts index 0dd01b2a52..10e4c357be 100644 --- a/services/backend/src/models/programmeModuleChild.ts +++ b/services/backend/src/models/programmeModuleChild.ts @@ -1,4 +1,3 @@ -/* eslint-disable import/no-cycle */ import { InferAttributes } from 'sequelize' import { Column, CreatedAt, DataType, ForeignKey, Model, PrimaryKey, Table, UpdatedAt } from 'sequelize-typescript' diff --git a/services/backend/src/models/student.ts b/services/backend/src/models/student.ts index b83276459a..d21a68db5e 100644 --- a/services/backend/src/models/student.ts +++ b/services/backend/src/models/student.ts @@ -1,4 +1,3 @@ -/* eslint-disable import/no-cycle */ import { InferAttributes } from 'sequelize' import { Column, CreatedAt, DataType, HasMany, Model, PrimaryKey, Table, UpdatedAt } from 'sequelize-typescript' diff --git a/services/backend/src/models/studyplan.ts b/services/backend/src/models/studyplan.ts index 5ce70568ef..ea7728d2a2 100644 --- a/services/backend/src/models/studyplan.ts +++ b/services/backend/src/models/studyplan.ts @@ -1,4 +1,3 @@ -/* eslint-disable import/no-cycle */ import { InferAttributes } from 'sequelize' import { BelongsTo, diff --git a/services/backend/src/models/studyrightExtent.ts b/services/backend/src/models/studyrightExtent.ts index ee21d111aa..e613e4480c 100644 --- a/services/backend/src/models/studyrightExtent.ts +++ b/services/backend/src/models/studyrightExtent.ts @@ -1,4 +1,3 @@ -/* eslint-disable import/no-cycle */ import { InferAttributes } from 'sequelize' import { Column, CreatedAt, DataType, Model, PrimaryKey, Table, UpdatedAt } from 'sequelize-typescript' diff --git a/services/backend/src/models/teacher.ts b/services/backend/src/models/teacher.ts index 23ac9567b8..6f0b6583aa 100644 --- a/services/backend/src/models/teacher.ts +++ b/services/backend/src/models/teacher.ts @@ -1,4 +1,3 @@ -/* eslint-disable import/no-cycle */ import { InferAttributes } from 'sequelize' import { BelongsToMany, Column, CreatedAt, DataType, Model, PrimaryKey, Table, UpdatedAt } from 'sequelize-typescript' diff --git a/services/backend/src/models/user.ts b/services/backend/src/models/user.ts index af01363a88..f6b920e1ac 100644 --- a/services/backend/src/models/user.ts +++ b/services/backend/src/models/user.ts @@ -1,4 +1,3 @@ -/* eslint-disable import/no-cycle */ import { CreationOptional, InferAttributes, InferCreationAttributes } from 'sequelize' import { AutoIncrement, Column, DataType, Default, Model, PrimaryKey, Table, Unique } from 'sequelize-typescript' diff --git a/services/backend/src/rapodiff/creditsDiff.js b/services/backend/src/rapodiff/creditsDiff.js index b64b9d86b5..d816ea6e80 100644 --- a/services/backend/src/rapodiff/creditsDiff.js +++ b/services/backend/src/rapodiff/creditsDiff.js @@ -1,7 +1,8 @@ const { orderBy } = require('lodash') // dbConnections must be imported to avoid Sequelize errors even if it's not used -// eslint-disable-next-line no-unused-vars + +// eslint-disable-next-line @typescript-eslint/no-unused-vars const { dbConnections } = require('../database/connection') const { computeCreditsProduced } = require('../services/providerCredits') const { parseCsv, printProgressBar } = require('./helpers') @@ -68,7 +69,7 @@ const diff = (rapoData, okData, code) => { } } -const process = async data => { +const processProgrammes = async data => { let programmeCounter = 0 const rapoProgrammeData = formatData(data.slice(1)) const allProgrammeCodes = [...new Set(Object.keys(rapoProgrammeData))] @@ -87,7 +88,7 @@ const process = async data => { const programmeCreditsDiff = async fileName => { console.log('Running studyprogramme credits diff') - await parseCsv(fileName, process) + await parseCsv(fileName, processProgrammes) console.log('Diff completed.') } diff --git a/services/backend/src/routes.ts b/services/backend/src/routes.ts index d589fc29c9..33ec86cc47 100644 --- a/services/backend/src/routes.ts +++ b/services/backend/src/routes.ts @@ -78,9 +78,8 @@ const routes = (app: Express, url: string) => { app.use(`${url}/close-to-graduation`, auth.roles(['fullSisuAccess', 'studyGuidanceGroups']), closeToGraduation) app.use(`${url}/study-programme-pins`, studyProgrammePins) app.use(`${url}/curriculum-periods`, curriculumPeriods) - app.get('*', async (_, res) => { - const results = { error: 'unknown endpoint' } - res.status(404).json(results) + app.get('*', (_, res) => { + res.status(404).json({ error: 'unknown endpoint' }) }) Sentry.setupExpressErrorHandler(app) app.use(errorHandler) diff --git a/services/backend/src/routes/courses.ts b/services/backend/src/routes/courses.ts index 4fbb43d915..cffe950bde 100644 --- a/services/backend/src/routes/courses.ts +++ b/services/backend/src/routes/courses.ts @@ -56,7 +56,7 @@ router.get('/v3/courseyearlystats', async (req: GetCourseYearlyStatsRequest, res const { roles, programmeRights } = req.user const userHasFullAccessToStudentData = hasFullAccessToStudentData(roles) - const userHasCorrectRole = userHasFullAccessToStudentData || roles.includes('courseStatistics') + const userHasCorrectRole = userHasFullAccessToStudentData === true || roles.includes('courseStatistics') const fullStudyProgrammeRights = getFullStudyProgrammeRights(programmeRights) // If user has rights to see at least one programme, then they are allowed to see all of them diff --git a/services/backend/src/routes/login.ts b/services/backend/src/routes/login.ts index 4d6b8ac5bb..cbc5953132 100644 --- a/services/backend/src/routes/login.ts +++ b/services/backend/src/routes/login.ts @@ -5,7 +5,7 @@ import { ApplicationError } from '../util/customErrors' const router = Router() -router.get('/', async (req: Request, res: Response) => { +router.get('/', (req: Request, res: Response) => { const { user, logoutUrl } = req if (!user) { diff --git a/services/backend/src/routes/population.ts b/services/backend/src/routes/population.ts index 28a9c520fb..39a42320cb 100644 --- a/services/backend/src/routes/population.ts +++ b/services/backend/src/routes/population.ts @@ -432,10 +432,9 @@ router.post('/v3/populationstatisticsbystudentnumbers', async (req: PostByStuden const filteredStudentNumbers = hasFullAccessToStudentData(roles) ? studentnumberlist : intersection(studentnumberlist, studentsUserCanAccess) - const studyProgrammeCode = - tags?.studyProgramme && tags?.studyProgramme.includes('+') - ? tags?.studyProgramme.split('+')[0] - : tags?.studyProgramme + const studyProgrammeCode = tags?.studyProgramme?.includes('+') + ? tags?.studyProgramme.split('+')[0] + : tags?.studyProgramme const result = await optimizedStatisticsOf( { diff --git a/services/backend/src/routes/studyProgramme.ts b/services/backend/src/routes/studyProgramme.ts index 93af236529..ccd6ce820f 100644 --- a/services/backend/src/routes/studyProgramme.ts +++ b/services/backend/src/routes/studyProgramme.ts @@ -57,7 +57,7 @@ router.get('/:id/basicstats', async (req: GetStatsRequest, res: Response) => { return res.status(422).end() } - logInfoForGrafana(code, combinedProgramme) + void logInfoForGrafana(code, combinedProgramme) const data = await getBasicStats(code, combinedProgramme, yearType, specialGroups) if (data) { return res.json(data) @@ -117,7 +117,7 @@ router.get('/:id/coursestats', async (req: GetCourseStatsRequest, res: Response) const combinedProgramme = req.query?.combined_programme const date = new Date() date.setHours(23, 59, 59, 999) - logInfoForGrafana(code, combinedProgramme) + void logInfoForGrafana(code, combinedProgramme) try { const data = await getStudyProgrammeCoursesForStudyTrack(date.getTime(), code, showByYear, combinedProgramme) return res.json(data) @@ -141,7 +141,7 @@ router.get('/:id/studytrackstats', async (req: GetStudyTrackStatsRequest, res: R return res.status(422).end() } - logInfoForGrafana(code, combinedProgramme) + void logInfoForGrafana(code, combinedProgramme) const data = await getStudyTrackStats(code, combinedProgramme, graduated, specialGroups) if (data) { return res.json(data) diff --git a/services/backend/src/routes/tags.ts b/services/backend/src/routes/tags.ts index 29651dd892..754db3d9d1 100644 --- a/services/backend/src/routes/tags.ts +++ b/services/backend/src/routes/tags.ts @@ -69,7 +69,6 @@ interface PostTagRequest extends Request { router.post('/tags', async (req: PostTagRequest, res: Response) => { const { - // eslint-disable-next-line @typescript-eslint/naming-convention tag: { studytrack, tagname, year, personal_user_id }, } = req.body const { roles, id, programmeRights } = req.user diff --git a/services/backend/src/routes/updater.ts b/services/backend/src/routes/updater.ts index 59d94651c0..b4804de741 100644 --- a/services/backend/src/routes/updater.ts +++ b/services/backend/src/routes/updater.ts @@ -80,7 +80,7 @@ router.get('/refresh_redis_cache', async (req: Request, res: Response) => { } }) -router.post('/refresh-teacher-leaderboard', async (req: Request, res: Response) => { +router.post('/refresh-teacher-leaderboard', (req: Request, res: Response) => { logger.info( `${req.user.username} requested refresh of teacher leaderboard for the current and previous academic year` ) @@ -90,17 +90,17 @@ router.post('/refresh-teacher-leaderboard', async (req: Request, res: Response) router.post('/refresh_study_programmes_v2', async (req: Request, res: Response) => { logger.info(`${req.user.username} requested refresh of study programmes`) - refreshProgrammes() + await refreshProgrammes() res.status(200).json('Added job for refreshing study programme overviews') }) router.post('/refresh_faculties_v2', async (req: Request, res: Response) => { logger.info(`${req.user.username} requested refresh of faculties`) - refreshFaculties() + await refreshFaculties() res.status(200).json('Added job for refreshing faculties') }) -router.post('/refresh_language_center_data', async (req: Request, res: Response) => { +router.post('/refresh_language_center_data', (req: Request, res: Response) => { logger.info(`${req.user.username} requested refresh of language center data`) if (!languageCenterViewEnabled) res.status(418).json({ error: 'The language center functionality is not activated in your environment.' }) @@ -108,7 +108,7 @@ router.post('/refresh_language_center_data', async (req: Request, res: Response) res.status(200).json('Added job for refreshing language center data') }) -router.post('/refresh-close-to-graduation', async (req: Request, res: Response) => { +router.post('/refresh-close-to-graduation', (req: Request, res: Response) => { logger.info(`${req.user.username} requested refresh of close to graduation data`) jobMaker.closeToGraduation() res.status(200).json('Added job for refreshing close to graduation data') diff --git a/services/backend/src/routes/users.ts b/services/backend/src/routes/users.ts index 516b677c15..2a2a447440 100644 --- a/services/backend/src/routes/users.ts +++ b/services/backend/src/routes/users.ts @@ -15,7 +15,7 @@ router.get('/', auth.roles(['admin']), async (_req: Request, res: Response) => { res.json(results) }) -router.get('/access_groups', auth.roles(['admin']), async (_req: Request, res: Response) => { +router.get('/access_groups', auth.roles(['admin']), (_req: Request, res: Response) => { res.json(roles) }) diff --git a/services/backend/src/services/completedCoursesSearch.ts b/services/backend/src/services/completedCoursesSearch.ts index 9ae1b82b58..6dc1ec03ec 100644 --- a/services/backend/src/services/completedCoursesSearch.ts +++ b/services/backend/src/services/completedCoursesSearch.ts @@ -83,7 +83,7 @@ const getCredits = async ( ? null : courses.find(course => course.substitutions.includes(credit.course_code))?.code return { - courseCode: originalCode || credit.course_code, + courseCode: originalCode ?? credit.course_code, substitution: originalCode ? credit.course_code : null, studentNumber: credit.student_studentnumber, creditType: credit.credittypecode, @@ -112,7 +112,7 @@ const getEnrollments = async (courses: Courses, fullCourseCodes: string[], stude const formattedEnrollments = enrollments.map(enrollment => { const originalCode = courses.find(course => course.substitutions.includes(enrollment.course_code))?.code return { - courseCode: originalCode || enrollment.course_code, + courseCode: originalCode ?? enrollment.course_code, substitution: originalCode ? enrollment.course_code : null, studentNumber: enrollment.studentnumber, date: enrollment.enrollment_date_time, diff --git a/services/backend/src/services/courses/courseStatsCounter.ts b/services/backend/src/services/courses/courseStatsCounter.ts index 232a01ee71..9de1e3edb1 100644 --- a/services/backend/src/services/courses/courseStatsCounter.ts +++ b/services/backend/src/services/courses/courseStatsCounter.ts @@ -22,26 +22,16 @@ const initializePassingSemesters = () => { return passingSemesters } -const getEnrolledStudents = (enrollments: DynamicEnrollments) => { - if (enrollments) { - return Object.keys(enrollments) - .filter(key => key !== EnrollmentState.ENROLLED && key !== 'semesters') - .reduce((acc, key) => [...acc, ...[...enrollments[key]].map(studentNumber => studentNumber)], [] as string[]) - } - return [] -} - -const getFilteredEnrolledNoGrade = ( - enrollments: DynamicEnrollments, - enrolledStudents: string[], - allStudents: string[] -) => { - if (enrollments[EnrollmentState.ENROLLED]) { - return [...enrollments[EnrollmentState.ENROLLED]] - .filter(student => !enrolledStudents.includes(student) && !allStudents.includes(student)) - .reduce((acc, student) => ({ ...acc, [student]: true }), {} as Record) +const getFilteredEnrolledNoGrade = (enrollments: DynamicEnrollments, allStudents: string[]) => { + const enrolledStudents = [...(enrollments[EnrollmentState.ENROLLED] ?? [])] + const result: Record = {} + for (const student of enrolledStudents) { + if (allStudents.includes(student)) { + continue + } + result[student] = true } - return {} as Record + return result } type DynamicEnrollments = { @@ -262,9 +252,8 @@ export class CourseStatsCounter { public getFinalStats() { const { stats, students } = this - const enrolledStudents = getEnrolledStudents(this.enrollments) - const allStudents = Object.keys(students.all).map(student => student) - const filteredEnrolledNoGrade = getFilteredEnrolledNoGrade(this.enrollments, enrolledStudents, allStudents) + const allStudents = Object.keys(students.all) + const filteredEnrolledNoGrade = getFilteredEnrolledNoGrade(this.enrollments, allStudents) students.all = { ...students.all, ...filteredEnrolledNoGrade } students.enrolledNoGrade = filteredEnrolledNoGrade diff --git a/services/backend/src/services/courses/index.ts b/services/backend/src/services/courses/index.ts index ebddbce9cd..fb38970395 100644 --- a/services/backend/src/services/courses/index.ts +++ b/services/backend/src/services/courses/index.ts @@ -251,7 +251,7 @@ const getYearlyStatsOfNew = async ( ) let substitutionCourses: Course[] | undefined - if (combineSubstitutions && courseForSubs && courseForSubs.substitutions && courseForSubs.substitutions.length > 0) { + if (combineSubstitutions && courseForSubs?.substitutions && courseForSubs.substitutions.length > 0) { substitutionCourses = await Course.findAll({ where: { code: { @@ -270,7 +270,7 @@ const getYearlyStatsOfNew = async ( return { ...statistics, coursecode: courseCode, - alternatives: substitutionCourses || [{ code: courseForSubs!.code, name: courseForSubs!.name }], + alternatives: substitutionCourses ?? [{ code: courseForSubs!.code, name: courseForSubs!.name }], name: course?.name, } } @@ -401,7 +401,7 @@ export const getCourseYearlyStats = async ( }) ) - if (serviceProvider === 'fd') logger.info(`Debugging c.y.s.: finished creating statsRegular`) + if (serviceProvider === 'fd') logger.info('Debugging c.y.s.: finished creating statsRegular') return statsRegular } diff --git a/services/backend/src/services/faculty/facultyService.ts b/services/backend/src/services/faculty/facultyService.ts index 958334ff9b..36c0225e00 100644 --- a/services/backend/src/services/faculty/facultyService.ts +++ b/services/backend/src/services/faculty/facultyService.ts @@ -193,11 +193,7 @@ export const setGraduationStats = async (data: GraduationData, programmeFilter: return dataToRedis } -export const getGraduationStats = async ( - id: string, - programmeFilter: ProgrammeFilter, - keepGraduationTimes: boolean = false -) => { +export const getGraduationStats = async (id: string, programmeFilter: ProgrammeFilter, keepGraduationTimes = false) => { const redisKey = createRedisKeyForGraduationTimeStats(id, programmeFilter) const dataFromRedis = await redisClient.get(redisKey) if (!dataFromRedis) { diff --git a/services/backend/src/services/faculty/facultyStudentProgress.ts b/services/backend/src/services/faculty/facultyStudentProgress.ts index c94e65b694..095b2b6e12 100644 --- a/services/backend/src/services/faculty/facultyStudentProgress.ts +++ b/services/backend/src/services/faculty/facultyStudentProgress.ts @@ -128,7 +128,7 @@ export const combineFacultyStudentProgress = async ( studyRightsOfProgramme, }) statsOfProgrammes.push(updatedStats) - setStudyTrackStats(updatedStats, graduated, specialGroups) + await setStudyTrackStats(updatedStats, graduated, specialGroups) } } diff --git a/services/backend/src/services/faculty/facultyStudents.ts b/services/backend/src/services/faculty/facultyStudents.ts index f69a505113..df90b9a604 100644 --- a/services/backend/src/services/faculty/facultyStudents.ts +++ b/services/backend/src/services/faculty/facultyStudents.ts @@ -82,7 +82,7 @@ export const combineFacultyStudents = async ( }, studyRightsOfProgramme, }) - setStudyTrackStats(updatedStats, graduated, specialGroups) + await setStudyTrackStats(updatedStats, graduated, specialGroups) if (!years.length) { years = updatedStats.years } diff --git a/services/backend/src/services/openUni/openUniManageSearches.ts b/services/backend/src/services/openUni/openUniManageSearches.ts index b189497726..fc2c8a0361 100644 --- a/services/backend/src/services/openUni/openUniManageSearches.ts +++ b/services/backend/src/services/openUni/openUniManageSearches.ts @@ -36,7 +36,7 @@ export const getOpenUniSearches = async (userId: string) => { export const createNewSearch = async (userId: string, name: string, courseCodes: string[]) => { const savedSearches = await getOpenUniSearchesByUser(userId) - if (savedSearches && savedSearches.some(search => search.name === name)) { + if (savedSearches?.some(search => search.name === name)) { return null } try { diff --git a/services/backend/src/services/openUni/openUniStats.ts b/services/backend/src/services/openUni/openUniStats.ts index 467682c100..822e4888ff 100644 --- a/services/backend/src/services/openUni/openUniStats.ts +++ b/services/backend/src/services/openUni/openUniStats.ts @@ -28,7 +28,7 @@ type StudentStats = { const uniq = objects => [...new Set(objects)] -const calculateTotalsForStudent = async (studentStats: StudentStats, studentNumber: string) => { +const calculateTotalsForStudent = (studentStats: StudentStats, studentNumber: string) => { Object.keys(studentStats[studentNumber].courseInfo).forEach(course => { const { status } = studentStats[studentNumber].courseInfo[course] if (status.passed) { @@ -143,7 +143,7 @@ export const getCustomOpenUniCourses = async (courseCodes: string[], startDate: updateUnfinishedStatus(studentCourses[courseCode], enrollmentDateTime) } } - await calculateTotalsForStudent(studentStats, studentNumber) + calculateTotalsForStudent(studentStats, studentNumber) } const openUniStats = { students: studentStats, courses } return openUniStats diff --git a/services/backend/src/services/populations/bottlenecksOf.ts b/services/backend/src/services/populations/bottlenecksOf.ts index 529e4dcb8d..3393cacb0f 100644 --- a/services/backend/src/services/populations/bottlenecksOf.ts +++ b/services/backend/src/services/populations/bottlenecksOf.ts @@ -25,7 +25,7 @@ const getStudentsAndCourses = async ( if (!studentNumbers) { const { months, studyRights, startDate, endDate, exchangeStudents, nondegreeStudents, transferredStudents } = params const studentnumbers = - selectedStudents || + selectedStudents ?? (await getStudentNumbersWithAllStudyRightElements({ studyRights, startDate, @@ -64,7 +64,7 @@ type Bottlenecks = { allStudents: number } -export const bottlenecksOf = async (query: Query, studentNumbers: string[] | null, encryptData: boolean = false) => { +export const bottlenecksOf = async (query: Query, studentNumbers: string[] | null, encryptData = false) => { const encryptStudentNumbers = (bottlenecks: Bottlenecks) => { for (const course of Object.keys(bottlenecks.coursestatistics)) { const encryptedStudentStats = {} @@ -142,7 +142,7 @@ export const bottlenecksOf = async (query: Query, studentNumbers: string[] | nul coursestats.addCourseSubstitutions(course.substitutions) if (course.enrollments) { course.enrollments.forEach(({ studentnumber, state, enrollment_date_time }) => { - if ((query?.selectedStudents && query?.selectedStudents.includes(studentnumber)) || !query?.selectedStudents) { + if (query?.selectedStudents?.includes(studentnumber) || !query?.selectedStudents) { const semester = getPassingSemester(startYear, enrollment_date_time) coursestats.markEnrollment(studentnumber, state, semester) } @@ -151,7 +151,7 @@ export const bottlenecksOf = async (query: Query, studentNumbers: string[] | nul if ('credits' in course) { course.credits.forEach(credit => { const { studentnumber, passingGrade, improvedGrade, failingGrade, grade, date } = parseCreditInfo(credit) - if ((query?.selectedStudents && query?.selectedStudents.includes(studentnumber)) || !query?.selectedStudents) { + if (query?.selectedStudents?.includes(studentnumber) || !query?.selectedStudents) { const semester = getPassingSemester(startYear, date) coursestats.markCredit(studentnumber, grade, passingGrade, failingGrade, improvedGrade, semester) } diff --git a/services/backend/src/services/populations/closeToGraduation.ts b/services/backend/src/services/populations/closeToGraduation.ts index 3b11ef6173..bacc18fb26 100644 --- a/services/backend/src/services/populations/closeToGraduation.ts +++ b/services/backend/src/services/populations/closeToGraduation.ts @@ -85,7 +85,7 @@ const formatStudent = (student: Student) => { const { studentnumber: studentNumber, abbreviatedname: name, - // eslint-disable-next-line @typescript-eslint/naming-convention + sis_person_id, email, phone_number: phoneNumber, diff --git a/services/backend/src/services/populations/optimizedStatisticsOf.ts b/services/backend/src/services/populations/optimizedStatisticsOf.ts index 8cfa9c3b39..57f07b0c2f 100644 --- a/services/backend/src/services/populations/optimizedStatisticsOf.ts +++ b/services/backend/src/services/populations/optimizedStatisticsOf.ts @@ -39,7 +39,7 @@ export const optimizedStatisticsOf = async (query: Query, studentNumberList?: st parseQueryParams(formattedQueryParams as FormattedQueryParams) const studentNumbers = - studentNumberList || + studentNumberList ?? (await getStudentNumbersWithAllStudyRightElements({ studyRights, startDate, @@ -68,7 +68,7 @@ export const optimizedStatisticsOf = async (query: Query, studentNumberList?: st tag ) - const formattedStudents = await formatStudentsForApi( + const formattedStudents = formatStudentsForApi( students, enrollments, credits, diff --git a/services/backend/src/services/populations/shared.ts b/services/backend/src/services/populations/shared.ts index dc32d0d129..fc678366f5 100644 --- a/services/backend/src/services/populations/shared.ts +++ b/services/backend/src/services/populations/shared.ts @@ -1,4 +1,3 @@ -/* eslint-disable @typescript-eslint/naming-convention */ import { orderBy } from 'lodash' import moment from 'moment' import { Op, QueryTypes } from 'sequelize' @@ -22,13 +21,12 @@ type CriteriaYear = { } const createEmptyCriteriaYear = (criteria: Criteria, year: string): CriteriaYear => { - const coursesSatisfied: CoursesSatisfied = - criteria?.courses && criteria?.courses[year] - ? criteria.courses[year]?.reduce((acc: CoursesSatisfied, course: string) => { - acc[course] = null - return acc - }, {} as CoursesSatisfied) - : {} + const coursesSatisfied: CoursesSatisfied = criteria?.courses?.[year] + ? criteria.courses[year]?.reduce((acc: CoursesSatisfied, course: string) => { + acc[course] = null + return acc + }, {} as CoursesSatisfied) + : {} return { credits: false, totalSatisfied: 0, @@ -60,12 +58,10 @@ const updateCourseByYear = ( ) => { // TODO: Clean up this mess if ( - criteria?.courses && - criteria?.courses[criteriaYear] && + criteria?.courses?.[criteriaYear] && (criteria.courses[criteriaYear].includes(course.course_code) || - criteria.courses[criteriaYear].some( - (criteriaCourse: string) => - criteria.allCourses[criteriaCourse] && criteria.allCourses[criteriaCourse].includes(course.course_code) + criteria.courses[criteriaYear].some((criteriaCourse: string) => + criteria.allCourses[criteriaCourse]?.includes(course.course_code) )) ) { if ( @@ -268,7 +264,7 @@ const formatStudentForPopulationStatistics = ( secondaryEmail: secondary_email, phoneNumber: phone_number, updatedAt: updatedAt || createdAt, - tags: tags || [], + tags: tags ?? [], studyrightStart: startDate, starting: moment(started).isBetween(startDateMoment, endDateMoment, null, '[]'), option, @@ -326,9 +322,9 @@ export const parseQueryParams = (query: Query) => { ? new Date(`${year + 1}-${SemesterStart.FALL}`).toISOString() : new Date(`${year + 1}-${SemesterStart.SPRING}`).toISOString() - const exchangeStudents = studentStatuses != null && studentStatuses.includes('EXCHANGE') - const nondegreeStudents = studentStatuses != null && studentStatuses.includes('NONDEGREE') - const transferredStudents = studentStatuses != null && studentStatuses.includes('TRANSFERRED') + const exchangeStudents = studentStatuses?.includes('EXCHANGE') + const nondegreeStudents = studentStatuses?.includes('NONDEGREE') + const transferredStudents = studentStatuses?.includes('TRANSFERRED') return { exchangeStudents, @@ -407,7 +403,7 @@ export const getOptionsForStudents = async ( }, {}) } -export const formatStudentsForApi = async ( +export const formatStudentsForApi = ( students: Array, enrollments: Enrollment[], credits: Credit[], diff --git a/services/backend/src/services/providerCredits.ts b/services/backend/src/services/providerCredits.ts index a23c6ec7ec..20c00a91d8 100644 --- a/services/backend/src/services/providerCredits.ts +++ b/services/backend/src/services/providerCredits.ts @@ -92,11 +92,9 @@ const getBasicDegreeStudyRight = ( const rightDates = new Date(studyRight.startDate).getTime() <= new Date(date).getTime() && new Date(date).getTime() <= new Date(studyRight.endDate).getTime() - const enrolledAsPresent = - studyRight.semesterEnrollments != null && - studyRight.semesterEnrollments.some( - enrollment => enrollment.semester === semestercode && enrollment.type === EnrollmentType.PRESENT - ) + const enrolledAsPresent = studyRight.semesterEnrollments?.some( + enrollment => enrollment.semester === semestercode && enrollment.type === EnrollmentType.PRESENT + ) return basicDegreeExtentCodes.includes(studyRight.extentCode) && rightDates && enrolledAsPresent }) } @@ -178,11 +176,7 @@ export const computeCreditsProduced = async (providerCode: string, isAcademicYea return { stats, id: providerCode } } -export const getCreditsProduced = async ( - providerCode: string, - isAcademicYear: boolean, - specialIncluded: boolean = true -) => { +export const getCreditsProduced = async (providerCode: string, isAcademicYear: boolean, specialIncluded = true) => { let data = await getCreditStats(providerCode, isAcademicYear, specialIncluded) if (data) { return data diff --git a/services/backend/src/services/providers.ts b/services/backend/src/services/providers.ts index bbc824755c..de14aba9a3 100644 --- a/services/backend/src/services/providers.ts +++ b/services/backend/src/services/providers.ts @@ -23,7 +23,7 @@ export const getCourseCodesOfProvider = async (provider: string) => { }) const coursesWithOpenUniSubstitutions = coursesByProvider.map(({ code, substitutions }) => { - if (!substitutions || !substitutions.length) { + if (!substitutions?.length) { return [code] } const alternatives = [`AY-${code}`, `AY${code}`, `A-${code}`] diff --git a/services/backend/src/services/studyProgramme/studyProgrammeCourses.ts b/services/backend/src/services/studyProgramme/studyProgrammeCourses.ts index 6a4203a73b..6db10c9902 100644 --- a/services/backend/src/services/studyProgramme/studyProgrammeCourses.ts +++ b/services/backend/src/services/studyProgramme/studyProgrammeCourses.ts @@ -7,6 +7,7 @@ import { mapToProviders } from '../../shared/util' import { CreditTypeCode, EnrollmentState } from '../../types' import { isOpenUniCourseCode } from '../../util' import { createArrayOfCourses } from '../languageCenterData' +import { getCurrentStudyYearStartDate, getNotCompletedForProgrammeCourses, getAllProgrammeCourses } from '.' import { getOtherStudentsForProgrammeCourses, getOwnStudentsForProgrammeCourses, @@ -14,7 +15,6 @@ import { getStudentsWithoutStudyRightForProgrammeCourses, getTransferStudentsForProgrammeCourses, } from './studentGetters' -import { getCurrentStudyYearStartDate, getNotCompletedForProgrammeCourses, getAllProgrammeCourses } from '.' const getCurrentYearStartDate = () => { return new Date(new Date().getFullYear(), 0, 1) @@ -25,7 +25,7 @@ const getAllStudyProgrammeCourses = async (studyProgramme: string) => { const normalCourses = await getAllProgrammeCourses(providerCode) return normalCourses.reduce((acc, curr) => { acc.push(curr.code) - if (curr.substitutions && curr.substitutions.includes(`AY${curr.code}`)) { + if (curr.substitutions?.includes(`AY${curr.code}`)) { acc.push(`AY${curr.code}`) } return acc @@ -286,7 +286,7 @@ export const getStudyProgrammeCoursesForStudyTrack = async ( acc[curr.code] = { code: curr.code, name: curr.name, - isStudyModule: curr.isStudyModule || false, + isStudyModule: curr.isStudyModule ?? false, years: {}, } } diff --git a/services/backend/src/services/studyProgramme/studyProgrammeGraduations.ts b/services/backend/src/services/studyProgramme/studyProgrammeGraduations.ts index 8e1e42b739..edd4289b5c 100644 --- a/services/backend/src/services/studyProgramme/studyProgrammeGraduations.ts +++ b/services/backend/src/services/studyProgramme/studyProgrammeGraduations.ts @@ -3,7 +3,7 @@ import moment from 'moment' import { Name } from '../../shared/types' import { mapToProviders } from '../../shared/util' -import { DegreeProgrammeType, ExtentCode, SemesterEnrollment, StudyTrack } from '../../types' +import { DegreeProgrammeType, ExtentCode, Phase, SemesterEnrollment, StudyTrack } from '../../types' import { getDegreeProgrammeType, getMinimumCreditsOfProgramme, sortByProgrammeCode } from '../../util' import { countTimeCategories } from '../graduationHelpers' import { getSemestersAndYears } from '../semesters' @@ -232,7 +232,7 @@ const getProgrammesBeforeStarting = async ({ if (!studyRightElement) return acc // If the extent code is something else, that means the student hasn't continued from a bachelor's programme if (studyRight.extentCode !== ExtentCode.BACHELOR_AND_MASTER) return acc - const phase1Programmes = studyRight.studyRightElements.filter(elem => elem.phase === 1) + const phase1Programmes = studyRight.studyRightElements.filter(elem => elem.phase === Phase.ANY) const [latestPhase1Programme] = orderBy(phase1Programmes, ['endDate'], ['desc']) if (!acc[latestPhase1Programme.code]) { const programmeWithYears: ProgrammeWithYears = { @@ -242,7 +242,7 @@ const getProgrammesBeforeStarting = async ({ } acc[latestPhase1Programme.code] = programmeWithYears } - const phase2Programmes = studyRight.studyRightElements.filter(elem => elem.phase === 2) + const phase2Programmes = studyRight.studyRightElements.filter(elem => elem.phase === Phase.MASTER) const hasTransferred = hasTransferredFromOrToProgramme(studyRight, studyRightElement) @@ -273,7 +273,7 @@ const getProgrammesAfterGraduation = async ({ if (!includeAllSpecials && hasTransferred.some(fromOrTo => fromOrTo === true)) return acc - const phase2Programmes = studyRight.studyRightElements.filter(elem => elem.phase === 2) + const phase2Programmes = studyRight.studyRightElements.filter(elem => elem.phase === Phase.MASTER) const [firstPhase2Programme] = orderBy(phase2Programmes, ['startDate'], ['asc']) if (!firstPhase2Programme) return acc @@ -319,7 +319,7 @@ export const getGraduationStatsForStudyTrack = async ({ const years = getYearsArray(since.getFullYear(), isAcademicYear) as number[] const queryParameters = { studyProgramme, since, years, isAcademicYear, includeAllSpecials } const combinedQueryParameters = { - studyProgramme: combinedProgramme || '', + studyProgramme: combinedProgramme ?? '', since, years, isAcademicYear, diff --git a/services/backend/src/services/teachers/top.ts b/services/backend/src/services/teachers/top.ts index bef761fb05..3c91de9510 100644 --- a/services/backend/src/services/teachers/top.ts +++ b/services/backend/src/services/teachers/top.ts @@ -96,7 +96,7 @@ const updatedStats = ( } } -const filterTopTeachers = (stats: Record, limit: number = 50) => { +const filterTopTeachers = (stats: Record, limit = 50) => { return Object.values(stats) .sort((t1, t2) => t2.credits - t1.credits) .slice(0, limit) @@ -119,7 +119,6 @@ const findTopTeachers = async (yearCode: number) => { const all: Record = {} const openuni: Record = {} for (const credit of credits) { - // eslint-disable-next-line @typescript-eslint/naming-convention const { credits, credittypecode, isStudyModule, is_open, teacherId, teacherName } = credit if (isStudyModule) continue const passed = Credit.passed(credit) || Credit.improved(credit) @@ -143,7 +142,7 @@ const findAndSaveTopTeachers = async (yearCode: number) => { await setTeacherStats(CategoryID.ALL, yearCode, all) } -export const findAndSaveTeachers = async (endCode?: number, startCode: number = 1) => { +export const findAndSaveTeachers = async (endCode?: number, startCode = 1) => { const endYearCode = endCode ?? (await getCurrentSemester()).getDataValue('yearcode') for (let code = startCode; code <= endYearCode; code++) { await findAndSaveTopTeachers(code) diff --git a/services/backend/src/services/userService.ts b/services/backend/src/services/userService.ts index f1f10f10a7..d702be104c 100644 --- a/services/backend/src/services/userService.ts +++ b/services/backend/src/services/userService.ts @@ -100,7 +100,7 @@ const getStudyProgrammeRights = ( return studyProgrammeRights } -const formatUser = async (user: ExpandedUser, getStudentAccess: boolean = true) => { +const formatUser = async (user: ExpandedUser, getStudentAccess = true) => { const fullStudyProgrammeRights = getFullStudyProgrammeRights(user.detailedProgrammeRights) const shouldFetchStudentAccess = getStudentAccess && !hasFullAccessToStudentData(user.roles) @@ -293,7 +293,7 @@ export const getUserFd = async ({ username }: { username: string }) => { } userFromDbOrm.lastLogin = new Date() - userFromDbOrm.save() + await userFromDbOrm.save() const userFromDb = userFromDbOrm.toJSON() diff --git a/services/backend/src/types/course.ts b/services/backend/src/types/course.ts index 0b71cf4174..7726da303c 100644 --- a/services/backend/src/types/course.ts +++ b/services/backend/src/types/course.ts @@ -1,4 +1,3 @@ -/* eslint-disable import/no-cycle */ import { InferAttributes } from 'sequelize' import { Course } from '../models' diff --git a/services/backend/src/types/index.ts b/services/backend/src/types/index.ts index 78db6e1c03..5f54ed9646 100644 --- a/services/backend/src/types/index.ts +++ b/services/backend/src/types/index.ts @@ -1,4 +1,3 @@ -/* eslint-disable import/no-cycle */ export { CourseWithSubsId, ParsedCourse } from './course' export { CreditTypeCode } from './creditTypeCode' export { Criteria } from './criteria' diff --git a/services/backend/src/types/user.ts b/services/backend/src/types/user.ts index 6d6a438765..e662b02986 100644 --- a/services/backend/src/types/user.ts +++ b/services/backend/src/types/user.ts @@ -1,4 +1,3 @@ -/* eslint-disable import/no-cycle */ import { InferAttributes } from 'sequelize' import { User } from '../models/user' diff --git a/services/backend/src/util/index.ts b/services/backend/src/util/index.ts index b9b720f6ae..2270807e22 100644 --- a/services/backend/src/util/index.ts +++ b/services/backend/src/util/index.ts @@ -10,7 +10,7 @@ const isObjectWithKey = (obj: unknown, key: string): obj is Record { +export const createLocaleComparator = (key?: string, desc = false) => { return (val1: unknown, val2: unknown): number => { let val1ToCompare: unknown let val2ToCompare: unknown @@ -43,10 +43,10 @@ export const getFullStudyProgrammeRights = (detailedProgrammeRights: DetailedPro export const hasFullAccessToStudentData = (roles?: Role[]) => { const rolesWithFullAccess: Role[] = ['admin', 'fullSisuAccess'] - return roles != null && roles.some(role => rolesWithFullAccess.includes(role)) + return roles?.some(role => rolesWithFullAccess.includes(role)) } -export const isOpenUniCourseCode = (code: string) => code.match(/^AY?(.+?)(?:en|fi|sv)?$/) +export const isOpenUniCourseCode = (code: string) => /^AY?(.+?)(?:en|fi|sv)?$/.exec(code) /** * Returns the keys of the given object as an array of strings, typed as the keys of the object. diff --git a/services/backend/src/util/jami.ts b/services/backend/src/util/jami.ts index b6da271b1c..81519795f4 100644 --- a/services/backend/src/util/jami.ts +++ b/services/backend/src/util/jami.ts @@ -20,7 +20,7 @@ type UserIamAccess = { export const getUserIamAccess = async ( sisPersonId: string, iamGroups: string[], - attempt: number = 1 + attempt = 1 ): Promise => { if (iamGroups.length === 0) { return {} @@ -69,17 +69,14 @@ export const getAllUserAccess = async (userIds: string[]) => { return data as Access[] } -const testJami = async () => { - try { - await jamiClient.get('/ping', { timeout: 4000 }) - logger.info('JAMI connected') - } catch (error) { - logger.error(error) - logger.warn('JAMI not responding :(') - logger.info('Are you sure you are using the latest JAMI image?') - } -} - if (serviceProvider === 'toska') { - testJami() + jamiClient + .get('/ping', { timeout: 4000 }) + .then(() => { + logger.info('JAMI connected') + }) + .catch(error => { + logger.error('JAMI not responding :(', { error }) + logger.info('Are you sure you are using the latest JAMI image?') + }) } diff --git a/services/backend/src/util/mami.js b/services/backend/src/util/mami.js index e5f0237c5e..6b9206ea72 100644 --- a/services/backend/src/util/mami.js +++ b/services/backend/src/util/mami.js @@ -1,4 +1,3 @@ -/* eslint-disable no-unused-vars */ const getUserIamAccess = async (_, __, ___) => { return {} } diff --git a/services/backend/src/util/semester.ts b/services/backend/src/util/semester.ts index a80af99f21..d09e6295a1 100644 --- a/services/backend/src/util/semester.ts +++ b/services/backend/src/util/semester.ts @@ -1,15 +1,10 @@ import moment from 'moment' -enum SpringSemester { - START_MONTH = 0, - END_MONTH = 6, +const isSpring = (date: moment.Moment) => { + return 0 <= date.month() && date.month() <= 6 } -const isSpring = (date: moment.Moment): boolean => { - return SpringSemester.START_MONTH <= date.month() && date.month() <= SpringSemester.END_MONTH -} - -const getSemester = (date: moment.Moment): 'FALL' | 'SPRING' => (isSpring(date) ? 'SPRING' : 'FALL') +const getSemester = (date: moment.Moment) => (isSpring(date) ? 'SPRING' : 'FALL') export enum SemesterStart { SPRING = '01-01', diff --git a/services/backend/src/worker/worker.js b/services/backend/src/worker/worker.js index 6ad0dfd60f..cea806eb1f 100644 --- a/services/backend/src/worker/worker.js +++ b/services/backend/src/worker/worker.js @@ -1,4 +1,5 @@ const Sentry = require('@sentry/node') +// eslint-disable-next-line no-redeclare const { Worker } = require('bullmq') const moment = require('moment') diff --git a/services/frontend/.eslintrc.json b/services/frontend/.eslintrc.json deleted file mode 100644 index 01a8a0925d..0000000000 --- a/services/frontend/.eslintrc.json +++ /dev/null @@ -1,108 +0,0 @@ -{ - "root": true, - "env": { - "browser": true, - "es2021": true - }, - "parserOptions": { - "ecmaVersion": "latest", - "sourceType": "module" - }, - "extends": ["../../.eslintrc.json", "plugin:react/jsx-runtime"], - "overrides": [ - { - "files": ["**/*.ts", "**/*.tsx"], - "env": { - "es2021": true, - "node": true - }, - "extends": [ - "airbnb-typescript", - "eslint:recommended", - "plugin:@typescript-eslint/recommended", - "plugin:prettier/recommended" - ], - "parser": "@typescript-eslint/parser", - "parserOptions": { - "ecmaVersion": 2021, - "sourceType": "module", - "project": ["./services/frontend/tsconfig.json", "./services/frontend/tsconfig.node.json"] - }, - "rules": { - "@typescript-eslint/no-explicit-any": "off", - "@typescript-eslint/no-unnecessary-type-assertion": "error", - "import/no-unused-modules": [ - "error", - { - "missingExports": true, - "unusedExports": true - } - ], - "import/prefer-default-export": "off", - "react/require-default-props": "off" - } - }, - { - "files": ["**/*.js", "**/*.jsx"], - "rules": { - "import/no-unused-modules": "off" - } - } - ], - "rules": { - "camelcase": "error", - "consistent-return": "error", - "import/no-commonjs": "error", - "import/no-default-export": "error", - "import/no-unused-modules": ["error", { "missingExports": true, "unusedExports": true }], - "import/order": [ - "error", - { - "alphabetize": { "order": "asc", "caseInsensitive": true }, - "groups": ["builtin", "external", "internal", "parent", "sibling"], - "pathGroups": [{ "pattern": "@/**", "group": "internal", "position": "before" }] - } - ], - "import/prefer-default-export": "off", - "jsx-a11y/click-events-have-key-events": "off", - "jsx-a11y/label-has-associated-control": "off", - "jsx-a11y/label-has-for": "off", - "jsx-a11y/no-static-element-interactions": "off", - "no-async-promise-executor": "error", - "no-await-in-loop": "error", - "no-implied-eval": "off", - "no-param-reassign": ["error", { "props": false }], - "no-promise-executor-return": "error", - "no-return-await": "error", - "react/forbid-prop-types": "off", - "react/function-component-definition": [ - "error", - { "namedComponents": "arrow-function", "unnamedComponents": "arrow-function" } - ], - "react/jsx-filename-extension": ["error", { "allow": "as-needed" }], - "react/jsx-key": "error", - "react/jsx-no-constructed-context-values": "off", - "react/jsx-props-no-spreading": "off", - "react/jsx-sort-props": ["error", { "reservedFirst": false }], - "react/no-unescaped-entities": "off", - "react/no-unknown-property": "off", - "react/no-unstable-nested-components": "off", - "react/prefer-stateless-function": "error", - "react/prop-types": "off", - "react-hooks/rules-of-hooks": "error" - }, - "plugins": ["react", "react-hooks"], - "settings": { - "import/resolver": { - "eslint-import-resolver-custom-alias": { - "alias": { - "@": "./services/frontend/src" - }, - "extensions": [".js", ".jsx", ".ts", ".tsx"] - } - }, - "react": { - "version": "18.2.0" - } - } -} diff --git a/services/frontend/src/components/CourseStatistics/CourseTable/index.jsx b/services/frontend/src/components/CourseStatistics/CourseTable/index.jsx index 075e1f5ea7..90e4d4a85e 100644 --- a/services/frontend/src/components/CourseStatistics/CourseTable/index.jsx +++ b/services/frontend/src/components/CourseStatistics/CourseTable/index.jsx @@ -54,7 +54,7 @@ CourseTable.propTypes = { onSelectCourse: func.isRequired, hidden: bool.isRequired, title: string.isRequired, - // eslint-disable-next-line react/require-default-props + controlIcon: string, } diff --git a/services/frontend/src/components/CourseStatistics/ResultTabs/panes/util.ts b/services/frontend/src/components/CourseStatistics/ResultTabs/panes/util.ts index d964807d61..4d9e413106 100644 --- a/services/frontend/src/components/CourseStatistics/ResultTabs/panes/util.ts +++ b/services/frontend/src/components/CourseStatistics/ResultTabs/panes/util.ts @@ -33,33 +33,27 @@ export const isThesisGrades = (grades: Record) => { } const isThesisSeries = (series: Array>) => { - return series && series.some(record => isThesisGrades(record)) + return series?.some(record => isThesisGrades(record)) } const isSecondNationalLanguageSeries = (series: Array>) => { - return ( - series && - series.every(record => { - const grades = Object.keys(record) - const hasPassFailGrades = grades.some(grade => PASS_FAIL_GRADES.includes(grade)) - const hasNumericGrades = grades.some(grade => NUMERIC_GRADES.includes(grade)) - const hasSecondNationalLanguageGrades = grades.some(grade => SECOND_NATIONAL_LANGUAGE_GRADES.includes(grade)) - return !hasNumericGrades && hasPassFailGrades && hasSecondNationalLanguageGrades - }) - ) + return series?.every(record => { + const grades = Object.keys(record) + const hasPassFailGrades = grades.some(grade => PASS_FAIL_GRADES.includes(grade)) + const hasNumericGrades = grades.some(grade => NUMERIC_GRADES.includes(grade)) + const hasSecondNationalLanguageGrades = grades.some(grade => SECOND_NATIONAL_LANGUAGE_GRADES.includes(grade)) + return !hasNumericGrades && hasPassFailGrades && hasSecondNationalLanguageGrades + }) } const isPassFailSeries = (series: Array>) => { - return ( - series && - series.every(record => { - const grades = Object.keys(record) - const hasPassFailGrades = grades.some(grade => PASS_FAIL_GRADES.includes(grade)) - const hasNumericGrades = grades.some(grade => NUMERIC_GRADES.includes(grade)) - const hasSecondNationalLanguageGrades = grades.some(grade => SECOND_NATIONAL_LANGUAGE_GRADES.includes(grade)) - return !hasNumericGrades && hasPassFailGrades && !hasSecondNationalLanguageGrades - }) - ) + return series?.every(record => { + const grades = Object.keys(record) + const hasPassFailGrades = grades.some(grade => PASS_FAIL_GRADES.includes(grade)) + const hasNumericGrades = grades.some(grade => NUMERIC_GRADES.includes(grade)) + const hasSecondNationalLanguageGrades = grades.some(grade => SECOND_NATIONAL_LANGUAGE_GRADES.includes(grade)) + return !hasNumericGrades && hasPassFailGrades && !hasSecondNationalLanguageGrades + }) } export const getSeriesType = (series: Array>) => { diff --git a/services/frontend/src/components/CreditAccumulationGraphHighCharts/index.jsx b/services/frontend/src/components/CreditAccumulationGraphHighCharts/index.jsx index 1552de9ae5..cc3a96c0aa 100644 --- a/services/frontend/src/components/CreditAccumulationGraphHighCharts/index.jsx +++ b/services/frontend/src/components/CreditAccumulationGraphHighCharts/index.jsx @@ -1,4 +1,3 @@ -/* eslint-disable camelcase */ import exportData from 'highcharts/modules/export-data' import exporting from 'highcharts/modules/exporting' import { chain, flatten, flow } from 'lodash' diff --git a/services/frontend/src/components/FacultyStatistics/TimesAndPaths/MedianBarChart.jsx b/services/frontend/src/components/FacultyStatistics/TimesAndPaths/MedianBarChart.jsx index 9d11901736..017a56e242 100644 --- a/services/frontend/src/components/FacultyStatistics/TimesAndPaths/MedianBarChart.jsx +++ b/services/frontend/src/components/FacultyStatistics/TimesAndPaths/MedianBarChart.jsx @@ -27,17 +27,17 @@ export const MedianBarChart = ({ if (!facultyGraph && goalExceptions.needed && ['master', 'bcMsCombo'].includes(level)) { // change colors for longer medicine goal times modData = JSON.parse(JSON.stringify(data)) - for (let i = 0; i < modData.length; i++) { - if (Object.keys(goalExceptions).includes(modData[i].code)) { - const realGoal = goal + goalExceptions[modData[i].code] - if (modData[i].median <= realGoal) { - modData[i].color = '#90A959' - } else if (modData[i].median <= realGoal + 12) { - modData[i].color = '#FEE191' + for (const data of modData) { + if (Object.keys(goalExceptions).includes(data.code)) { + const realGoal = goal + goalExceptions[data.code] + if (data.median <= realGoal) { + data.color = '#90A959' + } else if (data.median <= realGoal + 12) { + data.color = '#FEE191' } else { - modData[i].color = '#FB6962' + data.color = '#FB6962' } - modData[i].realGoal = realGoal + data.realGoal = realGoal } } } diff --git a/services/frontend/src/components/FacultyStatistics/facultyHelpers.ts b/services/frontend/src/components/FacultyStatistics/facultyHelpers.ts index ad6e3993ee..7a852405b3 100644 --- a/services/frontend/src/components/FacultyStatistics/facultyHelpers.ts +++ b/services/frontend/src/components/FacultyStatistics/facultyHelpers.ts @@ -53,8 +53,8 @@ const isBetween = (number: number, lowerLimit: number, upperLimit: number) => { export const calculateStats = ( creditCounts: Record, maximumAmountOfCredits: number, - minimumAmountOfCredits: number = 0, - numberOfCreditCategories: number = 7 + minimumAmountOfCredits = 0, + numberOfCreditCategories = 7 ) => { const tableStats: Array> = [] if (creditCounts === undefined) { @@ -74,26 +74,26 @@ export const calculateStats = ( minimumAmountOfCredits ) const tableTitles = ['', 'All'] - for (let i = 0; i < limits.length; i++) { - if (limits[i][0] === undefined) tableTitles.push(`< ${limits[i][1]} credits`) - else if (limits[i][1] === undefined) tableTitles.push(`≥ ${limits[i][0]} credits`) - else tableTitles.push(`${limits[i][0]}–${limits[i][1]} credits`) + for (const limit of limits) { + if (limit[0] === undefined) tableTitles.push(`< ${limit[1]} credits`) + else if (limit[1] === undefined) tableTitles.push(`≥ ${limit[0]} credits`) + else tableTitles.push(`${limit[0]}–${limit[1]} credits`) } Object.keys(creditCounts).forEach(year => { const yearCreditCount = creditCounts[year] const yearCounts = [year, yearCreditCount.length] tableStats.push(yearCounts) - for (let i = 0; i < limits.length; i++) { - yearCounts.push(yearCreditCount.filter(credits => isBetween(credits, limits[i][0], limits[i][1])).length) + for (const limit of limits) { + yearCounts.push(yearCreditCount.filter(credits => isBetween(credits, limit[0], limit[1])).length) } }) const totalCounts: Array = ['Total'] for (let i = 1; i < tableStats[0].length; i++) { let columnSum = 0 - for (let j = 0; j < tableStats.length; j++) { - columnSum += tableStats[j][i] as number + for (const stats of tableStats) { + columnSum += stats[i] as number } totalCounts.push(columnSum) } diff --git a/services/frontend/src/components/FilterView/filters/date/index.jsx b/services/frontend/src/components/FilterView/filters/date/index.jsx index f1218a1a62..8fc386f5a5 100644 --- a/services/frontend/src/components/FilterView/filters/date/index.jsx +++ b/services/frontend/src/components/FilterView/filters/date/index.jsx @@ -61,7 +61,6 @@ export const creditDateFilter = createFilter({ }, selectors: { - // eslint-disable-next-line no-unused-vars selectedStartDate: ({ startDate }, _) => startDate, }, diff --git a/services/frontend/src/components/LanguagePicker/index.jsx b/services/frontend/src/components/LanguagePicker/index.jsx deleted file mode 100644 index 7ab00d08bb..0000000000 --- a/services/frontend/src/components/LanguagePicker/index.jsx +++ /dev/null @@ -1,31 +0,0 @@ -import { Dropdown } from 'semantic-ui-react' - -import { LANGUAGE_CODES } from '@/shared/language' -import { useLanguage } from './useLanguage' - -export const LanguagePicker = () => { - const { language, setLanguage } = useLanguage() - - const onChange = (_, { value }) => setLanguage(value) - - const options = LANGUAGE_CODES.map(code => ({ - key: code, - text: code.toUpperCase(), - value: code, - })) - - return ( - - ) -} diff --git a/services/frontend/src/components/PopulationStudents/index.jsx b/services/frontend/src/components/PopulationStudents/index.jsx index 88d4efb734..2be75cfe3e 100644 --- a/services/frontend/src/components/PopulationStudents/index.jsx +++ b/services/frontend/src/components/PopulationStudents/index.jsx @@ -145,7 +145,7 @@ const PopulationStudents = ({ const programmes = studyGuidanceGroup.tags.studyProgramme.includes('+') ? studyGuidanceGroup.tags.studyProgramme.split('+') : [studyGuidanceGroup.tags.studyProgramme] - // eslint-disable-next-line prefer-destructuring + mainProgramme = programmes[0] combinedProgramme = programmes.length > 1 ? programmes[1] : '' } diff --git a/services/frontend/src/components/SortableTable/columnHeader.jsx b/services/frontend/src/components/SortableTable/columnHeader.jsx index 6e7c518c2e..94d566ee92 100644 --- a/services/frontend/src/components/SortableTable/columnHeader.jsx +++ b/services/frontend/src/components/SortableTable/columnHeader.jsx @@ -1,4 +1,3 @@ -/* eslint-disable no-return-assign */ import { produce } from 'immer' import { chain, clone, includes, range, toPairs } from 'lodash' import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react' diff --git a/services/frontend/src/components/SortableTable/visitors/DataVisitor.js b/services/frontend/src/components/SortableTable/visitors/DataVisitor.js index a12faf7e41..1216bcd2ae 100644 --- a/services/frontend/src/components/SortableTable/visitors/DataVisitor.js +++ b/services/frontend/src/components/SortableTable/visitors/DataVisitor.js @@ -1,4 +1,3 @@ -/* eslint-disable max-classes-per-file */ /* eslint-disable class-methods-use-this */ import { getDataItemType, DataItemType } from '@/components/SortableTable/common' diff --git a/services/frontend/src/components/StudyProgramme/MedianTimeBarChart.tsx b/services/frontend/src/components/StudyProgramme/MedianTimeBarChart.tsx index 342d3252c4..e0e78da3d4 100644 --- a/services/frontend/src/components/StudyProgramme/MedianTimeBarChart.tsx +++ b/services/frontend/src/components/StudyProgramme/MedianTimeBarChart.tsx @@ -1,5 +1,3 @@ -/* eslint-disable func-names */ -/* eslint-disable object-shorthand */ /* eslint-disable react/no-this-in-sfc */ import accessibility from 'highcharts/modules/accessibility' import exportData from 'highcharts/modules/export-data' @@ -76,7 +74,7 @@ export const MedianTimeBarChart = ({ byStartYear, data, goal, title }: MedianTim tooltip: { backgroundColor: 'white', fontSize: '25px', - formatter: function (this: { + formatter(this: { y: number point: { amount: number; name: string; statistics: Statistics; classSize: number } }) { @@ -103,7 +101,7 @@ export const MedianTimeBarChart = ({ byStartYear, data, goal, title }: MedianTim style: { textOutline: 'none', }, - formatter: function (this: { point: { amount: number; classSize: number } }) { + formatter(this: { point: { amount: number; classSize: number } }) { return getDataLabel(this.point.amount, this.point.classSize) }, }, diff --git a/services/frontend/src/components/StudyProgramme/StudyTrackOverview/BarChart.tsx b/services/frontend/src/components/StudyProgramme/StudyTrackOverview/BarChart.tsx index a4f689dab1..472934b582 100644 --- a/services/frontend/src/components/StudyProgramme/StudyTrackOverview/BarChart.tsx +++ b/services/frontend/src/components/StudyProgramme/StudyTrackOverview/BarChart.tsx @@ -18,7 +18,7 @@ interface BarChartProps { } export const BarChart = ({ data, track }: BarChartProps) => { - if (!data || !data.creditGraphStats || !data.creditGraphStats[track]) { + if (!data?.creditGraphStats?.[track]) { return null } diff --git a/services/frontend/src/components/StudyProgramme/StudyTrackOverview/BasicDataTable.tsx b/services/frontend/src/components/StudyProgramme/StudyTrackOverview/BasicDataTable.tsx index ef7b878747..c706f58979 100644 --- a/services/frontend/src/components/StudyProgramme/StudyTrackOverview/BasicDataTable.tsx +++ b/services/frontend/src/components/StudyProgramme/StudyTrackOverview/BasicDataTable.tsx @@ -7,7 +7,7 @@ interface BasicDataTableProps { } export const BasicDataTable = ({ data, titles, track }: BasicDataTableProps) => { - if (!data || !data[track]?.length || !titles) { + if (!data?.[track]?.length || !titles) { return null } diff --git a/services/frontend/src/components/Teachers/TeacherLeaderBoard/LeaderForm.jsx b/services/frontend/src/components/Teachers/TeacherLeaderBoard/LeaderForm.jsx index 50e096ebdf..eb1f79506f 100644 --- a/services/frontend/src/components/Teachers/TeacherLeaderBoard/LeaderForm.jsx +++ b/services/frontend/src/components/Teachers/TeacherLeaderBoard/LeaderForm.jsx @@ -70,6 +70,6 @@ LeaderForm.propTypes = { initLeaderboard: func.isRequired, handleCategoryChange: func.isRequired, handleYearChange: func.isRequired, - selectedcategory: string, // eslint-disable-line - selectedyear: number, // eslint-disable-line + selectedcategory: string, + selectedyear: number, } diff --git a/services/frontend/src/conf.js b/services/frontend/src/conf.js index 10a19ca10d..158eb5a41e 100644 --- a/services/frontend/src/conf.js +++ b/services/frontend/src/conf.js @@ -9,14 +9,6 @@ export const sentryEnvironment = process.env.REACT_APP_SENTRY_ENVIRONMENT || '' export const sentryDSN = process.env.REACT_APP_SENTRY_DSN || '' export const runningInCypress = typeof window !== 'undefined' && !!window.Cypress -// Adminer is only used in dev mode, imo hardcoding this url here is ok. -const adminerBaseUrl = 'http://localhost:5050' -const databaseNames = ['kone-db', 'sis-db', 'sis-importer-db', 'user-db'] -export const adminerUrls = databaseNames.map(db => ({ - url: `${adminerBaseUrl}/?pgsql=${db}&username=postgres`, - text: db, -})) - // Base paths export const basePath = process.env.PUBLIC_URL || '' export const apiBasePath = `${basePath}/api` diff --git a/services/frontend/src/main.jsx b/services/frontend/src/main.jsx index b0e941f037..13ed5c421d 100644 --- a/services/frontend/src/main.jsx +++ b/services/frontend/src/main.jsx @@ -1,3 +1,4 @@ +// eslint-disable-next-line import/no-unused-modules import { createRoot } from 'react-dom/client' import { Provider } from 'react-redux' import { BrowserRouter } from 'react-router-dom' diff --git a/services/frontend/tsconfig.node.json b/services/frontend/tsconfig.node.json index 9b5382045c..f31b6cab1e 100644 --- a/services/frontend/tsconfig.node.json +++ b/services/frontend/tsconfig.node.json @@ -5,7 +5,8 @@ "module": "ESNext", "moduleResolution": "bundler", "allowSyntheticDefaultImports": true, - "strict": false + "strict": false, + "strictNullChecks": true }, "include": ["vite.config.ts"] } diff --git a/services/frontend/vite.config.ts b/services/frontend/vite.config.ts index aa1271bdd9..6a6244dfe6 100644 --- a/services/frontend/vite.config.ts +++ b/services/frontend/vite.config.ts @@ -1,6 +1,6 @@ /* eslint-disable import/no-extraneous-dependencies */ -import path from 'path' import react from '@vitejs/plugin-react-swc' +import path from 'path' import { defineConfig } from 'vite' import { inStaging } from './src/conf' diff --git a/updater/sis-updater-scheduler/src/scheduler.js b/updater/sis-updater-scheduler/src/scheduler.js index 43241729ec..26b5e7387a 100644 --- a/updater/sis-updater-scheduler/src/scheduler.js +++ b/updater/sis-updater-scheduler/src/scheduler.js @@ -1,4 +1,5 @@ const { eachLimit } = require('async') +// eslint-disable-next-line no-redeclare const crypto = require('crypto') const { chunk } = require('lodash') diff --git a/updater/sis-updater-worker/src/db/migrations/20200306_00_fix_constraints.js b/updater/sis-updater-worker/src/db/migrations/20200306_00_fix_constraints.js index 442154c454..0b85542282 100644 --- a/updater/sis-updater-worker/src/db/migrations/20200306_00_fix_constraints.js +++ b/updater/sis-updater-worker/src/db/migrations/20200306_00_fix_constraints.js @@ -1,14 +1,14 @@ module.exports = { up: async queryInterface => { // STUDYRIGHT - await queryInterface.sequelize.query(`alter table studyright drop constraint studyright_extentcode_fkey`) + await queryInterface.sequelize.query('alter table studyright drop constraint studyright_extentcode_fkey') await queryInterface.sequelize.query( `alter table studyright add constraint studyright_extentcode_fkey foreign key("extentcode") references "studyright_extents" ("extentcode") on delete cascade on update cascade` ) - await queryInterface.sequelize.query(`alter table studyright drop constraint studyright_student_studentnumber_fkey`) + await queryInterface.sequelize.query('alter table studyright drop constraint studyright_student_studentnumber_fkey') await queryInterface.sequelize.query( `alter table studyright add constraint studyright_student_studentnumber_fkey foreign key("student_studentnumber") references "student" ("studentnumber") @@ -17,7 +17,7 @@ module.exports = { // STUDYRIGHT_ELEMENTS await queryInterface.sequelize.query( - `alter table studyright_elements drop constraint studyright_elements_code_fkey` + 'alter table studyright_elements drop constraint studyright_elements_code_fkey' ) await queryInterface.sequelize.query( `alter table studyright_elements @@ -26,7 +26,7 @@ module.exports = { ) await queryInterface.sequelize.query( - `alter table studyright_elements drop constraint studyright_elements_studentnumber_fkey` + 'alter table studyright_elements drop constraint studyright_elements_studentnumber_fkey' ) await queryInterface.sequelize.query( `alter table studyright_elements @@ -35,7 +35,7 @@ module.exports = { ) await queryInterface.sequelize.query( - `alter table studyright_elements drop constraint studyright_elements_studyrightid_fkey` + 'alter table studyright_elements drop constraint studyright_elements_studyrightid_fkey' ) await queryInterface.sequelize.query( `alter table studyright_elements @@ -44,28 +44,28 @@ module.exports = { ) // CREDIT - await queryInterface.sequelize.query(`alter table credit drop constraint credit_course_id_fkey`) + await queryInterface.sequelize.query('alter table credit drop constraint credit_course_id_fkey') await queryInterface.sequelize.query( `alter table credit add constraint credit_course_id_fkey foreign key("course_id") references "course" ("id") on delete cascade on update cascade` ) - await queryInterface.sequelize.query(`alter table credit drop constraint credit_credittypecode_fkey`) + await queryInterface.sequelize.query('alter table credit drop constraint credit_credittypecode_fkey') await queryInterface.sequelize.query( `alter table credit add constraint credit_credittypecode_fkey foreign key("credittypecode") references "credit_types" ("credittypecode") on delete cascade on update cascade` ) - await queryInterface.sequelize.query(`alter table credit drop constraint credit_semester_composite_fkey`) + await queryInterface.sequelize.query('alter table credit drop constraint credit_semester_composite_fkey') await queryInterface.sequelize.query( `alter table credit add constraint credit_semester_composite_fkey foreign key("semester_composite") references "semesters" ("composite") on delete cascade on update cascade` ) - await queryInterface.sequelize.query(`alter table credit drop constraint credit_student_studentnumber_fkey`) + await queryInterface.sequelize.query('alter table credit drop constraint credit_student_studentnumber_fkey') await queryInterface.sequelize.query( `alter table credit add constraint credit_student_studentnumber_fkey foreign key("student_studentnumber") references "student" ("studentnumber") diff --git a/updater/sis-updater-worker/src/db/migrations/20240827_00_remove_studyright_id_from_studyplans.js b/updater/sis-updater-worker/src/db/migrations/20240827_00_remove_studyright_id_from_studyplans.js index 7ca3de8e6b..c4b713db6f 100644 --- a/updater/sis-updater-worker/src/db/migrations/20240827_00_remove_studyright_id_from_studyplans.js +++ b/updater/sis-updater-worker/src/db/migrations/20240827_00_remove_studyright_id_from_studyplans.js @@ -1,3 +1,5 @@ +const { STRING } = require('sequelize') + module.exports = { up: async queryInterface => { await queryInterface.removeColumn('studyplan', 'studyrightid') diff --git a/updater/sis-updater-worker/src/updater/updateMeta.js b/updater/sis-updater-worker/src/updater/updateMeta.js index 660665b77f..72348abdbf 100644 --- a/updater/sis-updater-worker/src/updater/updateMeta.js +++ b/updater/sis-updater-worker/src/updater/updateMeta.js @@ -123,7 +123,7 @@ const updateCourses = async (courseIdToAttainments, groupIdToCourse) => { const sortedSubstitutions = [course.code, ...course.substitutions] .map(code => [code, getSubstitutionPriority(code)]) .sort((a, b) => b[1] - a[1]) - // eslint-disable-next-line prefer-destructuring + course.mainCourseCode = sortedSubstitutions[0][0] } diff --git a/updater/sis-updater-worker/src/updater/updateStudents/attainments.js b/updater/sis-updater-worker/src/updater/updateStudents/attainments.js index d7c36c4f84..519cc07a05 100644 --- a/updater/sis-updater-worker/src/updater/updateStudents/attainments.js +++ b/updater/sis-updater-worker/src/updater/updateStudents/attainments.js @@ -253,12 +253,11 @@ const updateAttainments = async ( if (!codeParts.length) return attainmentIdCodeMap let parsedCourseCode = '' - // eslint-disable-next-line prefer-destructuring + if (codeParts.length === 1) parsedCourseCode = codeParts[0] else if (codeParts[1].length < 7) { parsedCourseCode = `${codeParts[0]}-${codeParts[1]}` } else { - // eslint-disable-next-line prefer-destructuring parsedCourseCode = codeParts[0] } return { ...attainmentIdCodeMap, [att.id]: parsedCourseCode }