diff --git a/.github/workflows/nodelint.yml b/.github/workflows/nodelint.yml index 1e1e4716..17f4bd11 100644 --- a/.github/workflows/nodelint.yml +++ b/.github/workflows/nodelint.yml @@ -1,4 +1,4 @@ -name: ESLint +name: Lint & Format (ESLint + Prettier) on: [push] diff --git a/client/.prettierignore b/client/.prettierignore new file mode 100644 index 00000000..9a906847 --- /dev/null +++ b/client/.prettierignore @@ -0,0 +1,16 @@ +# Dependencies +node_modules/ + +# Build outputs +dist/ +../server/static/ + +# Test outputs +coverage/ +junit/ + +# Backups +*.backup + +# Generated files +src/docs/ \ No newline at end of file diff --git a/client/eslint.config.mjs b/client/eslint.config.mjs index 023ed3fe..a62fecf1 100644 --- a/client/eslint.config.mjs +++ b/client/eslint.config.mjs @@ -2,6 +2,8 @@ import js from '@eslint/js'; import pluginVue from 'eslint-plugin-vue'; import globals from 'globals'; import babelParser from '@babel/eslint-parser'; +import prettierConfig from 'eslint-config-prettier'; +import prettierPlugin from 'eslint-plugin-prettier'; export default [ { @@ -11,12 +13,16 @@ export default [ '../server/static/**', 'junit/**', '*.backup', + 'src/docs/**', ], }, js.configs.recommended, ...pluginVue.configs['flat/vue2-recommended'], { files: ['**/*.{js,vue}'], + plugins: { + prettier: prettierPlugin, + }, languageOptions: { ecmaVersion: 2021, sourceType: 'module', @@ -37,27 +43,24 @@ export default [ }, }, rules: { + // Prettier integration - runs Prettier as an ESLint rule + 'prettier/prettier': 'error', + + // Disable formatting rules that conflict with Prettier + ...prettierConfig.rules, + + // Let Prettier handle line length (via printWidth config) + 'max-len': 'off', + + // Custom linting rules (non-formatting) 'no-unused-vars': 'off', 'vue/no-unused-vars': 'off', 'no-plusplus': 'off', - 'no-param-reassign': ['error', { - props: true, - ignorePropertyModificationsFor: [ - 'state', - 'acc', - 'e', - ], - }], - 'max-len': [ + 'no-param-reassign': [ 'error', - 150, - 2, { - ignoreUrls: true, - ignoreComments: false, - ignoreRegExpLiterals: true, - ignoreStrings: true, - ignoreTemplateLiterals: true, + props: true, + ignorePropertyModificationsFor: ['state', 'acc', 'e'], }, ], }, diff --git a/client/package-lock.json b/client/package-lock.json index 2e1a31a2..ea414231 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -1,12 +1,12 @@ { "name": "client", - "version": "0.22.1", + "version": "0.23.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "client", - "version": "0.22.1", + "version": "0.23.0", "dependencies": { "bootstrap": "4.6.2", "bootstrap-vue": "2.23.1", @@ -42,9 +42,12 @@ "@vitest/ui": "^4.0.16", "@vue/test-utils": "^2.4.6", "eslint": "^9.39.2", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-prettier": "^5.5.4", "eslint-plugin-vue": "^9.33.0", "globals": "^15.14.0", "jsdom": "^27.4.0", + "prettier": "^3.7.4", "sass": "1.97.2", "vite": "^7.3.1", "vitest": "^4.0.16" @@ -2933,6 +2936,19 @@ "node": ">=14" } }, + "node_modules/@pkgr/core": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", + "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/pkgr" + } + }, "node_modules/@polka/url": { "version": "1.0.0-next.29", "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", @@ -3360,6 +3376,23 @@ "prettier": "^1.18.2 || ^2.0.0" } }, + "node_modules/@types/vuelidate/node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "license": "MIT", + "optional": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/@types/vuelidate/node_modules/vue": { "version": "2.7.16", "resolved": "https://registry.npmjs.org/vue/-/vue-2.7.16.tgz", @@ -4446,6 +4479,53 @@ } } }, + "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-prettier": { + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.4.tgz", + "integrity": "sha512-swNtI95SToIz05YINMA6Ox5R057IMAmWZ26GqPxusAp1TZzj+IdY9tXNWWD3vkF/wEqydCONcwjTFpxybBqZsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.11.7" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } + } + }, "node_modules/eslint-plugin-vue": { "version": "9.33.0", "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.33.0.tgz", @@ -4704,6 +4784,13 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-diff": { + "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-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -5824,22 +5911,34 @@ } }, "node_modules/prettier": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.7.4.tgz", + "integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==", "dev": true, "license": "MIT", - "optional": true, "bin": { - "prettier": "bin-prettier.js" + "prettier": "bin/prettier.cjs" }, "engines": { - "node": ">=10.13.0" + "node": ">=14" }, "funding": { "url": "https://github.com/prettier/prettier?sponsor=1" } }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.1.tgz", + "integrity": "sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/proto-list": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", @@ -6305,6 +6404,22 @@ "dev": true, "license": "MIT" }, + "node_modules/synckit": { + "version": "0.11.11", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz", + "integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pkgr/core": "^0.2.9" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/synckit" + } + }, "node_modules/tinybench": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", diff --git a/client/package.json b/client/package.json index 2fd369db..32772b56 100644 --- a/client/package.json +++ b/client/package.json @@ -1,14 +1,18 @@ { "name": "client", - "version": "0.22.1", + "version": "0.23.0", "private": true, "scripts": { "prebuild": "scripts/copy-docs.sh && node scripts/generate-doc-manifest.js", "build": "vite build", "build:analyze": "vite build --mode analyze", - "lint": "eslint 'src/**/*.{js,vue}' --fix", - "ci-lint": "eslint 'src/**/*.{js,vue}'", + "lint": "npm run format && npm run lint:eslint", + "lint:eslint": "eslint 'src/**/*.{js,vue}' --fix", + "ci-lint": "npm run format:check && npm run lint:eslint-check", + "lint:eslint-check": "eslint 'src/**/*.{js,vue}'", "lint:filter": "./scripts/eslint-filter.sh", + "format": "prettier --write 'src/**/*.{js,vue,json,css,scss}'", + "format:check": "prettier --check 'src/**/*.{js,vue,json,css,scss}'", "test": "vitest", "test:ui": "vitest --ui", "test:run": "vitest run", @@ -54,9 +58,12 @@ "@vitest/ui": "^4.0.16", "@vue/test-utils": "^2.4.6", "eslint": "^9.39.2", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-prettier": "^5.5.4", "eslint-plugin-vue": "^9.33.0", "globals": "^15.14.0", "jsdom": "^27.4.0", + "prettier": "^3.7.4", "sass": "1.97.2", "vite": "^7.3.1", "vitest": "^4.0.16" diff --git a/client/prettier.config.mjs b/client/prettier.config.mjs new file mode 100644 index 00000000..67b1fa21 --- /dev/null +++ b/client/prettier.config.mjs @@ -0,0 +1,40 @@ +/** + * Prettier configuration for DigiScript frontend + * Based on Vue.js community recommendations + * @see https://prettier.io/docs/en/configuration.html + * @see https://vuejs.org/style-guide/ + */ +export default { + // Standard Prettier defaults with Vue community preferences + printWidth: 100, + tabWidth: 2, + useTabs: false, + semi: true, + singleQuote: true, + quoteProps: 'as-needed', + trailingComma: 'es5', + bracketSpacing: true, + bracketSameLine: false, + arrowParens: 'always', + endOfLine: 'lf', + + // Vue-specific options + vueIndentScriptAndStyle: false, // Don't indent diff --git a/client/src/views/show/config/ConfigActs.vue b/client/src/views/show/config/ConfigActs.vue index 912333a6..bbb8d744 100644 --- a/client/src/views/show/config/ConfigActs.vue +++ b/client/src/views/show/config/ConfigActs.vue @@ -1,8 +1,5 @@