feat: Add prettier and configure autofix to use it (#6642)

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Frank Elsinga
2026-01-08 10:51:36 +01:00
committed by GitHub
parent 0eca301181
commit 65b21d2c4b
9 changed files with 183 additions and 61 deletions

View File

@@ -15,6 +15,7 @@ module.exports = {
"eslint:recommended",
"plugin:vue/vue3-recommended",
"plugin:jsdoc/recommended-error",
"prettier", // Disables ESLint formatting rules that conflict with Prettier
],
parser: "vue-eslint-parser",
parserOptions: {
@@ -29,7 +30,6 @@ module.exports = {
rules: {
"yoda": "error",
eqeqeq: [ "warn", "smart" ],
"linebreak-style": [ "error", "unix" ],
"camelcase": [ "warn", {
"properties": "never",
"ignoreImports": true
@@ -37,68 +37,22 @@ module.exports = {
"no-unused-vars": [ "warn", {
"args": "none"
}],
indent: [
"error",
4,
{
ignoredNodes: [ "TemplateLiteral" ],
SwitchCase: 1,
},
],
quotes: [ "error", "double" ],
semi: "error",
"vue/html-indent": [ "error", 4 ], // default: 2
"vue/max-attributes-per-line": "off",
"vue/singleline-html-element-content-newline": "off",
"vue/html-self-closing": "off",
"vue/require-component-is": "off", // not allow is="style" https://github.com/vuejs/eslint-plugin-vue/issues/462#issuecomment-430234675
"vue/attribute-hyphenation": "off", // This change noNL to "no-n-l" unexpectedly
"vue/multi-word-component-names": "off",
"no-multi-spaces": [ "error", {
ignoreEOLComments: true,
}],
"array-bracket-spacing": [ "warn", "always", {
"singleValue": true,
"objectsInArrays": false,
"arraysInArrays": false
}],
"space-before-function-paren": [ "error", {
"anonymous": "always",
"named": "never",
"asyncArrow": "always"
}],
"curly": "error",
"object-curly-spacing": [ "error", "always" ],
"object-curly-newline": "off",
"object-property-newline": "error",
"comma-spacing": "error",
"brace-style": "error",
"no-var": "error",
"key-spacing": "warn",
"keyword-spacing": "warn",
"space-infix-ops": "error",
"arrow-spacing": "warn",
"no-throw-literal": "error",
"no-trailing-spaces": "error",
"no-constant-condition": [ "error", {
"checkLoops": false,
}],
"space-before-blocks": "warn",
//"no-console": "warn",
"no-extra-boolean-cast": "off",
"no-multiple-empty-lines": [ "warn", {
"max": 1,
"maxBOF": 0,
}],
"lines-between-class-members": [ "warn", "always", {
exceptAfterSingleLine: true,
}],
"no-unneeded-ternary": "error",
"array-bracket-newline": [ "error", "consistent" ],
"eol-last": [ "error", "always" ],
//"prefer-template": "error",
"template-curly-spacing": [ "warn", "never" ],
"comma-dangle": [ "warn", "only-multiline" ],
"no-empty": [ "error", {
"allowEmptyCatch": true
}],
@@ -143,13 +97,6 @@ module.exports = {
"jsdoc/require-param-description": "warn"
},
"overrides": [
{
"files": [ "src/languages/*.js", "src/icon.js" ],
"rules": {
"comma-dangle": [ "error", "always-multiline" ],
}
},
// Override for TypeScript
{
"files": [

View File

@@ -37,5 +37,10 @@ jobs:
- name: Auto-fix CSS/SCSS linting issues
run: npm run lint-fix:style
continue-on-error: true
# TODO: disabled until we have agreed that this is the formatting that we want to enforce
# - name: Auto-format code with Prettier
# run: npm run fmt
# continue-on-error: true
- uses: autofix-ci/action@635ffb0c9798bd160680f18fd73371e355b85f27

38
.prettierignore Normal file
View File

@@ -0,0 +1,38 @@
# Dependencies
node_modules/
# Build output
dist/
build/
# Data directories
data/
# Test output
test-results/
playwright-report/
private/
# Logs
*.log
npm-debug.log*
# OS files
.DS_Store
Thumbs.db
# IDE
.vscode/
.idea/
# Lock files
package-lock.json
pnpm-lock.yaml
yarn.lock
# Generated files
*.min.js
*.min.css
# Docker
docker/

71
.prettierrc.js Normal file
View File

@@ -0,0 +1,71 @@
/**
* Prettier Configuration for Uptime Kuma
*
* Usage:
* npm run fmt - Format all files (auto-runs in CI via autofix workflow)
* npm run fmt -- --check - Check formatting without making changes
*
* TIP: This formatter is automatically run in CI, so no need to worry about it
*/
module.exports = {
// Core formatting options - matching original ESLint rules
semi: true,
singleQuote: false,
trailingComma: "es5",
printWidth: 120,
tabWidth: 4,
useTabs: false,
endOfLine: "lf",
arrowParens: "always",
bracketSpacing: true,
bracketSameLine: false,
// Vue-specific settings
vueIndentScriptAndStyle: false,
singleAttributePerLine: false,
htmlWhitespaceSensitivity: "ignore", // More forgiving with whitespace in HTML
// Override settings for specific file types
overrides: [
{
files: "*.vue",
options: {
parser: "vue",
},
},
{
files: ["*.json"],
options: {
tabWidth: 2,
trailingComma: "none",
},
},
{
files: ["*.yml", "*.yaml"],
options: {
tabWidth: 2,
trailingComma: "none",
},
},
{
files: ["package.json"],
options: {
tabWidth: 2,
},
},
{
files: ["src/icon.js"],
options: {
trailingComma: "all",
},
},
{
files: ["*.md"],
options: {
printWidth: 100,
proseWrap: "preserve",
tabWidth: 2,
},
},
],
};

View File

@@ -1,10 +1,11 @@
{
"extends": "stylelint-config-standard",
"extends": [
"stylelint-config-standard",
"stylelint-config-prettier"
],
"customSyntax": "postcss-html",
"rules": {
"indentation": 4,
"no-descending-specificity": null,
"selector-list-comma-newline-after": null,
"declaration-empty-line-before": null,
"alpha-value-notation": "number",
"color-function-notation": "legacy",

View File

@@ -269,7 +269,8 @@ to review the appropriate one for your contribution.
### Continuous Integration
All pull requests must pass our continuous integration checks. These checks include:
- **Linting**: We use ESLint and Stylelint to enforce code style. You can run the linter locally with `npm run lint`.
- **Linting**: We use ESLint and Stylelint for code quality checks. You can run the linter locally with `npm run lint`.
- **Formatting**: We use Prettier for code formatting. You can format your code with `npm run fmt` (or CI will do this for you)
- **Testing**: We use Playwright for end-to-end tests and have a suite of backend tests. You can run the tests locally with `npm test`.
I ([@louislam](https://github.com/louislam)) have the final say.

52
package-lock.json generated
View File

@@ -126,6 +126,7 @@
"dns2": "~2.0.1",
"dompurify": "~3.2.4",
"eslint": "~8.14.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-jsdoc": "~46.4.6",
"eslint-plugin-vue": "~8.7.1",
"favico.js": "~0.3.10",
@@ -134,11 +135,13 @@
"postcss-html": "~1.5.0",
"postcss-rtlcss": "~3.7.2",
"postcss-scss": "~4.0.4",
"prettier": "^3.7.4",
"prismjs": "~1.30.0",
"qrcode": "~1.5.0",
"rollup-plugin-visualizer": "^5.6.0",
"sass": "~1.42.1",
"stylelint": "^15.10.1",
"stylelint-config-prettier": "^9.0.5",
"stylelint-config-standard": "~25.0.0",
"terser": "~5.15.0",
"test": "~3.3.0",
@@ -9944,6 +9947,22 @@
"url": "https://opencollective.com/eslint"
}
},
"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-jsdoc": {
"version": "46.4.6",
"resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-46.4.6.tgz",
@@ -15157,6 +15176,22 @@
"node": ">= 0.8.0"
}
},
"node_modules/prettier": {
"version": "3.7.4",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.7.4.tgz",
"integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==",
"dev": true,
"license": "MIT",
"bin": {
"prettier": "bin/prettier.cjs"
},
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/pretty-bytes": {
"version": "6.1.1",
"resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-6.1.1.tgz",
@@ -17517,6 +17552,23 @@
"url": "https://opencollective.com/stylelint"
}
},
"node_modules/stylelint-config-prettier": {
"version": "9.0.5",
"resolved": "https://registry.npmjs.org/stylelint-config-prettier/-/stylelint-config-prettier-9.0.5.tgz",
"integrity": "sha512-U44lELgLZhbAD/xy/vncZ2Pq8sh2TnpiPvo38Ifg9+zeioR+LAkHu0i6YORIOxFafZoVg0xqQwex6e6F25S5XA==",
"dev": true,
"license": "MIT",
"bin": {
"stylelint-config-prettier": "bin/check.js",
"stylelint-config-prettier-check": "bin/check.js"
},
"engines": {
"node": ">= 12"
},
"peerDependencies": {
"stylelint": ">= 11.x < 15"
}
},
"node_modules/stylelint-config-recommended": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-7.0.0.tgz",

View File

@@ -16,6 +16,7 @@
"lint:style": "stylelint \"**/*.{vue,css,scss}\" --ignore-path .gitignore",
"lint-fix:style": "stylelint \"**/*.{vue,css,scss}\" --fix --ignore-path .gitignore",
"lint": "npm run lint:js && npm run lint:style",
"fmt": "prettier --write \"**/*.{js,ts,vue,css,scss,json,md,yml,yaml}\" --ignore-path .gitignore",
"lint:prod": "npm run lint:js-prod && npm run lint:style",
"dev": "concurrently -k -r \"wait-on tcp:3000 && npm run start-server-dev \" \"npm run start-frontend-dev\"",
"start-frontend-dev": "cross-env NODE_ENV=development vite --host --config ./config/vite.config.js",
@@ -187,6 +188,7 @@
"dns2": "~2.0.1",
"dompurify": "~3.2.4",
"eslint": "~8.14.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-jsdoc": "~46.4.6",
"eslint-plugin-vue": "~8.7.1",
"favico.js": "~0.3.10",
@@ -195,11 +197,13 @@
"postcss-html": "~1.5.0",
"postcss-rtlcss": "~3.7.2",
"postcss-scss": "~4.0.4",
"prettier": "^3.7.4",
"prismjs": "~1.30.0",
"qrcode": "~1.5.0",
"rollup-plugin-visualizer": "^5.6.0",
"sass": "~1.42.1",
"stylelint": "^15.10.1",
"stylelint-config-prettier": "^9.0.5",
"stylelint-config-standard": "~25.0.0",
"terser": "~5.15.0",
"test": "~3.3.0",

View File

@@ -216,8 +216,9 @@
<div v-if="editIncidentMode" class="form-text">
{{ $t("markdownSupported") }}
</div>
<!-- eslint-disable-next-line vue/no-v-html-->
<!-- eslint-disable vue/no-v-html-->
<div v-if="! editIncidentMode" class="content" data-testid="incident-content" v-html="incidentHTML"></div>
<!-- eslint-enable vue/no-v-html-->
<!-- Incident Date -->
<div class="date mt-3">
@@ -314,8 +315,9 @@
<!-- Description -->
<strong v-if="editMode">{{ $t("Description") }}:</strong>
<Editable v-if="enableEditMode" v-model="config.description" :contenteditable="editMode" tag="div" class="mb-4 description" data-testid="description-editable" />
<!-- eslint-disable-next-line vue/no-v-html-->
<!-- eslint-disable vue/no-v-html-->
<div v-if="! enableEditMode" class="alert-heading p-2" data-testid="description" v-html="descriptionHTML"></div>
<!-- eslint-enable vue/no-v-html-->
<div v-if="editMode" class="mb-4">
<div>
@@ -366,8 +368,9 @@
<strong v-if="enableEditMode">{{ $t("Custom Footer") }}:</strong>
</div>
<Editable v-if="enableEditMode" v-model="config.footerText" tag="div" :contenteditable="enableEditMode" :noNL="false" class="alert-heading p-2" data-testid="custom-footer-editable" />
<!-- eslint-disable-next-line vue/no-v-html-->
<!-- eslint-disable vue/no-v-html-->
<div v-if="! enableEditMode" class="alert-heading p-2" data-testid="footer-text" v-html="footerHTML"></div>
<!-- eslint-enable vue/no-v-html-->
<p v-if="config.showPoweredBy" data-testid="powered-by">
{{ $t("Powered by") }} <a target="_blank" rel="noopener noreferrer" href="https://github.com/louislam/uptime-kuma">{{ $t("Uptime Kuma" ) }}</a>