diff --git a/webapp/.prettierignore b/webapp/.prettierignore new file mode 100644 index 0000000..f6455c6 --- /dev/null +++ b/webapp/.prettierignore @@ -0,0 +1,4 @@ +# Ignore artifacts: +build +coverage +node_modules diff --git a/webapp/.prettierrc b/webapp/.prettierrc new file mode 100644 index 0000000..2444c37 --- /dev/null +++ b/webapp/.prettierrc @@ -0,0 +1,46 @@ +{ + "arrowParens": "always", + "bracketSameLine": false, + "objectWrap": "preserve", + "bracketSpacing": true, + "semi": true, + "experimentalOperatorPosition": "end", + "experimentalTernaries": false, + "singleQuote": false, + "jsxSingleQuote": false, + "quoteProps": "as-needed", + "trailingComma": "all", + "singleAttributePerLine": true, + "htmlWhitespaceSensitivity": "css", + "vueIndentScriptAndStyle": false, + "proseWrap": "preserve", + "endOfLine": "lf", + "printWidth": 80, + "tabWidth": 2, + "useTabs": false, + "embeddedLanguageFormatting": "auto", + "plugins": ["@trivago/prettier-plugin-sort-imports"], + "importOrder": [ + "", + "", + "^@/(.*)$", + "^@app/(.*)$", + "^@providers", + "^@providers/(.*)$", + "^@components", + "^@components/(.*)$", + "^@widgets", + "^@widgets/(.*)$", + "^@assets", + "^@assets/(.*)$", + "^@pages", + "^@pages/(.*)$", + "^@ui", + "^@ui/(.*)$", + "[../]", + "[./]" + ], + "importOrderSeparation": true, + "importOrderSortSpecifiers": true, + "importOrderCaseInsensitive": false +} diff --git a/webapp/eslint.config.ts b/webapp/eslint.config.ts index 87658d7..93b060a 100644 --- a/webapp/eslint.config.ts +++ b/webapp/eslint.config.ts @@ -4,6 +4,7 @@ import tseslint from "typescript-eslint"; import pluginReact from "eslint-plugin-react"; import json from "@eslint/json"; import { defineConfig } from "eslint/config"; +import pluginPrettier from "eslint-config-prettier/flat"; export default defineConfig([ { files: ["**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"], plugins: { js }, extends: ["js/recommended"], languageOptions: { globals: globals.browser } }, @@ -27,4 +28,5 @@ export default defineConfig([ { files: ["**/*.json"], plugins: { json }, language: "json/json", extends: ["json/recommended"] }, /** @ts-expect-error json plugin not typed well*/ { files: ["**/*.jsonc"], plugins: { json }, language: "json/jsonc", extends: ["json/recommended"] }, + pluginPrettier, ]); diff --git a/webapp/package-lock.json b/webapp/package-lock.json index 8b3aae5..0a3f4f3 100644 --- a/webapp/package-lock.json +++ b/webapp/package-lock.json @@ -32,15 +32,18 @@ "@eslint/js": "^9.39.2", "@eslint/json": "^1.0.0", "@tailwindcss/vite": "^4.1.18", + "@trivago/prettier-plugin-sort-imports": "^6.0.2", "@types/chart.js": "^2.9.41", "@types/node": "^24.10.1", "@types/react": "^19.2.5", "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^5.1.1", "eslint": "^9.39.2", + "eslint-config-prettier": "^10.1.8", "eslint-plugin-react": "^7.37.5", "globals": "^17.2.0", "jiti": "^2.6.1", + "prettier": "3.8.1", "tailwind-merge": "^3.4.0", "tailwindcss": "^4.1.18", "tailwindcss-animate": "^1.0.7", @@ -2784,6 +2787,73 @@ "vite": "^5.2.0 || ^6 || ^7" } }, + "node_modules/@trivago/prettier-plugin-sort-imports": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-6.0.2.tgz", + "integrity": "sha512-3DgfkukFyC/sE/VuYjaUUWoFfuVjPK55vOFDsxD56XXynFMCZDYFogH2l/hDfOsQAm1myoU/1xByJ3tWqtulXA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@babel/generator": "^7.28.0", + "@babel/parser": "^7.28.0", + "@babel/traverse": "^7.28.0", + "@babel/types": "^7.28.0", + "javascript-natural-sort": "^0.7.1", + "lodash-es": "^4.17.21", + "minimatch": "^9.0.0", + "parse-imports-exports": "^0.2.4" + }, + "engines": { + "node": ">= 20" + }, + "peerDependencies": { + "@vue/compiler-sfc": "3.x", + "prettier": "2.x - 3.x", + "prettier-plugin-ember-template-tag": ">= 2.0.0", + "prettier-plugin-svelte": "3.x", + "svelte": "4.x || 5.x" + }, + "peerDependenciesMeta": { + "@vue/compiler-sfc": { + "optional": true + }, + "prettier-plugin-ember-template-tag": { + "optional": true + }, + "prettier-plugin-svelte": { + "optional": true + }, + "svelte": { + "optional": true + } + } + }, + "node_modules/@trivago/prettier-plugin-sort-imports/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@trivago/prettier-plugin-sort-imports/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -4380,6 +4450,22 @@ } } }, + "node_modules/eslint-config-prettier": { + "version": "10.1.8", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz", + "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", + "dev": true, + "license": "MIT", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "funding": { + "url": "https://opencollective.com/eslint-config-prettier" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, "node_modules/eslint-plugin-react": { "version": "7.37.5", "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz", @@ -5426,6 +5512,13 @@ "node": ">= 0.4" } }, + "node_modules/javascript-natural-sort": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz", + "integrity": "sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==", + "dev": true, + "license": "MIT" + }, "node_modules/jiti": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", @@ -5837,6 +5930,13 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "license": "MIT" }, + "node_modules/lodash-es": { + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.23.tgz", + "integrity": "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -6199,6 +6299,23 @@ "node": ">=6" } }, + "node_modules/parse-imports-exports": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/parse-imports-exports/-/parse-imports-exports-0.2.4.tgz", + "integrity": "sha512-4s6vd6dx1AotCx/RCI2m7t7GCh5bDRUtGNvRfHSP2wbBQdMi67pPe7mtzmgwcaQ8VKK/6IB7Glfyu3qdZJPybQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parse-statements": "1.0.11" + } + }, + "node_modules/parse-statements": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/parse-statements/-/parse-statements-1.0.11.tgz", + "integrity": "sha512-HlsyYdMBnbPQ9Jr/VgJ1YF4scnldvJpJxCVx6KgqPL4dxppsWrJHCIIxQXMJrqGnsRkNPATbeMJ8Yxu7JMsYcA==", + "dev": true, + "license": "MIT" + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -6313,6 +6430,22 @@ "node": ">= 0.8.0" } }, + "node_modules/prettier": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", + "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", diff --git a/webapp/package.json b/webapp/package.json index 13b7a36..49c0cef 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -8,7 +8,11 @@ "build": "tsc -b && vite build", "preview": "vite preview", "check:arch": "node ./scripts/check-architecture.cjs", + "check:code": "npm run compile && npm run format && npm run lint", "arch:tree": "node ./scripts/generate-tree.cjs ./src webappTree.md", + "compile": "tsc -b", + "format": "prettier . --write", + "format:check": "prettier . --check", "lint": "eslint ./src", "lint:fix": "eslint ./src --fix" }, @@ -37,15 +41,18 @@ "@eslint/js": "^9.39.2", "@eslint/json": "^1.0.0", "@tailwindcss/vite": "^4.1.18", + "@trivago/prettier-plugin-sort-imports": "^6.0.2", "@types/chart.js": "^2.9.41", "@types/node": "^24.10.1", "@types/react": "^19.2.5", "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^5.1.1", "eslint": "^9.39.2", + "eslint-config-prettier": "^10.1.8", "eslint-plugin-react": "^7.37.5", "globals": "^17.2.0", "jiti": "^2.6.1", + "prettier": "3.8.1", "tailwind-merge": "^3.4.0", "tailwindcss": "^4.1.18", "tailwindcss-animate": "^1.0.7",