@theholocron/astromech 5.0.0-alpha.78 → 5.0.0-alpha.79

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 CHANGED
@@ -33,7 +33,7 @@ const report = astromech.run("verification.unitTests", { passthrough: ["--watch"
33
33
  `holocron run verification.unitTests` runs your tests — you don't tell it
34
34
  turbo vs pnpm vs npm, or which runner:
35
35
 
36
- ```
36
+ ```text
37
37
  1. turbo.json defines the task → turbo run <task>
38
38
  2. package.json has a <task> script → <detected pm> run <task>
39
39
  (a "holocron run …" thin caller is skipped — no recursion)
@@ -83,10 +83,12 @@ publish/deploy-shaped task can carry, toggled via that task's `with:`.
83
83
 
84
84
  **`linterGroup` tasks** (`sourceQuality.staticAnalysis`,
85
85
  `sourceQuality.formatting`) bundle more than one tool under a single
86
- required check. Each tool is still gated by its own detection rule (e.g.
87
- `eslint` only runs if `eslint.config.*` is present) — the
86
+ required check. Each tool is still gated by its own detection rule — e.g.
87
+ `eslint` runs when either a local `eslint.config.*` is present, or the
88
+ package has no local file but `@theholocron/eslint-config` resolves
89
+ (the same shared-config splice the `tool`/`detect` runner path uses) — the
88
90
  `tool name → detection rule → local binary` mapping lives in one place,
89
- `src/linters.ts`. A repo's choice of which of these run is just which
91
+ `src/linters.ts`. A repo's choice of which of these run is based on which
90
92
  tasks it includes in `tasks: [...]`, same as any other task.
91
93
 
92
94
  **No super-linter.** Each task above runs its own tool directly, through
package/dist/index.d.mts CHANGED
@@ -452,11 +452,20 @@ declare const LINTER_NAMES: ReadonlySet<string>;
452
452
  * Resolve the linter set for a repo. An `explicit` list (from `config.tasks`)
453
453
  * picks the candidate set; otherwise the candidates are every `always` linter
454
454
  * plus every `detect`-gated linter whose filenames are present at the repo
455
- * root. Either way, a `detect`-gated linter (eslint, markdownlint) only makes
456
- * the final set when its config file is actually present — a repo can't run
457
- * eslint without an `eslint.config.*`, and super-linter FATALs if you ask it
458
- * to (theholocron/holocron#654). `always` linters are unconditional. Result
459
- * is ordered by {@link LINTERS} declaration order.
455
+ * root, OR whose mapped `@theholocron/*-config` package resolves per
456
+ * {@link sharedConfigAvailable} — a repo can't run eslint with genuinely no
457
+ * config anywhere (super-linter FATALs if you ask it to,
458
+ * theholocron/holocron#654), but a *shared* one it has installed counts
459
+ * (holocron#795: proving `clients`' eslint.config.ts files reduce to zero
460
+ * remaining content is only half the story — the file itself was still load-
461
+ * bearing here as the sole "eslint is even configured" signal until this
462
+ * fallback existed). `always` linters are unconditional. Result is ordered
463
+ * by {@link LINTERS} declaration order.
464
+ *
465
+ * `sharedConfigAvailable` is caller-computed (`run.ts`'s `runLinterGroup`
466
+ * already resolves each linter's `resolveToolConfig()` per member to build
467
+ * its actual command — reusing that instead of duplicating the package-
468
+ * resolution logic here keeps this function itself pure and file-I/O-free).
460
469
  *
461
470
  * @throws when an `explicit` name is not in the registry — a typo is a
462
471
  * config bug, not a linter to silently skip.
@@ -464,6 +473,7 @@ declare const LINTER_NAMES: ReadonlySet<string>;
464
473
  declare function resolveLinters(opts: {
465
474
  explicit?: string[];
466
475
  rootFiles: string[];
476
+ sharedConfigAvailable?: ReadonlySet<string>;
467
477
  }): Array<{
468
478
  name: string;
469
479
  def: LinterDef;
package/dist/index.mjs CHANGED
@@ -299,11 +299,20 @@ const LINTER_NAMES = new Set(Object.keys(LINTERS));
299
299
  * Resolve the linter set for a repo. An `explicit` list (from `config.tasks`)
300
300
  * picks the candidate set; otherwise the candidates are every `always` linter
301
301
  * plus every `detect`-gated linter whose filenames are present at the repo
302
- * root. Either way, a `detect`-gated linter (eslint, markdownlint) only makes
303
- * the final set when its config file is actually present — a repo can't run
304
- * eslint without an `eslint.config.*`, and super-linter FATALs if you ask it
305
- * to (theholocron/holocron#654). `always` linters are unconditional. Result
306
- * is ordered by {@link LINTERS} declaration order.
302
+ * root, OR whose mapped `@theholocron/*-config` package resolves per
303
+ * {@link sharedConfigAvailable} — a repo can't run eslint with genuinely no
304
+ * config anywhere (super-linter FATALs if you ask it to,
305
+ * theholocron/holocron#654), but a *shared* one it has installed counts
306
+ * (holocron#795: proving `clients`' eslint.config.ts files reduce to zero
307
+ * remaining content is only half the story — the file itself was still load-
308
+ * bearing here as the sole "eslint is even configured" signal until this
309
+ * fallback existed). `always` linters are unconditional. Result is ordered
310
+ * by {@link LINTERS} declaration order.
311
+ *
312
+ * `sharedConfigAvailable` is caller-computed (`run.ts`'s `runLinterGroup`
313
+ * already resolves each linter's `resolveToolConfig()` per member to build
314
+ * its actual command — reusing that instead of duplicating the package-
315
+ * resolution logic here keeps this function itself pure and file-I/O-free).
307
316
  *
308
317
  * @throws when an `explicit` name is not in the registry — a typo is a
309
318
  * config bug, not a linter to silently skip.
@@ -311,17 +320,18 @@ const LINTER_NAMES = new Set(Object.keys(LINTERS));
311
320
  function resolveLinters(opts) {
312
321
  const order = Object.keys(LINTERS);
313
322
  const present = new Set(opts.rootFiles);
314
- const configPresent = (def) => def.always === true || (def.detect ?? []).some((f) => present.has(f));
323
+ const shared = opts.sharedConfigAvailable ?? /* @__PURE__ */ new Set();
324
+ const configPresent = (name, def) => def.always === true || (def.detect ?? []).some((f) => present.has(f)) || shared.has(name);
315
325
  if (opts.explicit && opts.explicit.length > 0) {
316
326
  const unknown = opts.explicit.filter((n) => !LINTER_NAMES.has(n));
317
327
  if (unknown.length > 0) throw new Error(`unknown linter${unknown.length > 1 ? "s" : ""} ${unknown.map((n) => `"${n}"`).join(", ")} — known: ${order.join(", ")}`);
318
328
  const wanted = new Set(opts.explicit);
319
- return order.filter((n) => wanted.has(n) && configPresent(LINTERS[n])).map((name) => ({
329
+ return order.filter((n) => wanted.has(n) && configPresent(n, LINTERS[n])).map((name) => ({
320
330
  name,
321
331
  def: LINTERS[name]
322
332
  }));
323
333
  }
324
- return order.filter((name) => configPresent(LINTERS[name])).map((name) => ({
334
+ return order.filter((name) => configPresent(name, LINTERS[name])).map((name) => ({
325
335
  name,
326
336
  def: LINTERS[name]
327
337
  }));
@@ -731,9 +741,14 @@ function runLinterGroup(input, names, passthrough) {
731
741
  } catch {
732
742
  rootFiles = [];
733
743
  }
744
+ const sharedConfigAvailable = new Set(names.filter((name) => resolveToolConfig(name, cwd, {
745
+ readFile,
746
+ fileExists
747
+ }).length > 0));
734
748
  const resolved = resolveLinters({
735
749
  explicit: names,
736
- rootFiles
750
+ rootFiles,
751
+ sharedConfigAvailable
737
752
  });
738
753
  const reports = [];
739
754
  let anyHasLocalBin = false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@theholocron/astromech",
3
- "version": "5.0.0-alpha.78",
3
+ "version": "5.0.0-alpha.79",
4
4
  "description": "The Holocron task runner — one task manifest drives `holocron run`, `holocron ci`, the CI workflows, package.json scripts, linters, and required checks.",
5
5
  "keywords": [
6
6
  "ci",
@@ -37,7 +37,7 @@
37
37
  "dist"
38
38
  ],
39
39
  "dependencies": {
40
- "@theholocron/datapad": "5.0.0-alpha.78"
40
+ "@theholocron/datapad": "5.0.0-alpha.79"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@theholocron/eslint-config": "^8.4.5",
@@ -53,7 +53,7 @@
53
53
  "tsdown": "^0.22.14",
54
54
  "typescript": "^5.9.3",
55
55
  "vitest": "^4.1.11",
56
- "@theholocron/rollup-plugin-transform-template": "5.0.0-alpha.78"
56
+ "@theholocron/rollup-plugin-transform-template": "5.0.0-alpha.79"
57
57
  },
58
58
  "engines": {
59
59
  "node": ">=22"