@hublo/sentinel 1.4.0-alpha.16 → 1.4.0-alpha.17

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.
@@ -16,7 +16,7 @@ import {
16
16
  registerAdapters,
17
17
  resolve,
18
18
  resolveBin
19
- } from "../chunk-XGC2KK5J.js";
19
+ } from "../chunk-I64KRL6O.js";
20
20
  import {
21
21
  WORKSPACE_ROOT_MARKER,
22
22
  ensureWorkspacePrep,
@@ -8922,6 +8922,7 @@ function resolveVitest(cwd) {
8922
8922
  const fromModule = resolveBin(cwd, "vitest");
8923
8923
  return fromModule !== void 0 ? { bin: fromModule, origin: "module" } : { bin: void 0, origin: "module" };
8924
8924
  }
8925
+ var FORMATTABLE = /\.(m|c)?(j|t)sx?$|\.json$/;
8925
8926
  var VitestAdapter = class extends BaseAdapter {
8926
8927
  target = "test";
8927
8928
  runner = "vitest";
@@ -8960,21 +8961,48 @@ var VitestAdapter = class extends BaseAdapter {
8960
8961
  * MODULE's decision: `printWidth` lives in its own config, and 12 modules already set their
8961
8962
  * own. Guessing it is how a tool starts owning a setting it does not own.
8962
8963
  *
8963
- * The same delegation the build role asks a human to do by hand, done. A module that has not
8964
- * adopted the format role has no formatter to invoke, and this says nothing rather than
8965
- * choosing one for it.
8964
+ * The same delegation the build role asks a human to do by hand, done.
8965
+ *
8966
+ * ## ⚠️ Two boundaries, both learned by crossing them
8967
+ *
8968
+ * ### Only a module that has a formatter CONFIG
8969
+ *
8970
+ * The question is not "can a formatter be found". It always can: sentinel depends on oxfmt and
8971
+ * ships the binary, so `resolveOxfmt` falls back to its own install and never returns undefined
8972
+ * once sentinel is installed. Asking it that way meant a module with no oxfmt config was
8973
+ * formatted with oxfmt's DEFAULTS, which is a style nobody here chose.
8974
+ *
8975
+ * So the CONFIG is read. A module that wrote its own `.oxfmtrc.json` without adopting the role
8976
+ * has still stated a style, and running it is delegation; running oxfmt with no config is us
8977
+ * choosing one.
8978
+ *
8979
+ * Measured on `apps/nest/microservices/institution`, which has not adopted format and whose lint
8980
+ * forbids semicolons: `institution:lint` went from green to failing, thousands of `semi`, on a
8981
+ * module whose 2958 tests pass. So the adoption is read, not the binary.
8982
+ *
8983
+ * ### Only the files this just WROTE
8984
+ *
8985
+ * `--write .` is a whole-directory pass, and that is not a tidy-up. Same measurement: 1813 files
8986
+ * changed, 47333 insertions, 55506 deletions, in a module whose migration touched 268. A
8987
+ * migration diff is read by a person.
8988
+ *
8989
+ * A module that has not adopted format keeps what was written exactly as written, and is told so.
8990
+ * The codemod rewrites tokens in place, so those files keep the shape they already had.
8966
8991
  */
8967
8992
  async afterInit(ctx) {
8968
- const oxfmt = resolveOxfmt(ctx.cwd);
8969
- if (oxfmt === void 0) {
8993
+ const written = (ctx.written ?? []).filter((file) => FORMATTABLE.test(file));
8994
+ if (written.length === 0) return Promise.resolve();
8995
+ if (readFormatAdoption(ctx.cwd).configFile === null) {
8970
8996
  this.say(
8971
- `no formatter adopted here, so what was written keeps the shape it was written in. Run your own formatter over it before committing.`
8997
+ `no formatter configured here, so the ${written.length} file(s) this wrote keep the shape they were written in. Run your own formatter over them before committing.`
8972
8998
  );
8973
8999
  return Promise.resolve();
8974
9000
  }
8975
- const pass = spawnSync5(oxfmt, ["--write", "."], { cwd: ctx.cwd, encoding: "utf8" });
9001
+ const oxfmt = resolveOxfmt(ctx.cwd);
9002
+ if (oxfmt === void 0) return Promise.resolve();
9003
+ const pass = spawnSync5(oxfmt, ["--write", ...written], { cwd: ctx.cwd, encoding: "utf8" });
8976
9004
  this.say(
8977
- pass.status === 0 ? `formatted what this wrote with the module's own oxfmt config, so its \`--run --format\` passes on files it did not write itself.` : (
9005
+ pass.status === 0 ? `formatted the ${written.length} file(s) this wrote with the module's own oxfmt config, so its \`--run --format\` passes on files it did not write itself.` : (
8978
9006
  // Adoption SUCCEEDED; only the tidy-up did not. Failing here would revert a migration
8979
9007
  // over a formatting pass, which is the wrong trade.
8980
9008
  `the module's formatter could not run over what this wrote (${pass.status ?? "no exit code"}). Adoption itself is applied; run \`sentinel --run --format --fix\` before committing.`
@@ -10209,9 +10237,11 @@ async function dispatch(opts) {
10209
10237
  fix: false
10210
10238
  });
10211
10239
  }
10240
+ const written = [];
10212
10241
  for (const change of applyPlan(opts.cwd, plan4)) {
10213
10242
  process.stderr.write(` ${change.deleted ? "removed" : "wrote"} ${change.path}
10214
10243
  `);
10244
+ if (!change.deleted) written.push(change.path);
10215
10245
  }
10216
10246
  for (const note of plan4.notes ?? []) process.stderr.write(` ${note}
10217
10247
  `);
@@ -10223,7 +10253,8 @@ async function dispatch(opts) {
10223
10253
  cwd: opts.cwd,
10224
10254
  preset,
10225
10255
  ci: false,
10226
- fix: true
10256
+ fix: true,
10257
+ written
10227
10258
  });
10228
10259
  }
10229
10260
  return 0;
package/dist/index.d.ts CHANGED
@@ -66,6 +66,16 @@ interface RunContext {
66
66
  ci: boolean;
67
67
  /** Apply auto-fixes where the tool supports it. */
68
68
  fix: boolean;
69
+ /**
70
+ * The files `--init` just wrote, relative to `cwd`, for an `afterInit` that tidies up after
71
+ * itself.
72
+ *
73
+ * ⚠️ It exists because the alternative is a whole-directory pass, and that is not a tidy-up.
74
+ * Measured on `apps/nest/microservices/institution`: an `afterInit` running its formatter over
75
+ * `.` reformatted 1813 files, 47333 insertions and 55506 deletions, in a module whose migration
76
+ * touched 268. Only set by the `--init` path, so an adapter must treat it as optional.
77
+ */
78
+ written?: string[];
69
79
  /**
70
80
  * Cap on the number of structured diagnostics a `--report` embeds per module (the
71
81
  * full count still lives in `errors`, so nothing is hidden silently). `0` means no
package/dist/index.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  registerAdapters,
8
8
  resolve,
9
9
  setDefaultRunner
10
- } from "./chunk-XGC2KK5J.js";
10
+ } from "./chunk-I64KRL6O.js";
11
11
  import "./chunk-WLFE5RUU.js";
12
12
  export {
13
13
  BaseAdapter,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hublo/sentinel",
3
- "version": "1.4.0-alpha.16",
3
+ "version": "1.4.0-alpha.17",
4
4
  "description": "One CLI that guards code health across Hublo repos: shared lint/typescript/build/test presets, static & dynamic analysis, and architecture checks.",
5
5
  "type": "module",
6
6
  "license": "MIT",