@howells/husky 0.2.2 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -3
- package/bin/detect.mjs +9 -34
- package/bin/howells-husky.mjs +3 -20
- package/package.json +10 -6
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ In `package.json`:
|
|
|
18
18
|
"prepare": "howells-husky"
|
|
19
19
|
},
|
|
20
20
|
"lint-staged": {
|
|
21
|
-
"*.{js,ts,jsx,tsx,json,jsonc,css}": "howells-
|
|
21
|
+
"*.{js,ts,jsx,tsx,json,jsonc,css,md,mdx}": "howells-oxfmt --write"
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
```
|
|
@@ -31,7 +31,20 @@ That's it. On `pnpm install`, the hooks are installed automatically.
|
|
|
31
31
|
|
|
32
32
|
### Pre-commit
|
|
33
33
|
|
|
34
|
-
Runs `pnpm lint-staged` — formats staged files with the configured Howells formatter. Use `howells-
|
|
34
|
+
Runs `pnpm lint-staged` — formats staged files with the configured Howells formatter. Use `howells-oxfmt --write`.
|
|
35
|
+
|
|
36
|
+
**Staging is format-only. Never put `howells-fix` in lint-staged.** Formatting only moves whitespace, so it is safe to apply to a file you are already committing. `howells-fix` also runs `oxlint --fix`, and four rules that ultracite enables at error severity rewrite test assertions under that supposedly safe tier:
|
|
37
|
+
|
|
38
|
+
| Rule | Rewrites |
|
|
39
|
+
| --- | --- |
|
|
40
|
+
| `vitest/prefer-strict-equal` | `toEqual` → `toStrictEqual` |
|
|
41
|
+
| `vitest/prefer-to-be-truthy` | `toBe(true)` → `toBeTruthy()` |
|
|
42
|
+
| `vitest/prefer-to-be-falsy` | `toBe(false)` → `toBeFalsy()` |
|
|
43
|
+
| `vitest/prefer-describe-function-title` | the string title of a `describe` block |
|
|
44
|
+
|
|
45
|
+
The first three weaken what the assertion checks: `toBeTruthy()` passes on `1`, `"0"` and `{}`, which `toBe(true)` rejects. Applied on commit, they rewrite tests silently, in files the author already reviewed, and the commit still looks like the diff that was staged. One repository had 121 assertions changed this way before anyone noticed. This is an oxlint defect — `--fix` is documented as the tier that does not change behaviour — but until it is fixed, keep lint out of the commit hook. Pre-push runs the full lint and reports these as findings, which is where they belong.
|
|
46
|
+
|
|
47
|
+
The older names `howells-ox-fix` and `howells-format` are still accepted (legacy) for projects mid-migration; both format only.
|
|
35
48
|
|
|
36
49
|
### Pre-push
|
|
37
50
|
|
|
@@ -63,7 +76,7 @@ Your `package.json` must have:
|
|
|
63
76
|
- a `"prepush"` script appropriate to the repository, or both:
|
|
64
77
|
- a `"typecheck"` script (e.g. `tsc --noEmit` or `turbo run typecheck`)
|
|
65
78
|
- a `"lint"` script (e.g. `howells-lint` or `turbo run lint`)
|
|
66
|
-
- inline or standard external lint-staged configuration
|
|
79
|
+
- inline or standard external lint-staged configuration appropriate to the project, running a formatter only
|
|
67
80
|
|
|
68
81
|
## Why a package?
|
|
69
82
|
|
package/bin/detect.mjs
CHANGED
|
@@ -5,16 +5,16 @@
|
|
|
5
5
|
* around behaviour that is unit-testable in isolation.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
// `howells-fix`
|
|
9
|
-
// and
|
|
10
|
-
//
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
];
|
|
8
|
+
// Staging formats and nothing else. `howells-fix` also runs `oxlint --fix`,
|
|
9
|
+
// and four vitest rules that ultracite enables at error severity rewrite test
|
|
10
|
+
// assertions under that tier — `toBe(true)` becomes `toBeTruthy()`, which
|
|
11
|
+
// passes on values the original rejected. Applied on commit that happens
|
|
12
|
+
// silently, inside files the author has already reviewed. Linting belongs in
|
|
13
|
+
// pre-push, where it reports rather than rewrites.
|
|
14
|
+
export const recommendedLintStagedCommand = "howells-oxfmt --write";
|
|
16
15
|
|
|
17
|
-
export const
|
|
16
|
+
export const recommendedLintStagedGlob =
|
|
17
|
+
"*.{js,ts,jsx,tsx,json,jsonc,css,md,mdx}";
|
|
18
18
|
|
|
19
19
|
// Standard configuration names supported by lint-staged. Package-level files
|
|
20
20
|
// in a monorepo are discovered by lint-staged itself; the installer only needs
|
|
@@ -37,31 +37,6 @@ export function findLintStagedConfigFile(exists) {
|
|
|
37
37
|
return lintStagedConfigFileNames.find((file) => exists(file));
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
/**
|
|
41
|
-
* Flatten a lint-staged config object into the list of command strings it runs.
|
|
42
|
-
* Values may be a single command string or an array of them.
|
|
43
|
-
*/
|
|
44
|
-
export function lintStagedCommandValues(config) {
|
|
45
|
-
return Object.values(config).flatMap((value) => {
|
|
46
|
-
if (typeof value === "string") {
|
|
47
|
-
return [value];
|
|
48
|
-
}
|
|
49
|
-
if (Array.isArray(value)) {
|
|
50
|
-
return value.filter((item) => typeof item === "string");
|
|
51
|
-
}
|
|
52
|
-
return [];
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* True when a single lint-staged command invokes a supported Howells formatter.
|
|
58
|
-
*/
|
|
59
|
-
export function usesSupportedFormatter(command) {
|
|
60
|
-
return lintStagedFormatterCommands.some((formatter) =>
|
|
61
|
-
command.includes(formatter)
|
|
62
|
-
);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
40
|
/**
|
|
66
41
|
* Decide whether the primary `husky` spawn failed to launch and we should
|
|
67
42
|
* fall back to `npx husky`. A spawn that launched but exited non-zero is not a
|
package/bin/howells-husky.mjs
CHANGED
|
@@ -28,10 +28,9 @@ import path from "node:path";
|
|
|
28
28
|
import {
|
|
29
29
|
fallbackFailed,
|
|
30
30
|
findLintStagedConfigFile,
|
|
31
|
-
lintStagedCommandValues,
|
|
32
31
|
recommendedLintStagedCommand,
|
|
32
|
+
recommendedLintStagedGlob,
|
|
33
33
|
shouldUseNpxFallback,
|
|
34
|
-
usesSupportedFormatter,
|
|
35
34
|
} from "./detect.mjs";
|
|
36
35
|
|
|
37
36
|
const scriptDir = import.meta.dirname;
|
|
@@ -127,26 +126,10 @@ if (existsSync(packageJsonPath)) {
|
|
|
127
126
|
"[@howells/husky] Warning: no inline or external lint-staged config found."
|
|
128
127
|
);
|
|
129
128
|
console.warn(
|
|
130
|
-
` Add: "lint-staged": { "
|
|
129
|
+
` Add: "lint-staged": { "${recommendedLintStagedGlob}": "${recommendedLintStagedCommand}" }`
|
|
131
130
|
);
|
|
132
131
|
}
|
|
133
132
|
|
|
134
|
-
// Inline static configs can be checked directly. External JavaScript configs
|
|
135
|
-
// may compute commands dynamically, so lint-staged owns their validation.
|
|
136
|
-
const lsConfig = packageJson["lint-staged"];
|
|
137
|
-
if (lsConfig) {
|
|
138
|
-
const commands = lintStagedCommandValues(lsConfig);
|
|
139
|
-
const usesHowells = commands.some(usesSupportedFormatter);
|
|
140
|
-
if (!usesHowells) {
|
|
141
|
-
console.warn(
|
|
142
|
-
"[@howells/husky] Warning: lint-staged should use a supported Howells formatter."
|
|
143
|
-
);
|
|
144
|
-
console.warn(
|
|
145
|
-
` Expected: "*.{js,ts,jsx,tsx,json,jsonc,css}": "${recommendedLintStagedCommand}"`
|
|
146
|
-
);
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
133
|
// Projects can own an appropriately scoped pre-push gate. Older projects
|
|
151
134
|
// retain the package's typecheck + lint fallback until they add one.
|
|
152
135
|
const scripts = packageJson.scripts || {};
|
|
@@ -162,4 +145,4 @@ if (existsSync(packageJsonPath)) {
|
|
|
162
145
|
}
|
|
163
146
|
}
|
|
164
147
|
|
|
165
|
-
console.
|
|
148
|
+
console.error("[@howells/husky] Hooks installed.");
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@howells/husky",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.5",
|
|
4
4
|
"description": "Standardised git hooks for Howells projects. Immutable pre-commit and pre-push configuration.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
|
-
"url": "git+https://github.com/
|
|
8
|
+
"url": "git+https://github.com/howells/husky.git"
|
|
9
9
|
},
|
|
10
10
|
"bin": {
|
|
11
11
|
"howells-husky": "bin/howells-husky.mjs"
|
|
@@ -22,11 +22,14 @@
|
|
|
22
22
|
"./package.json": "./package.json"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"husky": "^9.1.7"
|
|
26
|
-
"lint-staged": "^16.4.0"
|
|
25
|
+
"husky": "^9.1.7"
|
|
27
26
|
},
|
|
28
27
|
"devDependencies": {
|
|
29
|
-
"@howells/lint": "^1.1.0"
|
|
28
|
+
"@howells/lint": "^1.1.0",
|
|
29
|
+
"lint-staged": "^16.4.0"
|
|
30
|
+
},
|
|
31
|
+
"lint-staged": {
|
|
32
|
+
"*.{js,mjs,cjs,ts,tsx,json,jsonc,css,md}": "howells-oxfmt --write"
|
|
30
33
|
},
|
|
31
34
|
"engines": {
|
|
32
35
|
"node": ">=24.15.0"
|
|
@@ -35,6 +38,7 @@
|
|
|
35
38
|
"lint": "howells-check --config=oxlint.config.ts package.json bin hooks README.md oxlint.config.ts oxfmt.config.ts",
|
|
36
39
|
"lint:fix": "howells-fix --config=oxlint.config.ts package.json bin hooks README.md oxlint.config.ts oxfmt.config.ts",
|
|
37
40
|
"format": "howells-oxfmt --write package.json bin hooks README.md oxlint.config.ts oxfmt.config.ts",
|
|
38
|
-
"test": "node --test bin/detect.test.mjs bin/pre-push.test.mjs"
|
|
41
|
+
"test": "node --test bin/detect.test.mjs bin/pre-push.test.mjs",
|
|
42
|
+
"prepush": "pnpm lint && pnpm test"
|
|
39
43
|
}
|
|
40
44
|
}
|