@inixiative/config 0.1.0 → 0.2.1
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 +2 -1
- package/dist/cli.js +93 -9
- package/lefthook/base.yml +8 -0
- package/package.json +5 -1
- package/versions.json +2 -1
package/README.md
CHANGED
|
@@ -12,6 +12,7 @@ Shared toolchain for the inixiative ecosystem: tsconfig/biome/tsup presets, a ve
|
|
|
12
12
|
| `@inixiative/config/biome/base.json` | formatter + linter core (single quotes, lineWidth 100, recommended + strictness block) |
|
|
13
13
|
| `@inixiative/config/biome/react.json` | overlay: hook dependency linting |
|
|
14
14
|
| `@inixiative/config/tsup` | `node(options)` / `react(options)` build presets |
|
|
15
|
+
| `@inixiative/config/lefthook/base.yml` | pre-commit hooks: typecheck + biome on staged files |
|
|
15
16
|
|
|
16
17
|
Adoption is three stub files plus the devDependency:
|
|
17
18
|
|
|
@@ -55,7 +56,7 @@ bunx @inixiative/config scan [root]
|
|
|
55
56
|
bunx @inixiative/config train [root]
|
|
56
57
|
```
|
|
57
58
|
|
|
58
|
-
`check` is read-only and exits non-zero on drift — run it in CI after a frozen-lockfile install. It verifies toolchain pins, `"latest"` ranges, `packageManager`/`.bun-version`, legacy `bun.lockb`, a committed (tracked, un-ignored) `bun.lock`, required scripts (`check`/`typecheck`/`lint`/`test`), stub `extends`, presence of this package, and for every ecosystem dependency that the declared range admits the blessed version and the lockfile actually resolves to it (the stale-lockfile class).
|
|
59
|
+
`check` is read-only and exits non-zero on drift — run it in CI after a frozen-lockfile install. It verifies toolchain pins, `"latest"` ranges, `packageManager`/`.bun-version`, legacy `bun.lockb`, a committed (tracked, un-ignored) `bun.lock`, required scripts (`check`/`typecheck`/`lint`/`test`), lefthook (dep + `lefthook.yml` extending the shared hooks + `prepare` script; git repos only), stub `extends`, presence of this package, and for every ecosystem dependency that the declared range admits the blessed version and the lockfile actually resolves to it (the stale-lockfile class).
|
|
59
60
|
|
|
60
61
|
`sync` applies every fix, re-locks via `bun install`, and runs `bun update` on stale ecosystem entries. It refuses to run on a dirty working tree without `--force`. The react preset is inferred from a `react` dependency; override with `--preset`. Missing scripts are filled with defaults; existing script bodies are never touched.
|
|
61
62
|
|
package/dist/cli.js
CHANGED
|
@@ -69,7 +69,7 @@ var tryParseJsonc = (text) => {
|
|
|
69
69
|
}
|
|
70
70
|
};
|
|
71
71
|
var parseRange = (range) => {
|
|
72
|
-
const match = range.match(/^(\^|~|>=)?\s*(\d+)\.(\d+)\.(\d+)
|
|
72
|
+
const match = range.match(/^(\^|~|>=)?\s*(\d+)\.(\d+)\.(\d+)$/);
|
|
73
73
|
if (!match) return null;
|
|
74
74
|
return {
|
|
75
75
|
op: match[1] ?? "=",
|
|
@@ -90,7 +90,9 @@ var admits = (range, version) => {
|
|
|
90
90
|
if (parts.some((p) => p === true)) return true;
|
|
91
91
|
return parts.includes(null) ? null : false;
|
|
92
92
|
}
|
|
93
|
-
const
|
|
93
|
+
const target = range.trim();
|
|
94
|
+
if (version.includes("-")) return target === version ? true : null;
|
|
95
|
+
const parsed = parseRange(target);
|
|
94
96
|
if (!parsed) return null;
|
|
95
97
|
const cmp = compare(version, parsed.version);
|
|
96
98
|
if (parsed.op === "=") return cmp === 0;
|
|
@@ -98,12 +100,22 @@ var admits = (range, version) => {
|
|
|
98
100
|
if (cmp < 0) return false;
|
|
99
101
|
const [major, minor] = parsed.version.split(".").map(Number);
|
|
100
102
|
const [vMajor, vMinor] = version.split(".").map(Number);
|
|
101
|
-
if (parsed.op === "^")
|
|
103
|
+
if (parsed.op === "^") {
|
|
104
|
+
if (major > 0) return vMajor === major;
|
|
105
|
+
if (minor > 0) return vMajor === 0 && vMinor === minor;
|
|
106
|
+
return cmp === 0;
|
|
107
|
+
}
|
|
102
108
|
return vMajor === major && vMinor === minor;
|
|
103
109
|
};
|
|
104
110
|
var lockedVersion = (lockText, name) => {
|
|
105
|
-
const
|
|
106
|
-
|
|
111
|
+
const lock = tryParseJsonc(lockText);
|
|
112
|
+
const packages = lock?.packages;
|
|
113
|
+
if (!packages || typeof packages !== "object") return null;
|
|
114
|
+
const entry = packages[name];
|
|
115
|
+
const spec = Array.isArray(entry) ? entry[0] : null;
|
|
116
|
+
if (typeof spec !== "string" || !spec.startsWith(`${name}@`)) return null;
|
|
117
|
+
const version = spec.slice(name.length + 1);
|
|
118
|
+
return /^\d/.test(version) ? version : null;
|
|
107
119
|
};
|
|
108
120
|
var topoOrder = (root, manifest2) => {
|
|
109
121
|
const repos = discoverRepos(root, manifest2).map((repo) => ({
|
|
@@ -273,15 +285,87 @@ function inspect(dir2, manifest2, presetOverride) {
|
|
|
273
285
|
level: "error",
|
|
274
286
|
message: "bun.lock missing \u2192 run bun install and commit the lockfile"
|
|
275
287
|
});
|
|
276
|
-
} else
|
|
288
|
+
} else {
|
|
289
|
+
const ignoreStatus = spawnSync("git", ["check-ignore", "-q", "bun.lock"], {
|
|
290
|
+
cwd: dir2
|
|
291
|
+
}).status;
|
|
292
|
+
if (ignoreStatus === 0) {
|
|
293
|
+
findings.push({
|
|
294
|
+
level: "error",
|
|
295
|
+
message: "bun.lock is gitignored \u2192 removing the ignore rule; commit the lockfile",
|
|
296
|
+
fix: () => {
|
|
297
|
+
const gitignorePath = join(dir2, ".gitignore");
|
|
298
|
+
if (!existsSync(gitignorePath)) return;
|
|
299
|
+
const kept = readFileSync(gitignorePath, "utf8").split("\n").filter((line) => !/^\s*bun\.lockb?\s*$/.test(line));
|
|
300
|
+
writeFileSync(gitignorePath, kept.join("\n"));
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
} else if (ignoreStatus === 1) {
|
|
304
|
+
const trackedStatus = spawnSync("git", ["ls-files", "--error-unmatch", "bun.lock"], {
|
|
305
|
+
cwd: dir2
|
|
306
|
+
}).status;
|
|
307
|
+
if (trackedStatus === 1) {
|
|
308
|
+
findings.push({
|
|
309
|
+
level: "error",
|
|
310
|
+
message: "bun.lock untracked \u2192 staging it; commit the lockfile",
|
|
311
|
+
fix: () => {
|
|
312
|
+
spawnSync("git", ["add", "bun.lock"], { cwd: dir2 });
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
} else if (trackedStatus !== 0) {
|
|
316
|
+
findings.push({
|
|
317
|
+
level: "warn",
|
|
318
|
+
message: "git ls-files failed \u2014 cannot verify the lockfile is tracked"
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
} else {
|
|
322
|
+
findings.push({
|
|
323
|
+
level: "warn",
|
|
324
|
+
message: "git check-ignore failed \u2014 cannot verify the lockfile is not ignored"
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
const lefthookPin = manifest2.toolchain.lefthook;
|
|
329
|
+
if (lefthookPin && !DEP_FIELDS.some((field) => pkg[field]?.lefthook)) {
|
|
330
|
+
findings.push({
|
|
331
|
+
level: "error",
|
|
332
|
+
message: `lefthook missing \u2192 devDependency ${lefthookPin}`,
|
|
333
|
+
fix: () => {
|
|
334
|
+
pkg.devDependencies ??= {};
|
|
335
|
+
pkg.devDependencies.lefthook = lefthookPin;
|
|
336
|
+
touch();
|
|
337
|
+
}
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
const lefthookPath = join(dir2, "lefthook.yml");
|
|
341
|
+
const lefthookStub = "extends:\n - node_modules/@inixiative/config/lefthook/base.yml\n";
|
|
342
|
+
if (!existsSync(lefthookPath)) {
|
|
277
343
|
findings.push({
|
|
278
344
|
level: "error",
|
|
279
|
-
message: "
|
|
345
|
+
message: "lefthook.yml missing \u2192 stub extending @inixiative/config/lefthook/base.yml",
|
|
346
|
+
fix: () => writeFileSync(lefthookPath, lefthookStub)
|
|
280
347
|
});
|
|
281
|
-
} else if (
|
|
348
|
+
} else if (!readFileSync(lefthookPath, "utf8").includes("lefthook/base.yml")) {
|
|
282
349
|
findings.push({
|
|
283
350
|
level: "error",
|
|
284
|
-
message: "
|
|
351
|
+
message: "lefthook.yml does not extend the shared hooks \u2192 replaced with extends stub (local hooks overwritten \u2014 review the diff)",
|
|
352
|
+
fix: () => writeFileSync(lefthookPath, lefthookStub)
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
if (!pkg.scripts?.prepare) {
|
|
356
|
+
findings.push({
|
|
357
|
+
level: "error",
|
|
358
|
+
message: 'scripts.prepare missing \u2192 "lefthook install"',
|
|
359
|
+
fix: () => {
|
|
360
|
+
pkg.scripts ??= {};
|
|
361
|
+
pkg.scripts.prepare = "lefthook install";
|
|
362
|
+
touch();
|
|
363
|
+
}
|
|
364
|
+
});
|
|
365
|
+
} else if (!pkg.scripts.prepare.includes("lefthook")) {
|
|
366
|
+
findings.push({
|
|
367
|
+
level: "warn",
|
|
368
|
+
message: "scripts.prepare does not run lefthook install \u2014 hooks will not auto-install"
|
|
285
369
|
});
|
|
286
370
|
}
|
|
287
371
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inixiative/config",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Shared toolchain for the inixiative ecosystem: tsconfig/biome/tsup presets, a version manifest (BOM), and a sync/check CLI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"dist",
|
|
20
20
|
"tsconfig",
|
|
21
21
|
"biome",
|
|
22
|
+
"lefthook",
|
|
22
23
|
"versions.json",
|
|
23
24
|
"README.md"
|
|
24
25
|
],
|
|
@@ -29,12 +30,14 @@
|
|
|
29
30
|
"./tsconfig/react.json": "./tsconfig/react.json",
|
|
30
31
|
"./biome/base.json": "./biome/base.json",
|
|
31
32
|
"./biome/react.json": "./biome/react.json",
|
|
33
|
+
"./lefthook/base.yml": "./lefthook/base.yml",
|
|
32
34
|
"./tsup": {
|
|
33
35
|
"types": "./dist/tsup.d.ts",
|
|
34
36
|
"import": "./dist/tsup.js"
|
|
35
37
|
}
|
|
36
38
|
},
|
|
37
39
|
"scripts": {
|
|
40
|
+
"prepare": "lefthook install",
|
|
38
41
|
"build": "tsup",
|
|
39
42
|
"test": "bun test",
|
|
40
43
|
"typecheck": "tsc --noEmit",
|
|
@@ -47,6 +50,7 @@
|
|
|
47
50
|
"devDependencies": {
|
|
48
51
|
"@biomejs/biome": "2.5.2",
|
|
49
52
|
"@types/bun": "1.3.14",
|
|
53
|
+
"lefthook": "2.1.9",
|
|
50
54
|
"tsup": "8.5.1",
|
|
51
55
|
"typescript": "6.0.3"
|
|
52
56
|
},
|