diff --git a/.github/workflows/eslint.yml b/.github/workflows/eslint.yml index 40367209f..60a9b9f60 100644 --- a/.github/workflows/eslint.yml +++ b/.github/workflows/eslint.yml @@ -15,3 +15,5 @@ jobs: run: cd app && yarn install --frozen-lockfile - name: Run linter run: cd app && yarn lint + - name: Run type checking + run: cd app && yarn type-check diff --git a/app/.eslintrc.js b/app/.eslintrc.js deleted file mode 100644 index e703f8219..000000000 --- a/app/.eslintrc.js +++ /dev/null @@ -1,26 +0,0 @@ -module.exports = { - root: true, - env: { - es2021: true, - node: true, - }, - extends: [ - 'plugin:vue/vue3-recommended', - 'eslint:recommended', - '@vue/eslint-config-typescript', - 'plugin:prettier/recommended', - ], - rules: { - 'vue/no-v-html': 'off', - 'no-unused-vars': 'off', - '@typescript-eslint/no-unused-vars': [ - 'warn', - { - varsIgnorePattern: '^_', - argsIgnorePattern: '^_', - destructuredArrayIgnorePattern: '^_', - }, - ], - 'no-console': ['error', { allow: ['warn', 'error'] }], - }, -} diff --git a/app/components.d.ts b/app/components.d.ts index 6c78a9eb6..02e15a179 100644 --- a/app/components.d.ts +++ b/app/components.d.ts @@ -9,67 +9,67 @@ declare module 'vue' { export interface GlobalComponents { AdressItem: typeof import('./src/components/globals/formItems/AdressItem.vue')['default'] AppCatalogSkeleton: typeof import('./src/components/globals/skeletons/AppCatalogSkeleton.vue')['default'] - BAccordion: typeof import('bootstrap-vue-next')['BAccordion'] - BAccordionItem: typeof import('bootstrap-vue-next')['BAccordionItem'] - BBadge: typeof import('bootstrap-vue-next')['BBadge'] - BBreadcrumb: typeof import('bootstrap-vue-next')['BBreadcrumb'] - BBreadcrumbItem: typeof import('bootstrap-vue-next')['BBreadcrumbItem'] - BButton: typeof import('bootstrap-vue-next')['BButton'] - BButtonGroup: typeof import('bootstrap-vue-next')['BButtonGroup'] - BButtonToolbar: typeof import('bootstrap-vue-next')['BButtonToolbar'] - BCard: typeof import('bootstrap-vue-next')['BCard'] - BCardBody: typeof import('bootstrap-vue-next')['BCardBody'] - BCardGroup: typeof import('bootstrap-vue-next')['BCardGroup'] - BCardHeader: typeof import('bootstrap-vue-next')['BCardHeader'] - BCardText: typeof import('bootstrap-vue-next')['BCardText'] - BCardTitle: typeof import('bootstrap-vue-next')['BCardTitle'] - BCol: typeof import('bootstrap-vue-next')['BCol'] - BCollapse: typeof import('bootstrap-vue-next')['BCollapse'] - BDropdown: typeof import('bootstrap-vue-next')['BDropdown'] - BDropdownDivider: typeof import('bootstrap-vue-next')['BDropdownDivider'] - BDropdownForm: typeof import('bootstrap-vue-next')['BDropdownForm'] - BDropdownGroup: typeof import('bootstrap-vue-next')['BDropdownGroup'] - BDropdownItem: typeof import('bootstrap-vue-next')['BDropdownItem'] - BDropdownItemButton: typeof import('bootstrap-vue-next')['BDropdownItemButton'] - BDropdownText: typeof import('bootstrap-vue-next')['BDropdownText'] - BForm: typeof import('bootstrap-vue-next')['BForm'] - BFormCheckbox: typeof import('bootstrap-vue-next')['BFormCheckbox'] - BFormCheckboxGroup: typeof import('bootstrap-vue-next')['BFormCheckboxGroup'] - BFormFile: typeof import('bootstrap-vue-next')['BFormFile'] - BFormGroup: typeof import('bootstrap-vue-next')['BFormGroup'] - BFormInput: typeof import('bootstrap-vue-next')['BFormInput'] - BFormInvalidFeedback: typeof import('bootstrap-vue-next')['BFormInvalidFeedback'] - BFormRadio: typeof import('bootstrap-vue-next')['BFormRadio'] - BFormRadioGroup: typeof import('bootstrap-vue-next')['BFormRadioGroup'] - BFormSelect: typeof import('bootstrap-vue-next')['BFormSelect'] - BFormSelectOption: typeof import('bootstrap-vue-next')['BFormSelectOption'] - BFormTag: typeof import('bootstrap-vue-next')['BFormTag'] - BFormTags: typeof import('bootstrap-vue-next')['BFormTags'] - BFormTextarea: typeof import('bootstrap-vue-next')['BFormTextarea'] - BImg: typeof import('bootstrap-vue-next')['BImg'] - BInputGroup: typeof import('bootstrap-vue-next')['BInputGroup'] - BInputGroupText: typeof import('bootstrap-vue-next')['BInputGroupText'] - BLink: typeof import('bootstrap-vue-next')['BLink'] - BListGroup: typeof import('bootstrap-vue-next')['BListGroup'] - BListGroupItem: typeof import('bootstrap-vue-next')['BListGroupItem'] - BModal: typeof import('bootstrap-vue-next')['BModal'] - BModalOrchestrator: typeof import('bootstrap-vue-next')['BModalOrchestrator'] - BNav: typeof import('bootstrap-vue-next')['BNav'] - BNavbar: typeof import('bootstrap-vue-next')['BNavbar'] - BNavbarBrand: typeof import('bootstrap-vue-next')['BNavbarBrand'] - BNavbarNav: typeof import('bootstrap-vue-next')['BNavbarNav'] - BNavItem: typeof import('bootstrap-vue-next')['BNavItem'] - BNavText: typeof import('bootstrap-vue-next')['BNavText'] - BOverlay: typeof import('bootstrap-vue-next')['BOverlay'] - BPopover: typeof import('bootstrap-vue-next')['BPopover'] - BProgress: typeof import('bootstrap-vue-next')['BProgress'] - BProgressBar: typeof import('bootstrap-vue-next')['BProgressBar'] - BRow: typeof import('bootstrap-vue-next')['BRow'] + BAccordion: typeof import('bootstrap-vue-next/components/BAccordion')['BAccordion'] + BAccordionItem: typeof import('bootstrap-vue-next/components/BAccordion')['BAccordionItem'] + BBadge: typeof import('bootstrap-vue-next/components/BBadge')['BBadge'] + BBreadcrumb: typeof import('bootstrap-vue-next/components/BBreadcrumb')['BBreadcrumb'] + BBreadcrumbItem: typeof import('bootstrap-vue-next/components/BBreadcrumb')['BBreadcrumbItem'] + BButton: typeof import('bootstrap-vue-next/components/BButton')['BButton'] + BButtonGroup: typeof import('bootstrap-vue-next/components/BButton')['BButtonGroup'] + BButtonToolbar: typeof import('bootstrap-vue-next/components/BButton')['BButtonToolbar'] + BCard: typeof import('bootstrap-vue-next/components/BCard')['BCard'] + BCardBody: typeof import('bootstrap-vue-next/components/BCard')['BCardBody'] + BCardGroup: typeof import('bootstrap-vue-next/components/BCard')['BCardGroup'] + BCardHeader: typeof import('bootstrap-vue-next/components/BCard')['BCardHeader'] + BCardText: typeof import('bootstrap-vue-next/components/BCard')['BCardText'] + BCardTitle: typeof import('bootstrap-vue-next/components/BCard')['BCardTitle'] + BCol: typeof import('bootstrap-vue-next/components/BContainer')['BCol'] + BCollapse: typeof import('bootstrap-vue-next/components/BCollapse')['BCollapse'] + BDropdown: typeof import('bootstrap-vue-next/components/BDropdown')['BDropdown'] + BDropdownDivider: typeof import('bootstrap-vue-next/components/BDropdown')['BDropdownDivider'] + BDropdownForm: typeof import('bootstrap-vue-next/components/BDropdown')['BDropdownForm'] + BDropdownGroup: typeof import('bootstrap-vue-next/components/BDropdown')['BDropdownGroup'] + BDropdownItem: typeof import('bootstrap-vue-next/components/BDropdown')['BDropdownItem'] + BDropdownItemButton: typeof import('bootstrap-vue-next/components/BDropdown')['BDropdownItemButton'] + BDropdownText: typeof import('bootstrap-vue-next/components/BDropdown')['BDropdownText'] + BForm: typeof import('bootstrap-vue-next/components/BForm')['BForm'] + BFormCheckbox: typeof import('bootstrap-vue-next/components/BFormCheckbox')['BFormCheckbox'] + BFormCheckboxGroup: typeof import('bootstrap-vue-next/components/BFormCheckbox')['BFormCheckboxGroup'] + BFormFile: typeof import('bootstrap-vue-next/components/BFormFile')['BFormFile'] + BFormGroup: typeof import('bootstrap-vue-next/components/BFormGroup')['BFormGroup'] + BFormInput: typeof import('bootstrap-vue-next/components/BFormInput')['BFormInput'] + BFormInvalidFeedback: typeof import('bootstrap-vue-next/components/BForm')['BFormInvalidFeedback'] + BFormRadio: typeof import('bootstrap-vue-next/components/BFormRadio')['BFormRadio'] + BFormRadioGroup: typeof import('bootstrap-vue-next/components/BFormRadio')['BFormRadioGroup'] + BFormSelect: typeof import('bootstrap-vue-next/components/BFormSelect')['BFormSelect'] + BFormSelectOption: typeof import('bootstrap-vue-next/components/BFormSelect')['BFormSelectOption'] + BFormTag: typeof import('bootstrap-vue-next/components/BFormTags')['BFormTag'] + BFormTags: typeof import('bootstrap-vue-next/components/BFormTags')['BFormTags'] + BFormTextarea: typeof import('bootstrap-vue-next/components/BFormTextarea')['BFormTextarea'] + BImg: typeof import('bootstrap-vue-next/components/BImg')['BImg'] + BInputGroup: typeof import('bootstrap-vue-next/components/BInputGroup')['BInputGroup'] + BInputGroupText: typeof import('bootstrap-vue-next/components/BInputGroup')['BInputGroupText'] + BLink: typeof import('bootstrap-vue-next/components/BLink')['BLink'] + BListGroup: typeof import('bootstrap-vue-next/components/BListGroup')['BListGroup'] + BListGroupItem: typeof import('bootstrap-vue-next/components/BListGroup')['BListGroupItem'] + BModal: typeof import('bootstrap-vue-next/components/BModal')['BModal'] + BModalOrchestrator: typeof import('bootstrap-vue-next/components/BModal')['BModalOrchestrator'] + BNav: typeof import('bootstrap-vue-next/components/BNav')['BNav'] + BNavbar: typeof import('bootstrap-vue-next/components/BNavbar')['BNavbar'] + BNavbarBrand: typeof import('bootstrap-vue-next/components/BNavbar')['BNavbarBrand'] + BNavbarNav: typeof import('bootstrap-vue-next/components/BNavbar')['BNavbarNav'] + BNavItem: typeof import('bootstrap-vue-next/components/BNav')['BNavItem'] + BNavText: typeof import('bootstrap-vue-next/components/BNav')['BNavText'] + BOverlay: typeof import('bootstrap-vue-next/components/BOverlay')['BOverlay'] + BPopover: typeof import('bootstrap-vue-next/components/BPopover')['BPopover'] + BProgress: typeof import('bootstrap-vue-next/components/BProgress')['BProgress'] + BProgressBar: typeof import('bootstrap-vue-next/components/BProgress')['BProgressBar'] + BRow: typeof import('bootstrap-vue-next/components/BContainer')['BRow'] BSkeleton: typeof import('./src/components/globals/skeletons/BSkeleton.vue')['default'] BSkeletonWrapper: typeof import('./src/components/globals/skeletons/BSkeletonWrapper.vue')['default'] - BTab: typeof import('bootstrap-vue-next')['BTab'] - BTable: typeof import('bootstrap-vue-next')['BTable'] - BTabs: typeof import('bootstrap-vue-next')['BTabs'] + BTab: typeof import('bootstrap-vue-next/components/BTabs')['BTab'] + BTable: typeof import('bootstrap-vue-next/components/BTable')['BTable'] + BTabs: typeof import('bootstrap-vue-next/components/BTabs')['BTabs'] ButtonItem: typeof import('./src/components/globals/formItems/ButtonItem.vue')['default'] CardCollapse: typeof import('./src/components/CardCollapse.vue')['default'] CardDeckFeed: typeof import('./src/components/CardDeckFeed.vue')['default'] @@ -118,9 +118,7 @@ declare module 'vue' { YSpinner: typeof import('./src/components/globals/YSpinner.vue')['default'] } export interface ComponentCustomProperties { - vBModal: typeof import('bootstrap-vue-next')['vBModal'] - vBPopover: typeof import('bootstrap-vue-next')['vBPopover'] - vBToggle: typeof import('bootstrap-vue-next')['vBToggle'] - vBTooltip: typeof import('bootstrap-vue-next')['vBTooltip'] + vBModal: typeof import('bootstrap-vue-next/directives/BModal')['vBModal'] + vBToggle: typeof import('bootstrap-vue-next/directives/BToggle')['vBToggle'] } } diff --git a/app/eslint.config.mjs b/app/eslint.config.mjs new file mode 100644 index 000000000..352904405 --- /dev/null +++ b/app/eslint.config.mjs @@ -0,0 +1,41 @@ +import pluginVue from 'eslint-plugin-vue' +import vueTsEslintConfig from '@vue/eslint-config-typescript' +import skipFormatting from '@vue/eslint-config-prettier/skip-formatting' + +export default [ + { + name: 'app/files-to-lint', + files: ['**/*.{ts,js,vue}'], + }, + + { + name: 'app/files-to-ignore', + ignores: ['**/dist/**', '**/dist-ssr/**', '**/coverage/**'], + }, + + { + name: 'custom-ignore', + ignores: ['**/src/types/data/**'], + }, + + ...pluginVue.configs['flat/recommended'], + ...vueTsEslintConfig(), + skipFormatting, + + { + rules: { + 'vue/no-v-html': 'off', + 'no-unused-vars': 'off', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-unused-vars': [ + 'warn', + { + varsIgnorePattern: '^_', + argsIgnorePattern: '^_', + destructuredArrayIgnorePattern: '^_', + }, + ], + 'no-console': ['error', { allow: ['warn', 'error'] }], + }, + }, +] diff --git a/app/package.json b/app/package.json index c2aec76ce..6c7ce9b57 100644 --- a/app/package.json +++ b/app/package.json @@ -7,44 +7,44 @@ "scripts": { "dev": "vite", "build": "vite build", - "lint:js": "eslint --ext \".ts,.vue,.cjs,.js\" --ignore-path ../.gitignore .", + "lint:js": "eslint .", "lint:prettier": "prettier --check .", "lint": "yarn lint:js && yarn lint:prettier", "lintfix": "prettier --write --list-different . && yarn lint:js --fix", - "type-check": "vue-tsc --noEmit -p tsconfig.json" + "type-check": "vue-tsc --noEmit -p tsconfig.json", + "upgrade-deps": "yarn upgrade-interactive --latest" }, "dependencies": { "@fontsource/fira-code": "^5.1.0", "@fontsource/firago": "^5.1.0", "@vuelidate/core": "^2.0.3", "@vuelidate/validators": "^2.0.4", - "@vueuse/core": "^11.1.0", + "@vueuse/core": "^12.0.0", "bootstrap": "^5.3.3", - "bootstrap-vue-next": "^0.25.13", - "date-fns": "^4.0.0", + "bootstrap-vue-next": "^0.26.15", + "date-fns": "^4.1.0", "fork-awesome": "^1.2.0", "simple-evaluate": "^1.4.6", - "uuid": "^10.0.0", - "vue": "^3.5.6", + "uuid": "^11.0.3", + "vue": "^3.5.13", "vue-i18n": "^10.0.5", - "vue-router": "^4.4.5", + "vue-router": "^4.5.0", "vue-showdown": "^4.2.0" }, "devDependencies": { "@types/uuid": "^10.0.0", - "@vitejs/plugin-vue": "^5.1.3", - "@vue/eslint-config-typescript": "^13.0.0", - "@vue/tsconfig": "^0.5.1", - "eslint": "^8.57.0", - "eslint-config-prettier": "^9.1.0", - "eslint-plugin-prettier": "^5.2.1", - "eslint-plugin-vue": "^9.28.0", - "prettier": "^3.3.3", - "sass": "^1.78.0", - "typescript": "^5.6.2", - "unplugin-vue-components": "^0.27.4", - "vite": "^5.4.6", - "vue-tsc": "^2.1.6" + "@vitejs/plugin-vue": "^5.2.1", + "@vue/eslint-config-prettier": "^10.1.0", + "@vue/eslint-config-typescript": "^14.1.4", + "@vue/tsconfig": "^0.7.0", + "eslint": "^9.17.0", + "eslint-plugin-vue": "^9.32.0", + "prettier": "^3.4.2", + "sass": "^1.83.0", + "typescript": "^5.7.2", + "unplugin-vue-components": "^0.28.0", + "vite": "^6.0.3", + "vue-tsc": "^2.1.10" }, "browserslist": [ "> 1%", diff --git a/app/src/api/api.ts b/app/src/api/api.ts index 0ae10b5e4..1038d7ca0 100644 --- a/app/src/api/api.ts +++ b/app/src/api/api.ts @@ -101,7 +101,7 @@ export default { * @returns Promise that resolve the api response data * @throws Throw an `APIError` or subclass depending on server response */ - async fetch({ + async fetch({ uri, method = 'GET', cachePath = undefined, @@ -206,9 +206,7 @@ export default { * @returns Promise that resolve the api response data or an error * @throws Throw an `APIError` or subclass depending on server response */ - get( - query: string | Omit, - ): Promise { + get(query: string | Omit): Promise { return this.fetch(typeof query === 'string' ? { uri: query } : query) }, @@ -220,7 +218,7 @@ export default { * @returns Promise that resolve the api response data or an error * @throws Throw an `APIError` or subclass depending on server response */ - post(query: Omit): Promise { + post(query: Omit): Promise { return this.fetch({ ...query, method: 'POST' }) }, @@ -232,7 +230,7 @@ export default { * @returns Promise that resolve the api response data or an error * @throws Throw an `APIError` or subclass depending on server response */ - put(query: Omit): Promise { + put(query: Omit): Promise { return this.fetch({ ...query, method: 'PUT' }) }, @@ -244,7 +242,7 @@ export default { * @returns Promise that resolve the api response data or an error * @throws Throw an `APIError` or subclass depending on server response */ - delete(query: Omit): Promise { + delete(query: Omit): Promise { return this.fetch({ ...query, method: 'DELETE' }) }, diff --git a/app/src/api/errors.ts b/app/src/api/errors.ts index 9b8c7d092..bf108e52a 100644 --- a/app/src/api/errors.ts +++ b/app/src/api/errors.ts @@ -34,7 +34,6 @@ class APIError extends Error { } log() { - /* eslint-disable-next-line */ console.error(`${this.name} (${this.code}): ${this.path}\n${this.message}`) } } diff --git a/app/src/api/handlers.ts b/app/src/api/handlers.ts index efb82103f..0e393e827 100644 --- a/app/src/api/handlers.ts +++ b/app/src/api/handlers.ts @@ -17,9 +17,7 @@ import type { APIErrorData } from './api' * @param response - A fetch `Response` object. * @returns Parsed response's json or response's text. */ -export async function getResponseData( - response: Response, -): Promise { +export async function getResponseData(response: Response): Promise { // FIXME the api should always return json as response const responseText = await response.text() try { diff --git a/app/src/components/ConfigPanels.vue b/app/src/components/ConfigPanels.vue index aee639119..411061a5c 100644 --- a/app/src/components/ConfigPanels.vue +++ b/app/src/components/ConfigPanels.vue @@ -14,14 +14,14 @@ defineOptions({ }) const currentRoute = useRoute() -const props = defineProps<{ +const _props = defineProps<{ panel: ConfigPanel routes: ConfigPanels['routes'] validations: FormValidation }>() const emit = defineEmits<{ - apply: [action?: KeyOfStr] + apply: [action?: KeyOfStr] }>() const slots = defineSlots<{ diff --git a/app/src/components/RecursiveListGroup.vue b/app/src/components/RecursiveListGroup.vue index c7d580d69..87222567b 100644 --- a/app/src/components/RecursiveListGroup.vue +++ b/app/src/components/RecursiveListGroup.vue @@ -1,5 +1,9 @@