diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 00000000..554e8d52 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,2 @@ +cd -- "$(dirname -- "$0")/.." +npm run format:tests:commit diff --git a/package-lock.json b/package-lock.json index 86b0e07a..27a48e75 100644 --- a/package-lock.json +++ b/package-lock.json @@ -69,6 +69,7 @@ "@vitejs/plugin-vue": "^6.0.5", "@vitejs/plugin-vue-jsx": "^5.1.5", "@vue/test-utils": "^2.4.6", + "husky": "^9.1.7", "jsdom": "^29.0.0", "otpauth": "^9.5.0", "prettier": "2.8.8", @@ -230,8 +231,8 @@ "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", @@ -261,6 +262,7 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -556,6 +558,7 @@ "version": "7.29.2", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/template": "^7.28.6", @@ -1947,13 +1950,6 @@ "node": ">=0.12.0" } }, - "node_modules/@bubblewrap/core/node_modules/undici-types": { - "version": "7.19.2", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz", - "integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==", - "license": "MIT", - "optional": true - }, "node_modules/@bubblewrap/validator": { "version": "1.22.0", "resolved": "https://registry.npmjs.org/@bubblewrap/validator/-/validator-1.22.0.tgz", @@ -1971,7 +1967,7 @@ "version": "2.11.0", "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.11.0.tgz", "integrity": "sha512-sBXGT13cpmPR5BMgHE6UEEfEaShh5Ror6rfN3yEK5si7QVrtZg8LEPQb0VVhiLRUslD2yLnXtnRzG035J/mZXQ==", - "devOptional": true, + "dev": true, "license": "(Apache-2.0 AND BSD-3-Clause)" }, "node_modules/@creativebulma/bulma-badge": { @@ -2075,7 +2071,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=20.19.0" }, @@ -2124,7 +2119,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=20.19.0" } @@ -2136,6 +2130,7 @@ "cpu": [ "ppc64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2152,6 +2147,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2168,6 +2164,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2184,6 +2181,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2200,6 +2198,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2216,6 +2215,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2232,6 +2232,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2248,6 +2249,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2264,6 +2266,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2280,6 +2283,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2296,6 +2300,7 @@ "cpu": [ "ia32" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2312,6 +2317,7 @@ "cpu": [ "loong64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2328,6 +2334,7 @@ "cpu": [ "mips64el" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2344,6 +2351,7 @@ "cpu": [ "ppc64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2360,6 +2368,7 @@ "cpu": [ "riscv64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2376,6 +2385,7 @@ "cpu": [ "s390x" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2392,6 +2402,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2408,6 +2419,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2424,6 +2436,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2440,6 +2453,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2456,6 +2470,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2472,6 +2487,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2488,6 +2504,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2504,6 +2521,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2520,6 +2538,7 @@ "cpu": [ "ia32" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2562,7 +2581,6 @@ "resolved": "https://registry.npmjs.org/@fullcalendar/core/-/core-6.1.20.tgz", "integrity": "sha512-1cukXLlePFiJ8YKXn/4tMKsy0etxYLCkXk8nUCFi11nRONF2Ba2CD5b21/ovtOO2tL6afTJfwmc1ed3HG7eB1g==", "license": "MIT", - "peer": true, "dependencies": { "preact": "~10.12.1" } @@ -2806,7 +2824,6 @@ "resolved": "https://registry.npmjs.org/@jimp/custom/-/custom-0.22.12.tgz", "integrity": "sha512-xcmww1O/JFP2MrlGUMd3Q78S3Qu6W3mYTXYuIqFq33EorgYHV/HqymHfXy9GjiCJ7OI+7lWx6nYFOzU7M4rd1Q==", "license": "MIT", - "peer": true, "dependencies": { "@jimp/core": "^0.22.12" } @@ -2843,7 +2860,6 @@ "resolved": "https://registry.npmjs.org/@jimp/plugin-blit/-/plugin-blit-0.22.12.tgz", "integrity": "sha512-xslz2ZoFZOPLY8EZ4dC29m168BtDx95D6K80TzgUi8gqT7LY6CsajWO0FAxDwHz6h0eomHMfyGX0stspBrTKnQ==", "license": "MIT", - "peer": true, "dependencies": { "@jimp/utils": "^0.22.12" }, @@ -2856,7 +2872,6 @@ "resolved": "https://registry.npmjs.org/@jimp/plugin-blur/-/plugin-blur-0.22.12.tgz", "integrity": "sha512-S0vJADTuh1Q9F+cXAwFPlrKWzDj2F9t/9JAbUvaaDuivpyWuImEKXVz5PUZw2NbpuSHjwssbTpOZ8F13iJX4uw==", "license": "MIT", - "peer": true, "dependencies": { "@jimp/utils": "^0.22.12" }, @@ -2881,7 +2896,6 @@ "resolved": "https://registry.npmjs.org/@jimp/plugin-color/-/plugin-color-0.22.12.tgz", "integrity": "sha512-xImhTE5BpS8xa+mAN6j4sMRWaUgUDLoaGHhJhpC+r7SKKErYDR0WQV4yCE4gP+N0gozD0F3Ka1LUSaMXrn7ZIA==", "license": "MIT", - "peer": true, "dependencies": { "@jimp/utils": "^0.22.12", "tinycolor2": "^1.6.0" @@ -2925,7 +2939,6 @@ "resolved": "https://registry.npmjs.org/@jimp/plugin-crop/-/plugin-crop-0.22.12.tgz", "integrity": "sha512-FNuUN0OVzRCozx8XSgP9MyLGMxNHHJMFt+LJuFjn1mu3k0VQxrzqbN06yIl46TVejhyAhcq5gLzqmSCHvlcBVw==", "license": "MIT", - "peer": true, "dependencies": { "@jimp/utils": "^0.22.12" }, @@ -3049,7 +3062,6 @@ "resolved": "https://registry.npmjs.org/@jimp/plugin-resize/-/plugin-resize-0.22.12.tgz", "integrity": "sha512-3NyTPlPbTnGKDIbaBgQ3HbE6wXbAlFfxHVERmrbqAi8R3r6fQPxpCauA8UVDnieg5eo04D0T8nnnNIX//i/sXg==", "license": "MIT", - "peer": true, "dependencies": { "@jimp/utils": "^0.22.12" }, @@ -3062,7 +3074,6 @@ "resolved": "https://registry.npmjs.org/@jimp/plugin-rotate/-/plugin-rotate-0.22.12.tgz", "integrity": "sha512-9YNEt7BPAFfTls2FGfKBVgwwLUuKqy+E8bDGGEsOqHtbuhbshVGxN2WMZaD4gh5IDWvR+emmmPPWGgaYNYt1gA==", "license": "MIT", - "peer": true, "dependencies": { "@jimp/utils": "^0.22.12" }, @@ -3078,7 +3089,6 @@ "resolved": "https://registry.npmjs.org/@jimp/plugin-scale/-/plugin-scale-0.22.12.tgz", "integrity": "sha512-dghs92qM6MhHj0HrV2qAwKPMklQtjNpoYgAB94ysYpsXslhRTiPisueSIELRwZGEr0J0VUxpUY7HgJwlSIgGZw==", "license": "MIT", - "peer": true, "dependencies": { "@jimp/utils": "^0.22.12" }, @@ -3213,6 +3223,7 @@ "version": "2.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -3232,7 +3243,7 @@ "version": "0.3.11", "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -3941,6 +3952,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3954,6 +3966,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3967,6 +3980,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3980,6 +3994,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3993,6 +4008,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4006,6 +4022,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4019,6 +4036,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4032,6 +4050,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4045,6 +4064,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4058,6 +4078,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4071,6 +4092,7 @@ "cpu": [ "loong64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4084,6 +4106,7 @@ "cpu": [ "loong64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4097,6 +4120,7 @@ "cpu": [ "ppc64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4110,6 +4134,7 @@ "cpu": [ "ppc64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4123,6 +4148,7 @@ "cpu": [ "riscv64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4136,6 +4162,7 @@ "cpu": [ "riscv64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4149,6 +4176,7 @@ "cpu": [ "s390x" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4162,6 +4190,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4175,6 +4204,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4188,6 +4218,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4201,6 +4232,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4214,6 +4246,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4227,6 +4260,7 @@ "cpu": [ "ia32" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4240,6 +4274,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4368,6 +4403,7 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, "license": "MIT" }, "node_modules/@types/event-calendar__core": { @@ -5339,9 +5375,8 @@ "version": "8.16.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", - "devOptional": true, + "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -5376,7 +5411,6 @@ "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -5470,8 +5504,7 @@ "version": "5.10.4", "resolved": "https://registry.npmjs.org/apexcharts/-/apexcharts-5.10.4.tgz", "integrity": "sha512-gt0VUqZ2+mr25ScbUcKZgJr96jKYm4vjOcxEWCEh/E5F4dWqhyo3dBhPRvNNnkKiWxkMd2cBwj3ZYH3rK39fkA==", - "license": "SEE LICENSE IN LICENSE", - "peer": true + "license": "SEE LICENSE IN LICENSE" }, "node_modules/aria-query": { "version": "5.3.1", @@ -5595,7 +5628,6 @@ "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.5.tgz", "integrity": "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==", "license": "MIT", - "peer": true, "dependencies": { "follow-redirects": "^1.15.11", "form-data": "^4.0.5", @@ -5810,7 +5842,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -5895,8 +5926,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/bulma/-/bulma-1.0.4.tgz", "integrity": "sha512-Ffb6YGXDiZYX3cqvSbHWqQ8+LkX6tVoTcZuVB3lm93sbAVXlO0D6QlOTMnV6g18gILpAXqkG2z9hf9z4hCjz2g==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/bulma-block-list": { "version": "1.1.0", @@ -6154,7 +6184,6 @@ "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.5.1.tgz", "integrity": "sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw==", "license": "MIT", - "peer": true, "dependencies": { "@kurkle/color": "^0.3.0" }, @@ -6343,7 +6372,7 @@ "version": "0.5.2", "resolved": "https://registry.npmjs.org/colorjs.io/-/colorjs.io-0.5.2.tgz", "integrity": "sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/colors": { @@ -6417,6 +6446,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, "license": "MIT" }, "node_modules/copy-anything": { @@ -6568,7 +6598,6 @@ "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", "license": "ISC", - "peer": true, "engines": { "node": ">=12" } @@ -6757,7 +6786,6 @@ "integrity": "sha512-4gCtFXaAA3zYZdTp5s4Hl2sozuySsgz4jy1EnpBHNfpMa9dK1ZCG7viqBPCwXtmgc8nHqUsAu3G4gtmXkkY3Sw==", "deprecated": "Vue 2 has reached EOL and is no longer actively maintained. See https://v2.vuejs.org/eol/ for more details.", "license": "MIT", - "peer": true, "dependencies": { "@vue/compiler-sfc": "2.7.16", "csstype": "^3.1.0" @@ -7195,6 +7223,7 @@ "version": "0.25.12", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "dev": true, "hasInstallScript": true, "license": "MIT", "bin": { @@ -7239,6 +7268,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -7516,6 +7546,7 @@ "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, "license": "MIT", "engines": { "node": ">=12.0.0" @@ -7770,6 +7801,7 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -7863,6 +7895,7 @@ "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -8259,6 +8292,22 @@ "node": ">=18.18.0" } }, + "node_modules/husky": { + "version": "9.1.7", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", + "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", + "dev": true, + "license": "MIT", + "bin": { + "husky": "bin.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, "node_modules/iconv-lite": { "version": "0.7.2", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", @@ -8286,8 +8335,7 @@ "version": "6.2.2", "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.2.tgz", "integrity": "sha512-yjD9nARJ/jb1g+CvD0tlhUHOrJ9Sy0P8T9MF3YaLlHnSRpwPfpTX0XIvpmw3gAJUmEu3FiICLBDPXVwyEvrleg==", - "license": "Apache-2.0", - "peer": true + "license": "Apache-2.0" }, "node_modules/ieee754": { "version": "1.2.1", @@ -9192,6 +9240,7 @@ "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, "license": "MIT", "bin": { "json5": "lib/cli.js" @@ -9552,16 +9601,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/moment": { - "version": "2.30.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", - "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", - "license": "MIT", - "peer": true, - "engines": { - "node": "*" - } - }, "node_modules/mrmime": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", @@ -10126,6 +10165,7 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "devOptional": true, "license": "MIT", "engines": { "node": ">=12" @@ -10354,7 +10394,6 @@ "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.4.tgz", "integrity": "sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==", "license": "MIT", - "peer": true, "dependencies": { "dijkstrajs": "^1.0.1", "pngjs": "^5.0.0", @@ -10708,8 +10747,8 @@ "version": "4.60.0", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.0.tgz", "integrity": "sha512-yqjxruMGBQJ2gG4HtjZtAfXArHomazDHoFwFFmZZl0r7Pdo7qCIXKqKHZc8yeoMgzJJ+pO6pEEHa+V7uzWlrAQ==", + "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/estree": "1.0.8" }, @@ -10756,6 +10795,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -10893,7 +10933,6 @@ "resolved": "https://registry.npmjs.org/sass/-/sass-1.98.0.tgz", "integrity": "sha512-+4N/u9dZ4PrgzGgPlKnaaRQx64RO0JBKs9sDhQ2pLgN6JQZ25uPQZKQYaBJU48Kd5BxgXoJ4e09Dq7nMcOUW3A==", "license": "MIT", - "peer": true, "dependencies": { "chokidar": "^4.0.0", "immutable": "^5.1.5", @@ -10913,9 +10952,8 @@ "version": "1.98.0", "resolved": "https://registry.npmjs.org/sass-embedded/-/sass-embedded-1.98.0.tgz", "integrity": "sha512-Do7u6iRb6K+lrllcTkB1BXcHwOxcKe3rEfOF/GcCLE2w3WpddakRAosJOHFUR37DpsvimQXEt5abs3NzUjEIqg==", - "devOptional": true, + "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@bufbuild/protobuf": "^2.5.0", "colorjs.io": "^0.5.0", @@ -11262,7 +11300,7 @@ "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -11555,7 +11593,7 @@ "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", @@ -11566,7 +11604,7 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "devOptional": true, + "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -11976,7 +12014,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/sync-child-process/-/sync-child-process-1.0.2.tgz", "integrity": "sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "sync-message-port": "^1.0.0" @@ -11989,7 +12027,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/sync-message-port/-/sync-message-port-1.2.0.tgz", "integrity": "sha512-gAQ9qrUN/UCypHtGFbbe7Rc/f9bzO88IwrG8TDo/aMKAApKyD6E3W4Cm0EfhfBb6Z6SKt59tTCTfD+n1xmAvMg==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=16.0.0" @@ -12086,7 +12124,7 @@ "version": "5.46.1", "resolved": "https://registry.npmjs.org/terser/-/terser-5.46.1.tgz", "integrity": "sha512-vzCjQO/rgUuK9sf8VJZvjqiqiHFaZLnOiimmUuOKODxWL8mm/xua7viT7aqX7dgPY60otQjUotzFMmCB4VdmqQ==", - "devOptional": true, + "dev": true, "license": "BSD-2-Clause", "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -12105,7 +12143,7 @@ "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/tesseract.js": { @@ -12197,6 +12235,7 @@ "version": "0.2.15", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, "license": "MIT", "dependencies": { "fdir": "^6.5.0", @@ -12655,15 +12694,15 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz", "integrity": "sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/vite": { "version": "7.1.11", "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.11.tgz", "integrity": "sha512-uzcxnSDVjAopEUjljkWh8EIrg6tlzrjFUfMcR1EVsRDGwf/ccef0qQPRyOrROwhrTDaApueq+ja+KLPlzR/zdg==", + "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", @@ -13485,6 +13524,7 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -14056,7 +14096,6 @@ "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", @@ -14116,7 +14155,6 @@ "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.31.tgz", "integrity": "sha512-iV/sU9SzOlmA/0tygSmjkEN6Jbs3nPoIPFhCMLD2STrjgOU8DX7ZtzMhg4ahVwf5Rp9KoFzcXeB1ZrVbLBp5/Q==", "license": "MIT", - "peer": true, "dependencies": { "@vue/compiler-dom": "3.5.31", "@vue/compiler-sfc": "3.5.31", @@ -14804,7 +14842,6 @@ "integrity": "sha512-cIFJOD1DESzpjOBl763Kp1AH7UE/0fcdHe6rZXUdQ9c50uvgigvW97u3IcSeBwOkgqL/PXPBktBCh0KEu5L8XQ==", "dev": true, "license": "MIT", - "peer": true, "bin": { "rollup": "dist/bin/rollup" }, diff --git a/package.json b/package.json index f44dbafa..b7487739 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,9 @@ "build": "vite build", "build:dev": "vite build --mode development", "format:tests": "prettier --write \"tests/**/*.{js,ts}\"", + "format:tests:commit": "node scripts/pre-commit-format-tests.mjs", "format:tests:check": "prettier --check \"tests/**/*.{js,ts}\"", + "prepare": "node scripts/prepare-husky.mjs", "postinstall": "node scripts/postinstall-sync-playwright-root-links.mjs", "preview": "vite preview", "preview:prod": "npm run build && npm run preview -- --host 127.0.0.1 --port 4173", @@ -90,6 +92,7 @@ "@vitejs/plugin-vue": "^6.0.5", "@vitejs/plugin-vue-jsx": "^5.1.5", "@vue/test-utils": "^2.4.6", + "husky": "^9.1.7", "jsdom": "^29.0.0", "otpauth": "^9.5.0", "prettier": "2.8.8", diff --git a/scripts/pre-commit-format-tests.mjs b/scripts/pre-commit-format-tests.mjs new file mode 100644 index 00000000..7efe18d5 --- /dev/null +++ b/scripts/pre-commit-format-tests.mjs @@ -0,0 +1,111 @@ +import path from "node:path"; +import { spawnSync } from "node:child_process"; +import { fileURLToPath } from "node:url"; + +const scriptDir = path.dirname(fileURLToPath(import.meta.url)); +const repoRoot = path.resolve(scriptDir, ".."); +const gitPathspecs = [":(glob)tests/**/*.js", ":(glob)tests/**/*.ts"]; + +function run(command, args, options = {}) { + const result = spawnSync(command, args, { + cwd: repoRoot, + encoding: "utf8", + ...options, + }); + + if (result.error) { + throw result.error; + } + + return result; +} + +function fail(message) { + console.error(message); + process.exit(1); +} + +function runNpmScript(scriptName) { + if (process.env.npm_execpath) { + return run(process.execPath, [process.env.npm_execpath, "run", scriptName], { stdio: "inherit" }); + } + + const npmCommand = process.platform === "win32" ? "npm.cmd" : "npm"; + return run(npmCommand, ["run", scriptName], { + shell: process.platform === "win32", + stdio: "inherit", + }); +} + +function parseLines(output) { + return output + .split(/\r?\n/) + .map((line) => line.trim()) + .filter(Boolean); +} + +const worktreeResult = run("git", ["rev-parse", "--show-toplevel"]); + +if (worktreeResult.status !== 0) { + fail("Pre-commit formatting must run inside the front-end-vue Git worktree."); +} + +const gitRoot = path.resolve(worktreeResult.stdout.trim()); + +if (gitRoot !== repoRoot) { + fail(`Expected front-end-vue to be the Git root, but git reported: ${gitRoot}`); +} + +const unstagedTrackedResult = run("git", ["diff", "--name-only", "--", ...gitPathspecs]); + +if (unstagedTrackedResult.status !== 0) { + fail("Unable to inspect unstaged test-file changes before running Prettier."); +} + +const untrackedResult = run("git", ["ls-files", "--others", "--exclude-standard", "--", ...gitPathspecs]); + +if (untrackedResult.status !== 0) { + fail("Unable to inspect untracked test files before running Prettier."); +} + +const unsafePaths = [ + ...parseLines(unstagedTrackedResult.stdout), + ...parseLines(untrackedResult.stdout), +]; + +if (unsafePaths.length > 0) { + const formattedPaths = unsafePaths.map((filePath) => ` - ${filePath}`).join("\n"); + fail( + [ + "Pre-commit formatting aborted because tests contain unstaged changes.", + "Stage or discard these files before committing so the hook does not add unrelated work:", + formattedPaths, + ].join("\n") + ); +} + +console.log("Running Prettier for frontend test files..."); +const formatResult = runNpmScript("format:tests"); + +if (formatResult.status !== 0) { + process.exit(formatResult.status ?? 1); +} + +console.log("Restaging formatted frontend test files..."); +const knownFilesResult = run("git", ["ls-files", "--cached", "--others", "--exclude-standard", "--", ...gitPathspecs]); + +if (knownFilesResult.status !== 0) { + fail("Prettier completed, but the hook could not resolve test files for restaging."); +} + +const filesToStage = parseLines(knownFilesResult.stdout); + +if (filesToStage.length === 0) { + process.exit(0); +} + +const addResult = run("git", ["add", "--", ...filesToStage], { stdio: "inherit" }); + +if (addResult.status !== 0) { + fail("Prettier completed, but git add failed while restaging formatted test files."); +} diff --git a/scripts/prepare-husky.mjs b/scripts/prepare-husky.mjs new file mode 100644 index 00000000..0b9d1963 --- /dev/null +++ b/scripts/prepare-husky.mjs @@ -0,0 +1,38 @@ +import path from "node:path"; +import { spawnSync } from "node:child_process"; +import { fileURLToPath } from "node:url"; + +const scriptDir = path.dirname(fileURLToPath(import.meta.url)); +const repoRoot = path.resolve(scriptDir, ".."); +const huskyBin = path.join(repoRoot, "node_modules", "husky", "bin.js"); + +function run(command, args, options = {}) { + const result = spawnSync(command, args, { + cwd: repoRoot, + encoding: "utf8", + ...options, + }); + + if (result.error) { + throw result.error; + } + + return result; +} + +const worktreeResult = run("git", ["rev-parse", "--show-toplevel"]); + +if (worktreeResult.status !== 0) { + console.log("Skipping Husky install because front-end-vue is not attached to a Git worktree."); + process.exit(0); +} + +const gitRoot = path.resolve(worktreeResult.stdout.trim()); + +if (gitRoot !== repoRoot) { + console.log(`Skipping Husky install because Git root is ${gitRoot}, not ${repoRoot}.`); + process.exit(0); +} + +const huskyResult = run(process.execPath, [huskyBin], { stdio: "inherit" }); +process.exit(huskyResult.status ?? 1); diff --git a/tests/e2e/support/network.js b/tests/e2e/support/network.js index f1cfd0a7..04e42309 100644 --- a/tests/e2e/support/network.js +++ b/tests/e2e/support/network.js @@ -645,7 +645,10 @@ function mergeEdgeGatewayFixtureRecord(baseGateway, overrides = {}) { function createEdgeGatewayFixture(options = {}) { const primaryBrokerConnected = options.brokerConnected ?? true; const gatewayOverridesById = new Map( - (Array.isArray(options.gatewayOverrides) ? options.gatewayOverrides : []).map((gateway) => [Number(gateway.id), gateway]) + (Array.isArray(options.gatewayOverrides) ? options.gatewayOverrides : []).map((gateway) => [ + Number(gateway.id), + gateway, + ]) ); const baseGateways = [ { diff --git a/tests/unit/edge-gateway-workspace.spec.js b/tests/unit/edge-gateway-workspace.spec.js index 2fb344ae..d24cf1d7 100644 --- a/tests/unit/edge-gateway-workspace.spec.js +++ b/tests/unit/edge-gateway-workspace.spec.js @@ -101,9 +101,11 @@ describe("edge gateway workspace contract", () => { }); it("keeps route selection in the page layer and lets the department page deep-link into the canonical detail page", () => { - expect(workspaceSource).toContain('selectedGatewayId: {'); + expect(workspaceSource).toContain("selectedGatewayId: {"); expect(workspaceSource).toContain('defineEmits(["open-gateway-page", "select-gateway"])'); - expect(workspaceSource).toContain("const routeSelectedGatewayId = computed(() => normalizeGatewayId(props.selectedGatewayId));"); + expect(workspaceSource).toContain( + "const routeSelectedGatewayId = computed(() => normalizeGatewayId(props.selectedGatewayId));" + ); expect(workspaceSource).toContain('data-testid="gateway-unavailable-state"'); expect(edgeGatewaysViewSource).toContain('route.name === "edgegatewaydetail"'); expect(edgeGatewaysViewSource).toContain(':selected-gateway-id="selectedGatewayId"');