diff --git a/lefthook.yml b/lefthook.yml new file mode 100644 index 00000000..58f346f6 --- /dev/null +++ b/lefthook.yml @@ -0,0 +1,27 @@ +# Autofix-only: these commands never block a commit. Unfixable lint errors are +# printed for visibility, but `|| true` keeps the hook green. CI is what gates. +# +# `glob` scopes each tool to the file types it handles, so a commit touching +# only e.g. Markdown skips all three commands instead of spawning no-op +# processes. Lefthook already skips a command when its file list comes out +# empty, so the globs are for clarity and speed, not safety. +pre-commit: + commands: + lint: + priority: 1 + # oxlint reads .astro too, and CI's bare `oxlint` discovers them. + glob: '*.{js,jsx,mjs,cjs,mts,cts,ts,tsx,astro}' + run: pnpm exec oxlint --fix {staged_files} || true + stage_fixed: true + fmt: + priority: 2 + # Must cover every type oxfmt handles, or the hook stays silent on a + # file that `pnpm run check` then fails on in CI. + glob: '*.{js,jsx,mjs,cjs,mts,cts,ts,tsx,json,jsonc,yaml,yml,md,mdx,html}' + run: pnpm exec oxfmt {staged_files} || true + stage_fixed: true + fmt-astro: + priority: 2 + glob: '*.astro' + run: pnpm exec prettier --write {staged_files} || true + stage_fixed: true diff --git a/package.json b/package.json index 12e0bbc5..626adb08 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "@vitest/coverage-istanbul": "4.1.1", "buffer": "6.0.3", "git-cliff": "2.13.1", + "lefthook": "2.1.10", "parcel": "2.16.4", "process": "0.11.10", "typescript": "5.9.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 175f885b..a423bc94 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -23,6 +23,9 @@ importers: git-cliff: specifier: 2.13.1 version: 2.13.1 + lefthook: + specifier: 2.1.10 + version: 2.1.10 oxfmt: specifier: 0.61.0 version: 0.61.0 @@ -2951,6 +2954,60 @@ packages: resolution: {integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==} engines: {node: '>= 8'} + lefthook-darwin-arm64@2.1.10: + resolution: {integrity: sha512-nw+X8wRNDoUUV6WSteyKBbcLySq+fsmZt5WV/s50ZJpysmsDKJOUMln6SllNfP+60dzUahAO7REco/2633BsLg==} + cpu: [arm64] + os: [darwin] + + lefthook-darwin-x64@2.1.10: + resolution: {integrity: sha512-KQ/bHmvpkFdHMn4pZnUdTf+GuSC+aBBgBTxZT4GW+6cSf+qbErKZBhK7cH6BmILsvx43+VzEArvHYY7YOfRFOQ==} + cpu: [x64] + os: [darwin] + + lefthook-freebsd-arm64@2.1.10: + resolution: {integrity: sha512-8su6DwydP7+pv7kG0zCtjphqsw4ouOnfexRUErapy5GTxYBoUOhYz3RSHTSWNRsK6W4jva7FPUh2Lp5/PSn30w==} + cpu: [arm64] + os: [freebsd] + + lefthook-freebsd-x64@2.1.10: + resolution: {integrity: sha512-GeAJEFxko3Lk+AsnS3NleAFrpyMLFUKOlgJvPKuU0xHwVEI/z+ZoCcmuO0BX+4CS0NLbZhC/YQAvBASqDvvVdQ==} + cpu: [x64] + os: [freebsd] + + lefthook-linux-arm64@2.1.10: + resolution: {integrity: sha512-1sHTCmpTWjVMs+yKPBLRNT1kuuIr1yjietlk7rCB6wFPVOS6Ph3o2zPFH2AvW1UymHlqwyHXzBr9EtDpQ7j1mQ==} + cpu: [arm64] + os: [linux] + + lefthook-linux-x64@2.1.10: + resolution: {integrity: sha512-z/VlRB3bh6mBvW3r1rwnJ5vP8z+Krx5gJzkZ4veDXh+6FlRTx8wtd3g3fllOv/yZMxkgmL3fQoFXv05Esa7vBQ==} + cpu: [x64] + os: [linux] + + lefthook-openbsd-arm64@2.1.10: + resolution: {integrity: sha512-430zL8sSIKw5P0YXGG6PB+eAhHa06n0PXuaERaAQE4Ss3odfqwnl5Mq9hQmkEnOS1EGiQEKkd0UHv/i4PtMNIQ==} + cpu: [arm64] + os: [openbsd] + + lefthook-openbsd-x64@2.1.10: + resolution: {integrity: sha512-bgkO8PphGZVDhQgCJ524aYYPI5491pVmCiLPGjBIo1AvOSlIyw4N1Y+1C3QfqwEmechzw+Aq16SNc8pqv6UuXg==} + cpu: [x64] + os: [openbsd] + + lefthook-windows-arm64@2.1.10: + resolution: {integrity: sha512-5Q6etF0Fla2DDA4ilDySrdNgiR5+W7cJZwnZ69Je3kvWCaWm4wnkuc8FEdjp3kiL2x3ZXipdI00f5vpO8aWmog==} + cpu: [arm64] + os: [win32] + + lefthook-windows-x64@2.1.10: + resolution: {integrity: sha512-c/XH8YZtylG4XaxzqFfXluvq2LXq2W/p54Bnzn3+Z7E5X2Fk3JlFJAibulMbIt2+w8T7UI/r97ok5GqE4kGaeA==} + cpu: [x64] + os: [win32] + + lefthook@2.1.10: + resolution: {integrity: sha512-K7mM4WoqMwqfXYK11EHy+lSH1uW8XHni3Yn/bSqyerPkUPygGdf3xn18JoV5HyA06xuQL3ofGAOjG01QX9oJ4w==} + hasBin: true + lightningcss-android-arm64@1.30.2: resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==} engines: {node: '>= 12.0.0'} @@ -7208,6 +7265,49 @@ snapshots: klona@2.0.6: {} + lefthook-darwin-arm64@2.1.10: + optional: true + + lefthook-darwin-x64@2.1.10: + optional: true + + lefthook-freebsd-arm64@2.1.10: + optional: true + + lefthook-freebsd-x64@2.1.10: + optional: true + + lefthook-linux-arm64@2.1.10: + optional: true + + lefthook-linux-x64@2.1.10: + optional: true + + lefthook-openbsd-arm64@2.1.10: + optional: true + + lefthook-openbsd-x64@2.1.10: + optional: true + + lefthook-windows-arm64@2.1.10: + optional: true + + lefthook-windows-x64@2.1.10: + optional: true + + lefthook@2.1.10: + optionalDependencies: + lefthook-darwin-arm64: 2.1.10 + lefthook-darwin-x64: 2.1.10 + lefthook-freebsd-arm64: 2.1.10 + lefthook-freebsd-x64: 2.1.10 + lefthook-linux-arm64: 2.1.10 + lefthook-linux-x64: 2.1.10 + lefthook-openbsd-arm64: 2.1.10 + lefthook-openbsd-x64: 2.1.10 + lefthook-windows-arm64: 2.1.10 + lefthook-windows-x64: 2.1.10 + lightningcss-android-arm64@1.30.2: optional: true diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index db3a0b79..52ba6f88 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -9,6 +9,8 @@ allowBuilds: '@parcel/watcher': false '@swc/core': false esbuild: false + # lefthook's postinstall is what installs the git hooks. + lefthook: true lmdb: false msgpackr-extract: false sharp: false