@geonosis/doctor 2.6.0 → 2.7.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,35 @@
1
1
  # @geonosis/doctor
2
2
 
3
+ ## 2.7.0
4
+
5
+ ### Minor Changes
6
+
7
+ - d90986b: A twelfth question: `seams`. Every glob `adoption.seams` declares has to name a file in the tree
8
+ (never one under node_modules); one that names nothing is a WARN per glob saying to drop it or
9
+ name the file that replaced it, no `adoption.seams` at all is a SKIP by name, and a full set is
10
+ one OK line with the count. `geonosis update` measures a floor's adoption by exactly those files,
11
+ and during.day carried three dead globs of eight for a month while every bump report read
12
+ `0 deleted, 0 added` over them. `--only seams` runs it alone.
13
+
14
+ ### Patch Changes
15
+
16
+ - 7ee2097: `FLOOR_PACKAGES` names `@geonosis/buketi-ui`, the first package on the `kits/*` floor, so the doctor's
17
+ floor lines ask about it the way they ask about every other publishable floor.
18
+ - c01ea60: The `exercised` check knows a retired rule. A plugin may keep a rule's id resolvable after retiring
19
+ it — `meta.retired` — so a config that still names it parses; judged as a live rule it read as "not
20
+ exported" or "never fires", a FAIL against a tree whose only fault is a block the kit made stale.
21
+ The id is now set aside before the judging, and every verdict names it with the way out: it reports
22
+ nothing, goes at the next major, remove it from this config. A verdict that would have been OK or
23
+ SKIP is a WARN while any such id is still named.
24
+ - Updated dependencies [c13ade8]
25
+ - @geonosis/lint-parity@2.7.0
26
+
27
+ ## 2.6.1
28
+
29
+ ### Patch Changes
30
+
31
+ - @geonosis/lint-parity@2.6.1
32
+
3
33
  ## 2.6.0
4
34
 
5
35
  ### Patch Changes
package/README.md CHANGED
@@ -387,3 +387,16 @@ consumer wrote. It depends on `@geonosis/lint-parity` for the reach engine and o
387
387
  the kit's own `layer-walls` config holds every one of those walls.
388
388
 
389
389
  Apache-2.0.
390
+
391
+ ### `seams` — a declared seam that names nothing
392
+
393
+ `adoption.seams` in `geonosis.json` is what `geonosis update` measures a floor's adoption by:
394
+ lines deleted against lines added in the files a consumer says hold a floor's shape. A glob whose
395
+ file was deleted and never undeclared measures nothing, and every bump report reads `0 deleted,
396
+ 0 added` over it — during.day carried three of eight that way for a month.
397
+
398
+ | Seen | Line |
399
+ | ----------------------------------------------- | --------------------------------------------------- |
400
+ | no `adoption.seams` | **SKIP**, naming the key |
401
+ | every glob names a file (never in node_modules) | **OK**, with the count |
402
+ | a glob names no file | **WARN** per glob, saying to drop or replace it |
@@ -113,7 +113,8 @@ var CHECKS = [
113
113
  "observability",
114
114
  "deployed",
115
115
  "rails",
116
- "exams"
116
+ "exams",
117
+ "seams"
117
118
  ];
118
119
  var findingMaker = (check) => (subject, verdict, message) => ({
119
120
  check,
@@ -461,6 +462,12 @@ var probesOf = async (entry, plugin) => {
461
462
  })
462
463
  );
463
464
  };
465
+ var retiredOf = async (entry, plugin) => {
466
+ const loaded = await import(pathToFileURL(entry).href);
467
+ return new Set(
468
+ Object.entries(loaded.default?.rules ?? {}).filter(([, rule]) => typeof rule?.meta?.retired === "object" && rule.meta.retired !== null).map(([name]) => `${plugin}/${name}`)
469
+ );
470
+ };
464
471
  var grantsOf = async (entry) => {
465
472
  const loaded = await import(pathToFileURL(entry).href);
466
473
  const plugin = loaded.default?.meta?.name ?? "";
@@ -1245,6 +1252,7 @@ var OBSERVABILITY = "@geonosis/observability";
1245
1252
  var COMPOSITION_ROOT = "src/platform.ts";
1246
1253
  var FLOOR_PACKAGES = [
1247
1254
  "@geonosis/assistant",
1255
+ "@geonosis/buketi-ui",
1248
1256
  "@geonosis/conformance",
1249
1257
  "@geonosis/db",
1250
1258
  "@geonosis/document",
@@ -1629,6 +1637,7 @@ var reasonFrom = (config, oxlint) => {
1629
1637
  }
1630
1638
  };
1631
1639
  var named = (rules) => rules.join(", ");
1640
+ var retiredNote = (rules) => rules.length === 1 ? `${rules[0]} is retired by the plugin \u2014 it reports nothing and goes at the next major, so remove it from this config` : `${named(rules)} are retired by the plugin \u2014 they report nothing and go at the next major, so remove them from this config`;
1632
1641
  var countOf = (rules, verb) => rules.length === 1 ? `1 enabled rule ${verb}s` : `${rules.length} enabled rules ${verb}`;
1633
1642
  var ownReach = ({
1634
1643
  config,
@@ -1790,7 +1799,12 @@ var checkExercised = async ({
1790
1799
  repoCorpus,
1791
1800
  root
1792
1801
  }) => {
1793
- const said2 = (verdict, message) => finding5(config.relative, verdict, message);
1802
+ let retired = [];
1803
+ const said2 = (verdict, message) => retired.length === 0 ? finding5(config.relative, verdict, message) : finding5(
1804
+ config.relative,
1805
+ verdict === "OK" || verdict === "SKIP" ? "WARN" : verdict,
1806
+ `${message}; ${retiredNote(retired)}`
1807
+ );
1794
1808
  if (repoCorpus !== void 0 && !existsSync7(repoCorpus)) {
1795
1809
  return said2(
1796
1810
  "FAIL",
@@ -1809,8 +1823,13 @@ var checkExercised = async ({
1809
1823
  } catch (error) {
1810
1824
  return said2("SKIP", refusal(error));
1811
1825
  }
1812
- const enabled = enabledHere(config, manifest.plugin);
1813
- if (enabled.length === 0) return said2("SKIP", `no ${manifest.plugin} rule is enabled here`);
1826
+ const configured2 = enabledHere(config, manifest.plugin);
1827
+ const retiredIds = entry === void 0 ? /* @__PURE__ */ new Set() : await retiredOf(entry, manifest.plugin).catch(() => /* @__PURE__ */ new Set());
1828
+ retired = configured2.filter((rule) => retiredIds.has(rule));
1829
+ const enabled = configured2.filter((rule) => !retiredIds.has(rule));
1830
+ if (enabled.length === 0) {
1831
+ return retired.length === 0 ? said2("SKIP", `no ${manifest.plugin} rule is enabled here`) : said2("WARN", `nothing enabled here is a live ${manifest.plugin} rule`);
1832
+ }
1814
1833
  let reach;
1815
1834
  try {
1816
1835
  reach = corpusOf({ configA: config.path, configB: config.path, corpus, oxlint }).reach;
@@ -2679,7 +2698,7 @@ var checkRunner = ({
2679
2698
 
2680
2699
  // src/doctor.ts
2681
2700
  import { homedir as homedir3 } from "os";
2682
- import { join as join17 } from "path";
2701
+ import { join as join18 } from "path";
2683
2702
  import { resolveOxlint } from "@geonosis/lint-parity";
2684
2703
 
2685
2704
  // src/engine.ts
@@ -3000,6 +3019,46 @@ var checkRequiredOptions = async ({
3000
3019
  ];
3001
3020
  };
3002
3021
 
3022
+ // src/seams.ts
3023
+ import { existsSync as existsSync13, globSync, readFileSync as readFileSync16 } from "fs";
3024
+ import { join as join17 } from "path";
3025
+ var CONFIG = "geonosis.json";
3026
+ var finding12 = findingMaker("seams");
3027
+ var NO_SEAMS = `${CONFIG} declares no adoption.seams \u2014 nothing here says which files hold a floor's shape, so no bump can measure what it deleted; declare them when a floor is adopted`;
3028
+ var declaredSeams = (root) => {
3029
+ const at = join17(root, CONFIG);
3030
+ if (!existsSync13(at)) return void 0;
3031
+ let parsed;
3032
+ try {
3033
+ parsed = JSON.parse(readFileSync16(at, "utf8"));
3034
+ } catch {
3035
+ return void 0;
3036
+ }
3037
+ const seams = parsed.adoption?.seams;
3038
+ return Array.isArray(seams) ? seams.filter((one) => typeof one === "string") : void 0;
3039
+ };
3040
+ var namesAFile = (root, glob) => globSync(glob, {
3041
+ cwd: root,
3042
+ exclude: (name) => name === "node_modules" || name.startsWith("node_modules/")
3043
+ }).length > 0;
3044
+ var checkSeams = ({ root }) => {
3045
+ const seams = declaredSeams(root);
3046
+ if (seams === void 0 || seams.length === 0) return [finding12(CONFIG, "SKIP", NO_SEAMS)];
3047
+ const dead = seams.filter((glob) => !namesAFile(root, glob)).toSorted();
3048
+ if (dead.length === 0) {
3049
+ return [
3050
+ finding12(CONFIG, "OK", `adoption.seams: ${seams.length} seam glob(s), every one names a file`)
3051
+ ];
3052
+ }
3053
+ return dead.map(
3054
+ (glob) => finding12(
3055
+ glob,
3056
+ "WARN",
3057
+ `names no file in this tree, so the seam measures nothing and every bump reads 0 deleted, 0 added over it. Next: take it out of adoption.seams in ${CONFIG}, or name the file that replaced it`
3058
+ )
3059
+ );
3060
+ };
3061
+
3003
3062
  // src/doctor.ts
3004
3063
  var exercisedOf = ({
3005
3064
  configs,
@@ -3135,8 +3194,9 @@ var runDoctor = async ({
3135
3194
  ["observability", () => checkObservability({ now: Date.now(), root })],
3136
3195
  ["drift", () => checkDrift({ root, workspaces })],
3137
3196
  ["deployed", () => checkDeployed({ root })],
3138
- ["rails", () => checkRails({ root, userSettings: join17(home, USER_SETTINGS) })],
3139
- ["exams", () => checkExams({ root, workspaces })]
3197
+ ["rails", () => checkRails({ root, userSettings: join18(home, USER_SETTINGS) })],
3198
+ ["exams", () => checkExams({ root, workspaces })],
3199
+ ["seams", () => checkSeams({ root })]
3140
3200
  ];
3141
3201
  const collected = [];
3142
3202
  const ran = [];
@@ -3163,6 +3223,7 @@ var ABOUT = {
3163
3223
  drift: "the gates that were set up and are no longer running",
3164
3224
  envelope: "every gate read as many things as it was handed",
3165
3225
  exams: "every adopted floor has a test file that runs its exam",
3226
+ seams: "the seam globs adoption.seams declares each name a file",
3166
3227
  exercised: "every enabled rule fires on at least one corpus file",
3167
3228
  group: "the packages published on one version resolve to one version",
3168
3229
  loaded: "the plugin oxlint would load is the one the manifest pins",
@@ -4,7 +4,7 @@ import {
4
4
  formatDoctor,
5
5
  formatJson,
6
6
  runDoctor
7
- } from "./chunk-6ERJOIZS.js";
7
+ } from "./chunk-WUFVAO7G.js";
8
8
 
9
9
  // src/doctor-cli.ts
10
10
  import { fstatSync, statSync } from "fs";
@@ -135,6 +135,9 @@ var ABOUT = {
135
135
  installed floor's own declarations \u2014 every export ending in Conformance \u2014 never off a
136
136
  list held here. WARNs, because a floor adopted last week and one whose exam somebody
137
137
  deleted look the same from outside.`,
138
+ seams: `The seam globs adoption.seams declares each name a file. A glob whose file was deleted and
139
+ never undeclared measures nothing \u2014 every bump reads 0 deleted, 0 added over it \u2014 and a
140
+ floor's adoption is measured by exactly those files.`,
138
141
  exercised: `Every rule a config enables, against the corpus the loaded plugin ships. A rule at
139
142
  "error" that can never fire is indistinguishable from a clean tree. The line says what
140
143
  its number is evidence ABOUT \u2014 the corpus and the probes, never this tree \u2014 and a rule
package/dist/index.d.ts CHANGED
@@ -11,7 +11,7 @@ type Overrides = {
11
11
  * question one layer out — whether what was reported is what happened; `rails` asks it of the
12
12
  * settings an unattended run is bounded by, where a rendered file is not a loaded setting.
13
13
  */
14
- declare const CHECKS: readonly ["loaded", "group", "exercised", "baseline", "runner", "envelope", "drift", "observability", "deployed", "rails", "exams"];
14
+ declare const CHECKS: readonly ["loaded", "group", "exercised", "baseline", "runner", "envelope", "drift", "observability", "deployed", "rails", "exams", "seams"];
15
15
  type CheckName = (typeof CHECKS)[number];
16
16
  /**
17
17
  * `SKIP` is a first-class answer and is printed like any other: a check whose line is missing reads
package/dist/index.js CHANGED
@@ -48,7 +48,7 @@ import {
48
48
  resolveFrom,
49
49
  runDoctor,
50
50
  satisfies
51
- } from "./chunk-6ERJOIZS.js";
51
+ } from "./chunk-WUFVAO7G.js";
52
52
  export {
53
53
  CHECKS,
54
54
  COMPOSITION_ROOT,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geonosis/doctor",
3
- "version": "2.6.0",
3
+ "version": "2.7.0",
4
4
  "types": "./dist/index.d.ts",
5
5
  "description": "The adoption doctor — declared ≠ loaded, enabled ≠ exercised, a baseline that grew, a runner whose exit code is the only verdict.",
6
6
  "keywords": [
@@ -36,10 +36,10 @@
36
36
  "dist"
37
37
  ],
38
38
  "dependencies": {
39
- "@geonosis/lint-parity": "2.6.0"
39
+ "@geonosis/lint-parity": "2.7.0"
40
40
  },
41
41
  "devDependencies": {
42
- "@geonosis/ratchet": "2.6.0"
42
+ "@geonosis/ratchet": "2.7.0"
43
43
  },
44
44
  "peerDependencies": {
45
45
  "oxlint": ">=1.77"