@hublo/sentinel 1.0.1 → 1.0.2
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/dist/bin/sentinel.js +26 -31
- package/dist/{chunk-HKGCWPRT.js → chunk-SK6E5EM4.js} +35 -3
- package/dist/index.d.ts +11 -0
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/dist/bin/sentinel.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
FLAVOURS,
|
|
4
|
+
TARGETS,
|
|
5
|
+
VERBS,
|
|
3
6
|
availableTargets,
|
|
4
7
|
describeFramework,
|
|
5
8
|
dispatch,
|
|
@@ -11,7 +14,7 @@ import {
|
|
|
11
14
|
registerAdapters,
|
|
12
15
|
resolve,
|
|
13
16
|
resolveBin
|
|
14
|
-
} from "../chunk-
|
|
17
|
+
} from "../chunk-SK6E5EM4.js";
|
|
15
18
|
|
|
16
19
|
// bin/sentinel.ts
|
|
17
20
|
import { program } from "commander";
|
|
@@ -106,20 +109,6 @@ function resolveContext(cwd2, opts2) {
|
|
|
106
109
|
);
|
|
107
110
|
}
|
|
108
111
|
|
|
109
|
-
// src/core/domain.ts
|
|
110
|
-
var VERBS = ["run", "inspect", "init", "migrate", "report", "status"];
|
|
111
|
-
var TARGETS = [
|
|
112
|
-
"lint",
|
|
113
|
-
"format",
|
|
114
|
-
"typescript",
|
|
115
|
-
"build",
|
|
116
|
-
"test",
|
|
117
|
-
"static-analysis",
|
|
118
|
-
"runtime-analysis",
|
|
119
|
-
"arch"
|
|
120
|
-
];
|
|
121
|
-
var FLAVOURS = ["react", "nest", "svelte", "node"];
|
|
122
|
-
|
|
123
112
|
// src/core/orchestrate.ts
|
|
124
113
|
async function analyse(params) {
|
|
125
114
|
const results = [];
|
|
@@ -141,14 +130,6 @@ async function analyse(params) {
|
|
|
141
130
|
);
|
|
142
131
|
}
|
|
143
132
|
}
|
|
144
|
-
const ctx = {
|
|
145
|
-
module: module.name,
|
|
146
|
-
cwd: module.root,
|
|
147
|
-
flavour: flavour2,
|
|
148
|
-
ci: params.ci,
|
|
149
|
-
fix: params.fix,
|
|
150
|
-
maxDiagnostics: params.maxDiagnostics
|
|
151
|
-
};
|
|
152
133
|
for (const target of params.targets) {
|
|
153
134
|
let adapter;
|
|
154
135
|
try {
|
|
@@ -167,13 +148,22 @@ async function analyse(params) {
|
|
|
167
148
|
}
|
|
168
149
|
continue;
|
|
169
150
|
}
|
|
151
|
+
const effectiveFlavour = params.flavour ?? adapter.declaredFlavour?.(module.root) ?? flavour2;
|
|
152
|
+
const ctx = {
|
|
153
|
+
module: module.name,
|
|
154
|
+
cwd: module.root,
|
|
155
|
+
flavour: effectiveFlavour,
|
|
156
|
+
ci: params.ci,
|
|
157
|
+
fix: params.fix,
|
|
158
|
+
maxDiagnostics: params.maxDiagnostics
|
|
159
|
+
};
|
|
170
160
|
try {
|
|
171
161
|
if (params.verb === "run") {
|
|
172
162
|
if (params.modules.length > 1) {
|
|
173
163
|
const err = palette(process.stderr);
|
|
174
164
|
process.stderr.write(
|
|
175
165
|
`
|
|
176
|
-
${err.accent("\u25B6")} ${err.strong(module.name)} ${err.dim(`(${
|
|
166
|
+
${err.accent("\u25B6")} ${err.strong(module.name)} ${err.dim(`(${effectiveFlavour})`)} ${target}
|
|
177
167
|
`
|
|
178
168
|
);
|
|
179
169
|
}
|
|
@@ -181,7 +171,7 @@ async function analyse(params) {
|
|
|
181
171
|
results.push({
|
|
182
172
|
project: module.name,
|
|
183
173
|
target,
|
|
184
|
-
flavour:
|
|
174
|
+
flavour: effectiveFlavour,
|
|
185
175
|
ok: result.ok,
|
|
186
176
|
status: result.ok ? "ok" : "failed",
|
|
187
177
|
data: {}
|
|
@@ -192,7 +182,7 @@ async function analyse(params) {
|
|
|
192
182
|
results.push({
|
|
193
183
|
project: module.name,
|
|
194
184
|
target,
|
|
195
|
-
flavour:
|
|
185
|
+
flavour: effectiveFlavour,
|
|
196
186
|
ok: result.ok,
|
|
197
187
|
status: result.ok ? "ok" : "failed",
|
|
198
188
|
data: result.metrics ?? {}
|
|
@@ -203,7 +193,7 @@ async function analyse(params) {
|
|
|
203
193
|
results.push({
|
|
204
194
|
project: module.name,
|
|
205
195
|
target,
|
|
206
|
-
flavour:
|
|
196
|
+
flavour: effectiveFlavour,
|
|
207
197
|
ok: true,
|
|
208
198
|
status: "ok",
|
|
209
199
|
data: config
|
|
@@ -214,7 +204,7 @@ async function analyse(params) {
|
|
|
214
204
|
results.push({
|
|
215
205
|
project: module.name,
|
|
216
206
|
target,
|
|
217
|
-
flavour:
|
|
207
|
+
flavour: effectiveFlavour,
|
|
218
208
|
ok,
|
|
219
209
|
status: ok ? "ok" : "failed",
|
|
220
210
|
data: status
|
|
@@ -226,7 +216,7 @@ async function analyse(params) {
|
|
|
226
216
|
results.push({
|
|
227
217
|
project: module.name,
|
|
228
218
|
target,
|
|
229
|
-
flavour:
|
|
219
|
+
flavour: effectiveFlavour,
|
|
230
220
|
ok: false,
|
|
231
221
|
status: "failed",
|
|
232
222
|
data: { error: message }
|
|
@@ -529,8 +519,13 @@ async function runVerb() {
|
|
|
529
519
|
maxDiagnostics,
|
|
530
520
|
ci: Boolean(opts.ci),
|
|
531
521
|
fix: Boolean(opts.fix),
|
|
532
|
-
|
|
533
|
-
|
|
522
|
+
// Per-module progress is a HUMAN affordance: it tells someone staring at a slow sweep
|
|
523
|
+
// that it is alive. On this monorepo's 441 projects it is 441 lines that bury the four
|
|
524
|
+
// that matter, and it is pure noise in a captured log. So emit it only for an
|
|
525
|
+
// interactive terminal; a pipe, CI, or a generated trace gets the results and the
|
|
526
|
+
// one-line summary, which is all any of them can use.
|
|
527
|
+
onProgress: process.stderr.isTTY ? (done, total, name) => process.stderr.write(err.dim(` [${done}/${total}] ${name}
|
|
528
|
+
`)) : void 0
|
|
534
529
|
});
|
|
535
530
|
const summary = generateSummaries(results, targets);
|
|
536
531
|
if (opts.json && verb !== "run") {
|
|
@@ -62,6 +62,20 @@ var BaseAdapter = class {
|
|
|
62
62
|
}
|
|
63
63
|
};
|
|
64
64
|
|
|
65
|
+
// src/core/domain.ts
|
|
66
|
+
var VERBS = ["run", "inspect", "init", "migrate", "report", "status"];
|
|
67
|
+
var TARGETS = [
|
|
68
|
+
"lint",
|
|
69
|
+
"format",
|
|
70
|
+
"typescript",
|
|
71
|
+
"build",
|
|
72
|
+
"test",
|
|
73
|
+
"static-analysis",
|
|
74
|
+
"runtime-analysis",
|
|
75
|
+
"arch"
|
|
76
|
+
];
|
|
77
|
+
var FLAVOURS = ["react", "nest", "svelte", "node"];
|
|
78
|
+
|
|
65
79
|
// src/shared/color.ts
|
|
66
80
|
import { styleText } from "util";
|
|
67
81
|
function palette(stream) {
|
|
@@ -294,6 +308,20 @@ var TscAdapter = class extends BaseAdapter {
|
|
|
294
308
|
appliesTo(_flavour) {
|
|
295
309
|
return true;
|
|
296
310
|
}
|
|
311
|
+
/**
|
|
312
|
+
* The flavour read from the committed `extends` chain
|
|
313
|
+
* (`@hublo/sentinel/tsconfig/nest` -> `nest`), or undefined when the module has not
|
|
314
|
+
* adopted a preset, so the engine falls back to dependency detection.
|
|
315
|
+
*
|
|
316
|
+
* This is the same detection-free read `--status` uses, and it is why an adopted React app
|
|
317
|
+
* reports `react` even in a monorepo that hoists `react` to the root.
|
|
318
|
+
*/
|
|
319
|
+
declaredFlavour(cwd) {
|
|
320
|
+
const { preset } = readTsconfigAdoption(cwd);
|
|
321
|
+
if (!preset) return void 0;
|
|
322
|
+
const name = preset.slice(preset.lastIndexOf("/") + 1);
|
|
323
|
+
return FLAVOURS.includes(name) ? name : void 0;
|
|
324
|
+
}
|
|
297
325
|
/**
|
|
298
326
|
* Plan `--init`: make the module extend the sentinel preset with a THIN,
|
|
299
327
|
* conformant stub, route type-checking through the CLI, and pin the
|
|
@@ -745,8 +773,9 @@ async function dispatch(opts) {
|
|
|
745
773
|
if (opts.verb !== "init") {
|
|
746
774
|
throw new Error(`dispatch handles --init only; --${opts.verb} routes through analyse()`);
|
|
747
775
|
}
|
|
748
|
-
const
|
|
749
|
-
const adapter = resolve(opts.target,
|
|
776
|
+
const detected = resolveFlavour(opts);
|
|
777
|
+
const adapter = resolve(opts.target, detected, opts.runner);
|
|
778
|
+
const flavour = opts.flavour ?? adapter.declaredFlavour?.(opts.cwd) ?? detected;
|
|
750
779
|
const context = { cwd: opts.cwd, flavour };
|
|
751
780
|
const plan = await adapter.plan(context);
|
|
752
781
|
if (plan.blocked) {
|
|
@@ -772,6 +801,9 @@ export {
|
|
|
772
801
|
availableTargets,
|
|
773
802
|
resolve,
|
|
774
803
|
BaseAdapter,
|
|
804
|
+
VERBS,
|
|
805
|
+
TARGETS,
|
|
806
|
+
FLAVOURS,
|
|
775
807
|
palette,
|
|
776
808
|
readOwnPackage,
|
|
777
809
|
readOwnVersion,
|
|
@@ -783,4 +815,4 @@ export {
|
|
|
783
815
|
detectFramework,
|
|
784
816
|
dispatch
|
|
785
817
|
};
|
|
786
|
-
//# sourceMappingURL=chunk-
|
|
818
|
+
//# sourceMappingURL=chunk-SK6E5EM4.js.map
|
package/dist/index.d.ts
CHANGED
|
@@ -169,6 +169,17 @@ interface Adapter {
|
|
|
169
169
|
* adapters can share a (target, runner) if they specialise different flavours.
|
|
170
170
|
*/
|
|
171
171
|
appliesTo(flavour: Flavour): boolean;
|
|
172
|
+
/**
|
|
173
|
+
* The flavour this module has COMMITTED to, read from its own config, or undefined when
|
|
174
|
+
* it has not adopted a preset yet. Optional: an adapter implements it only when its tool's
|
|
175
|
+
* config states the flavour unambiguously.
|
|
176
|
+
*
|
|
177
|
+
* The engine prefers this over dependency detection, because in a monorepo dependencies are
|
|
178
|
+
* hoisted to the root: `host-admin` declares no `react`, so detection honestly answers
|
|
179
|
+
* `node` while the committed `extends` says `.../tsconfig/react`. Reporting the detected
|
|
180
|
+
* value there would show every adopted module as `node`, which is simply untrue.
|
|
181
|
+
*/
|
|
182
|
+
declaredFlavour?(cwd: string): Flavour | undefined;
|
|
172
183
|
/**
|
|
173
184
|
* Plan what `--init` should write, as declarative operations (see
|
|
174
185
|
* `FileOperation`). Given a normalized `UpdateContext`, the adapter may READ the
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hublo/sentinel",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
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",
|