@produtype/core 0.16.2 → 0.17.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/dist/report/buildReport.js +28 -7
- package/dist/report/score.d.ts +38 -1
- package/dist/report/score.js +50 -2
- package/package.json +1 -1
|
@@ -136,9 +136,6 @@ function buildReport(analysis, options) {
|
|
|
136
136
|
inconclusiveReasons.push('No recognizable source files were found.');
|
|
137
137
|
}
|
|
138
138
|
}
|
|
139
|
-
// An unrecognized project has almost no applicable detectors, so the absence
|
|
140
|
-
// of findings must not be rewarded with a high score: cap it at prototype.
|
|
141
|
-
const overallScore = inconclusive ? Math.min(combinedScore, 39) : combinedScore;
|
|
142
139
|
/**
|
|
143
140
|
* Coverage counts the expectations too, not only the observed rules.
|
|
144
141
|
*
|
|
@@ -152,10 +149,34 @@ function buildReport(analysis, options) {
|
|
|
152
149
|
const passedChecksForMaturity = findings.filter((f) => f.status === 'passed').length + satisfiedExpectations;
|
|
153
150
|
const assessedChecks = findings.filter((f) => f.status !== 'unknown').length
|
|
154
151
|
+ Math.max(applicableExpectations - expectationFindings.length, 0);
|
|
155
|
-
const
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
152
|
+
const coverage = { passed: passedChecksForMaturity, assessed: assessedChecks };
|
|
153
|
+
// An unrecognized project has almost no applicable detectors, so the absence
|
|
154
|
+
// of findings must not be rewarded with a high score: cap it at prototype.
|
|
155
|
+
const scoreAfterInconclusive = inconclusive ? Math.min(combinedScore, 39) : combinedScore;
|
|
156
|
+
/**
|
|
157
|
+
* The number obeys the same rule as the label.
|
|
158
|
+
*
|
|
159
|
+
* The score starts at 100 and only ever subtracts, so a repository small enough that
|
|
160
|
+
* almost nothing applies to it keeps most of what it was handed. The maturity label
|
|
161
|
+
* has refused to call that production ready since the coverage rule was added — and
|
|
162
|
+
* the number beside it went on saying 98, above every real product in the verification
|
|
163
|
+
* corpus. A Python transcription script rested on three passing checks out of four and
|
|
164
|
+
* outscored this product's own web application, which rests on thirty.
|
|
165
|
+
*
|
|
166
|
+
* Nothing is subtracted for thin coverage, because there is nothing to subtract for:
|
|
167
|
+
* the report simply may not enter the top band on evidence that cannot support it.
|
|
168
|
+
*/
|
|
169
|
+
/**
|
|
170
|
+
* An unresolved critical bars the top band too.
|
|
171
|
+
*
|
|
172
|
+
* Counted before the score is capped, because it is one of the two reasons the top
|
|
173
|
+
* band can be refused and both must reach the number, not only the label.
|
|
174
|
+
*/
|
|
175
|
+
const openCriticals = findings.filter((f) => f.severity === 'critical' && f.status !== 'passed' && f.status !== 'unknown').length;
|
|
176
|
+
const overallScore = (0, score_1.mayClaimTopBand)(coverage, openCriticals)
|
|
177
|
+
? scoreAfterInconclusive
|
|
178
|
+
: Math.min(scoreAfterInconclusive, score_1.TOP_BAND_CEILING);
|
|
179
|
+
const maturityLevel = (0, score_1.computeMaturity)(overallScore, coverage, openCriticals);
|
|
159
180
|
const findingsByCategory = Object.fromEntries(types_1.CATEGORIES.map((c) => [c, []]));
|
|
160
181
|
for (const f of findings)
|
|
161
182
|
findingsByCategory[f.category].push(f);
|
package/dist/report/score.d.ts
CHANGED
|
@@ -10,4 +10,41 @@ export interface ScoreCoverage {
|
|
|
10
10
|
passed: number;
|
|
11
11
|
assessed: number;
|
|
12
12
|
}
|
|
13
|
-
|
|
13
|
+
/**
|
|
14
|
+
* The highest score a report can reach when it may not claim the top band.
|
|
15
|
+
*
|
|
16
|
+
* The band boundary itself, deliberately: a report that cannot support the words
|
|
17
|
+
* "production ready" must not print a number that reads like it either. Two things bar
|
|
18
|
+
* the top band — evidence too thin to support it, and an unresolved critical — and both
|
|
19
|
+
* land here.
|
|
20
|
+
*/
|
|
21
|
+
export declare const TOP_BAND_CEILING = 84;
|
|
22
|
+
/**
|
|
23
|
+
* Whether the report checked enough to stand behind a top-band reading.
|
|
24
|
+
*
|
|
25
|
+
* Its own function because two things ask the question — the label and the number — and
|
|
26
|
+
* they were answering it differently. A repository small enough that almost nothing
|
|
27
|
+
* applies to it was labelled `partial` and scored 98, above every real product in the
|
|
28
|
+
* corpus; the label had learned that absence of findings is not evidence of quality and
|
|
29
|
+
* the score had not.
|
|
30
|
+
*/
|
|
31
|
+
export declare function coverageSupportsTopBand(coverage: ScoreCoverage): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Whether a report may print a top-band number at all.
|
|
34
|
+
*
|
|
35
|
+
* The single place the two bars are stated, so the score and the label cannot drift
|
|
36
|
+
* apart again: they did, and the number went on reading 98 above every real product in
|
|
37
|
+
* the corpus while the label said `partial`.
|
|
38
|
+
*/
|
|
39
|
+
export declare function mayClaimTopBand(coverage: ScoreCoverage, openCriticals: number): boolean;
|
|
40
|
+
/**
|
|
41
|
+
* How many critical findings are open.
|
|
42
|
+
*
|
|
43
|
+
* A separate argument rather than something derived from the score, because the score
|
|
44
|
+
* subtracts a fixed weight and then moves on: a project with forty-two passing checks
|
|
45
|
+
* and one unresolved critical came out at 91 and was called production ready. The
|
|
46
|
+
* category scores have refused to let a critical hide behind passing checks since the
|
|
47
|
+
* severity ceiling was added — "a category with one critical and nine passing checks is
|
|
48
|
+
* not 90% healthy" — and the report's own headline had not learned it.
|
|
49
|
+
*/
|
|
50
|
+
export declare function computeMaturity(score: number, coverage?: ScoreCoverage, openCriticals?: number): MaturityLevel;
|
package/dist/report/score.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TOP_BAND_CEILING = void 0;
|
|
3
4
|
exports.computeScore = computeScore;
|
|
5
|
+
exports.coverageSupportsTopBand = coverageSupportsTopBand;
|
|
6
|
+
exports.mayClaimTopBand = mayClaimTopBand;
|
|
4
7
|
exports.computeMaturity = computeMaturity;
|
|
5
8
|
const penaltyBySeverity = {
|
|
6
9
|
critical: 15,
|
|
@@ -25,7 +28,48 @@ function computeScore(findings) {
|
|
|
25
28
|
* nothing.
|
|
26
29
|
*/
|
|
27
30
|
const MIN_VERIFIED_FOR_PRODUCTION = 6;
|
|
28
|
-
|
|
31
|
+
/**
|
|
32
|
+
* The highest score a report can reach when it may not claim the top band.
|
|
33
|
+
*
|
|
34
|
+
* The band boundary itself, deliberately: a report that cannot support the words
|
|
35
|
+
* "production ready" must not print a number that reads like it either. Two things bar
|
|
36
|
+
* the top band — evidence too thin to support it, and an unresolved critical — and both
|
|
37
|
+
* land here.
|
|
38
|
+
*/
|
|
39
|
+
exports.TOP_BAND_CEILING = 84;
|
|
40
|
+
/**
|
|
41
|
+
* Whether the report checked enough to stand behind a top-band reading.
|
|
42
|
+
*
|
|
43
|
+
* Its own function because two things ask the question — the label and the number — and
|
|
44
|
+
* they were answering it differently. A repository small enough that almost nothing
|
|
45
|
+
* applies to it was labelled `partial` and scored 98, above every real product in the
|
|
46
|
+
* corpus; the label had learned that absence of findings is not evidence of quality and
|
|
47
|
+
* the score had not.
|
|
48
|
+
*/
|
|
49
|
+
function coverageSupportsTopBand(coverage) {
|
|
50
|
+
return coverage.passed >= MIN_VERIFIED_FOR_PRODUCTION && coverage.passed * 2 >= coverage.assessed;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Whether a report may print a top-band number at all.
|
|
54
|
+
*
|
|
55
|
+
* The single place the two bars are stated, so the score and the label cannot drift
|
|
56
|
+
* apart again: they did, and the number went on reading 98 above every real product in
|
|
57
|
+
* the corpus while the label said `partial`.
|
|
58
|
+
*/
|
|
59
|
+
function mayClaimTopBand(coverage, openCriticals) {
|
|
60
|
+
return coverageSupportsTopBand(coverage) && openCriticals === 0;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* How many critical findings are open.
|
|
64
|
+
*
|
|
65
|
+
* A separate argument rather than something derived from the score, because the score
|
|
66
|
+
* subtracts a fixed weight and then moves on: a project with forty-two passing checks
|
|
67
|
+
* and one unresolved critical came out at 91 and was called production ready. The
|
|
68
|
+
* category scores have refused to let a critical hide behind passing checks since the
|
|
69
|
+
* severity ceiling was added — "a category with one critical and nine passing checks is
|
|
70
|
+
* not 90% healthy" — and the report's own headline had not learned it.
|
|
71
|
+
*/
|
|
72
|
+
function computeMaturity(score, coverage, openCriticals = 0) {
|
|
29
73
|
if (score <= 39)
|
|
30
74
|
return 'prototype';
|
|
31
75
|
if (score <= 64)
|
|
@@ -45,8 +89,12 @@ function computeMaturity(score, coverage) {
|
|
|
45
89
|
* Absence of findings is not evidence of quality. The top band now requires the
|
|
46
90
|
* report to be able to point at things it checked and found right.
|
|
47
91
|
*/
|
|
48
|
-
if (coverage && (coverage
|
|
92
|
+
if (coverage && !coverageSupportsTopBand(coverage)) {
|
|
49
93
|
return 'partial';
|
|
50
94
|
}
|
|
95
|
+
// Nothing is production ready while something critical is open in it. This is the one
|
|
96
|
+
// claim in the report a reader acts on without reading further.
|
|
97
|
+
if (openCriticals > 0)
|
|
98
|
+
return 'partial';
|
|
51
99
|
return 'production_ready';
|
|
52
100
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@produtype/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0",
|
|
4
4
|
"description": "Deterministic CLI and library that analyzes a web application repository and reports how far it is from production-ready for the kind of product it is meant to be.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"bin": {
|