@hublo/sentinel 1.5.0-alpha.5 → 1.5.0-alpha.6
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
CHANGED
|
@@ -4806,22 +4806,28 @@ function helpFor(key) {
|
|
|
4806
4806
|
}
|
|
4807
4807
|
|
|
4808
4808
|
// src/roles/static-analysis/report.ts
|
|
4809
|
-
function hasFinding(report) {
|
|
4810
|
-
return report.rows.some((row) => row.over);
|
|
4811
|
-
}
|
|
4812
4809
|
function renderConsole(report) {
|
|
4813
4810
|
const lines = [];
|
|
4814
4811
|
const width = (pick) => Math.max(...report.rows.map((row) => pick(row).length));
|
|
4815
4812
|
const label = (row) => helpFor(row.metric)?.label ?? row.metric;
|
|
4816
4813
|
const value = (row) => `${row.value} ${row.unit}`;
|
|
4817
|
-
const limit = (row) => row.threshold === null ? "no threshold" : `max ${row.threshold}${row.moved ? " (module)" : ""}`;
|
|
4818
4814
|
const labelWidth = width(label);
|
|
4819
4815
|
const valueWidth = width(value);
|
|
4820
4816
|
lines.push(`sentinel static-analysis: ${report.module}`);
|
|
4821
4817
|
for (const row of report.rows) {
|
|
4822
|
-
lines.push(
|
|
4823
|
-
|
|
4824
|
-
|
|
4818
|
+
lines.push(` ${label(row).padEnd(labelWidth)} ${value(row).padStart(valueWidth)}`);
|
|
4819
|
+
}
|
|
4820
|
+
if (report.settings.length > 0) {
|
|
4821
|
+
const keyWidth = Math.max(...report.settings.map((setting) => setting.key.length));
|
|
4822
|
+
lines.push("", " measured with");
|
|
4823
|
+
for (const setting of report.settings) {
|
|
4824
|
+
lines.push(
|
|
4825
|
+
` ${setting.key.padEnd(keyWidth)} ${setting.value}${setting.moved ? " (module)" : ""}`
|
|
4826
|
+
);
|
|
4827
|
+
}
|
|
4828
|
+
if (report.settings.some((setting) => setting.moved)) {
|
|
4829
|
+
lines.push(` (module) = overridden in ${report.module}'s static-analysis.config.mjs`);
|
|
4830
|
+
}
|
|
4825
4831
|
}
|
|
4826
4832
|
if (report.byLanguage && Object.keys(report.byLanguage).length > 0) {
|
|
4827
4833
|
lines.push("", " per language, where a clone was found");
|
|
@@ -4856,13 +4862,19 @@ function escape(text) {
|
|
|
4856
4862
|
function renderHtml(report) {
|
|
4857
4863
|
const rows = report.rows.map((row) => {
|
|
4858
4864
|
const help = helpFor(row.metric);
|
|
4859
|
-
return ` <tr
|
|
4865
|
+
return ` <tr>
|
|
4860
4866
|
<th scope="row">${escape(help?.label ?? row.metric)}</th>
|
|
4861
4867
|
<td class="num">${escape(String(row.value))} <span class="unit">${escape(row.unit)}</span></td>
|
|
4862
|
-
<td class="num">${row.threshold === null ? '<span class="unit">none</span>' : escape(String(row.threshold))}${row.moved ? ' <span class="moved">module</span>' : ""}</td>
|
|
4863
4868
|
<td class="caveat">${escape(help?.caveat ?? "")}</td>
|
|
4864
4869
|
</tr>`;
|
|
4865
4870
|
}).join("\n");
|
|
4871
|
+
const settings = report.settings.map(
|
|
4872
|
+
(setting) => ` <tr>
|
|
4873
|
+
<th scope="row"><code>${escape(setting.key)}</code></th>
|
|
4874
|
+
<td class="num">${escape(setting.value)}</td>
|
|
4875
|
+
<td>${setting.moved ? '<span class="moved">overridden in this module</span>' : ""}</td>
|
|
4876
|
+
</tr>`
|
|
4877
|
+
).join("\n");
|
|
4866
4878
|
return `<!doctype html>
|
|
4867
4879
|
<html lang="en">
|
|
4868
4880
|
<head>
|
|
@@ -4878,14 +4890,16 @@ function renderHtml(report) {
|
|
|
4878
4890
|
main { max-width: 60rem; margin: 0 auto; }
|
|
4879
4891
|
h1 { font-size: 1.25rem; margin: 0 0 0.25rem; }
|
|
4880
4892
|
p.sub { color: var(--dim); margin: 0 0 1.5rem; }
|
|
4893
|
+
h2 { font-size: 0.95rem; margin: 2.5rem 0 0.5rem; }
|
|
4881
4894
|
table { width: 100%; border-collapse: collapse; }
|
|
4882
4895
|
th, td { text-align: left; padding: 0.6rem 0.75rem; border-bottom: 1px solid var(--rule);
|
|
4883
4896
|
vertical-align: top; }
|
|
4884
4897
|
thead th { font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--dim); }
|
|
4885
4898
|
td.num { font-variant-numeric: tabular-nums; white-space: nowrap; }
|
|
4886
|
-
|
|
4899
|
+
code { font: 0.9em ui-monospace, SFMono-Regular, Menlo, monospace; }
|
|
4900
|
+
.unit { color: var(--dim); font-size: 0.85em; }
|
|
4901
|
+
.moved { color: var(--warn); font-size: 0.85em; }
|
|
4887
4902
|
.caveat { color: var(--dim); font-size: 0.9em; }
|
|
4888
|
-
tr.over th, tr.over td.num { color: var(--warn); font-weight: 600; }
|
|
4889
4903
|
</style>
|
|
4890
4904
|
</head>
|
|
4891
4905
|
<body>
|
|
@@ -4894,12 +4908,21 @@ function renderHtml(report) {
|
|
|
4894
4908
|
<p class="sub">Passes: ${escape(report.passes.join(", "))}</p>
|
|
4895
4909
|
<table>
|
|
4896
4910
|
<thead>
|
|
4897
|
-
<tr><th scope="col">Metric</th><th scope="col">Value</th><th scope="col">
|
|
4911
|
+
<tr><th scope="col">Metric</th><th scope="col">Value</th><th scope="col">What it does not say</th></tr>
|
|
4898
4912
|
</thead>
|
|
4899
4913
|
<tbody>
|
|
4900
4914
|
${rows}
|
|
4901
4915
|
</tbody>
|
|
4902
4916
|
</table>
|
|
4917
|
+
<h2>Measured with</h2>
|
|
4918
|
+
<table>
|
|
4919
|
+
<thead>
|
|
4920
|
+
<tr><th scope="col">Setting</th><th scope="col">Value</th><th scope="col">Origin</th></tr>
|
|
4921
|
+
</thead>
|
|
4922
|
+
<tbody>
|
|
4923
|
+
${settings}
|
|
4924
|
+
</tbody>
|
|
4925
|
+
</table>
|
|
4903
4926
|
</main>
|
|
4904
4927
|
</body>
|
|
4905
4928
|
</html>
|
|
@@ -4984,6 +5007,14 @@ export default defineStaticAnalysis({
|
|
|
4984
5007
|
// Named product journeys, as { 'the name product uses': ['src/some/path/**'] }. Paths are
|
|
4985
5008
|
// relative to this module, because one run measures one module.
|
|
4986
5009
|
journeys: {},
|
|
5010
|
+
|
|
5011
|
+
// Everything else comes from the role, and this is the door when a module must move one of its
|
|
5012
|
+
// values. Anything set here is printed under "measured with" and marked \`(module)\`, so nobody
|
|
5013
|
+
// compares this module's figures with its neighbour's without seeing that they differ:
|
|
5014
|
+
//
|
|
5015
|
+
// overrides: {
|
|
5016
|
+
// duplication: { minTokens: 100 },
|
|
5017
|
+
// },
|
|
4987
5018
|
})
|
|
4988
5019
|
`;
|
|
4989
5020
|
var JscpdAdapter = class extends BaseAdapter {
|
|
@@ -5087,7 +5118,7 @@ ${result.stderr ?? ""}`
|
|
|
5087
5118
|
);
|
|
5088
5119
|
return { ok: false, code: result.status ?? 1 };
|
|
5089
5120
|
}
|
|
5090
|
-
const report = buildReport(ctx, rawReportDir);
|
|
5121
|
+
const report = buildReport(ctx, rawReportDir, config);
|
|
5091
5122
|
if (!report) {
|
|
5092
5123
|
process.stderr.write(`sentinel static-analysis(jscpd): jscpd wrote no report
|
|
5093
5124
|
`);
|
|
@@ -5135,7 +5166,18 @@ ${result.stderr ?? ""}`
|
|
|
5135
5166
|
function analysedNothing(stderr) {
|
|
5136
5167
|
return typeof stderr === "string" && stderr.includes("--fail-on-empty");
|
|
5137
5168
|
}
|
|
5138
|
-
function
|
|
5169
|
+
function duplicationSettings(config) {
|
|
5170
|
+
const moved = (key) => config.moved.some((path) => path === key || path.startsWith(`${key}.`));
|
|
5171
|
+
const row = (key, value) => ({ key, value, moved: moved(key) });
|
|
5172
|
+
return [
|
|
5173
|
+
row("duplication.minTokens", String(config.duplication.minTokens)),
|
|
5174
|
+
row("duplication.minLines", String(config.duplication.minLines)),
|
|
5175
|
+
row("duplication.kinds", config.duplication.kinds.join(", ")),
|
|
5176
|
+
row("languages", `${config.languages.length}: ${config.languages.join(", ")}`),
|
|
5177
|
+
row("ignore", `${config.ignore.length} patterns`)
|
|
5178
|
+
];
|
|
5179
|
+
}
|
|
5180
|
+
function buildReport(ctx, reportDir, config) {
|
|
5139
5181
|
const path = join19(reportDir, "jscpd-report.json");
|
|
5140
5182
|
if (!existsSync14(path)) return void 0;
|
|
5141
5183
|
let parsed;
|
|
@@ -5148,25 +5190,8 @@ function buildReport(ctx, reportDir) {
|
|
|
5148
5190
|
if (!total) return void 0;
|
|
5149
5191
|
const percent = Number((total.percentage ?? 0).toFixed(2));
|
|
5150
5192
|
const rows = [
|
|
5151
|
-
{
|
|
5152
|
-
|
|
5153
|
-
value: percent,
|
|
5154
|
-
unit: "%",
|
|
5155
|
-
// No threshold, and none is coming from here: see `preset-data.ts`. The figure is reported as
|
|
5156
|
-
// measured, and what makes it readable is the distribution it sits in, which one module
|
|
5157
|
-
// cannot know.
|
|
5158
|
-
threshold: null,
|
|
5159
|
-
over: false,
|
|
5160
|
-
moved: false
|
|
5161
|
-
},
|
|
5162
|
-
{
|
|
5163
|
-
metric: "clones",
|
|
5164
|
-
value: total.clones ?? 0,
|
|
5165
|
-
unit: "entries",
|
|
5166
|
-
threshold: null,
|
|
5167
|
-
over: false,
|
|
5168
|
-
moved: false
|
|
5169
|
-
}
|
|
5193
|
+
{ metric: "duplicatedLinesPercent", value: percent, unit: "%" },
|
|
5194
|
+
{ metric: "clones", value: total.clones ?? 0, unit: "entries" }
|
|
5170
5195
|
];
|
|
5171
5196
|
const formats = parsed.statistics?.formats ?? {};
|
|
5172
5197
|
const byLanguage = Object.fromEntries(
|
|
@@ -5179,7 +5204,13 @@ function buildReport(ctx, reportDir) {
|
|
|
5179
5204
|
}
|
|
5180
5205
|
])
|
|
5181
5206
|
);
|
|
5182
|
-
return {
|
|
5207
|
+
return {
|
|
5208
|
+
module: ctx.module,
|
|
5209
|
+
passes: ["duplication"],
|
|
5210
|
+
rows,
|
|
5211
|
+
settings: duplicationSettings(config),
|
|
5212
|
+
byLanguage
|
|
5213
|
+
};
|
|
5183
5214
|
}
|
|
5184
5215
|
function emit(report, shape, cwd) {
|
|
5185
5216
|
if (shape === "console") {
|
|
@@ -5197,8 +5228,12 @@ function emit(report, shape, cwd) {
|
|
|
5197
5228
|
function metricsOf(report) {
|
|
5198
5229
|
return {
|
|
5199
5230
|
passes: report.passes,
|
|
5200
|
-
finding: hasFinding(report),
|
|
5201
5231
|
...Object.fromEntries(report.rows.map((row) => [row.metric, row.value])),
|
|
5232
|
+
// Carried into `--json` and the CI comment for the same reason the console prints them: a
|
|
5233
|
+
// figure whose settings are unknown cannot be compared with the next module's.
|
|
5234
|
+
settings: Object.fromEntries(
|
|
5235
|
+
report.settings.map((s) => [s.key, { value: s.value, moved: s.moved }])
|
|
5236
|
+
),
|
|
5202
5237
|
byLanguage: report.byLanguage
|
|
5203
5238
|
};
|
|
5204
5239
|
}
|
package/dist/index.js
CHANGED
|
@@ -1171,6 +1171,14 @@ $ sentinel --init --dry-run
|
|
|
1171
1171
|
+ // Named product journeys, as { 'the name product uses': ['src/some/path/**'] }. Paths are
|
|
1172
1172
|
+ // relative to this module, because one run measures one module.
|
|
1173
1173
|
+ journeys: {},
|
|
1174
|
+
+
|
|
1175
|
+
+ // Everything else comes from the role, and this is the door when a module must move one of its
|
|
1176
|
+
+ // values. Anything set here is printed under "measured with" and marked `(module)`, so nobody
|
|
1177
|
+
+ // compares this module's figures with its neighbour's without seeing that they differ:
|
|
1178
|
+
+ //
|
|
1179
|
+
+ // overrides: {
|
|
1180
|
+
+ // duplication: { minTokens: 100 },
|
|
1181
|
+
+ // },
|
|
1174
1182
|
+ })
|
|
1175
1183
|
|
|
1176
1184
|
update package.json
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hublo/sentinel",
|
|
3
|
-
"version": "1.5.0-alpha.
|
|
3
|
+
"version": "1.5.0-alpha.6",
|
|
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",
|