@rsaglobaltech/specgate 0.26.0 → 0.27.1
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 +34 -0
- package/README.md +6 -0
- package/dist/packages/core/src/domain/ChangeMeasures.js +198 -0
- package/dist/packages/core/src/domain/ChangeMeasures.js.map +1 -0
- package/dist/packages/core/src/domain/ConventionalCommit.js +73 -0
- package/dist/packages/core/src/domain/ConventionalCommit.js.map +1 -0
- package/dist/packages/core/src/domain/HarnessConfig.js.map +1 -1
- package/dist/packages/core/src/domain/HarnessReport.js +2 -0
- package/dist/packages/core/src/domain/HarnessReport.js.map +1 -1
- package/dist/packages/core/src/domain/QualityChecks.js +218 -0
- package/dist/packages/core/src/domain/QualityChecks.js.map +1 -0
- package/dist/packages/core/src/domain/QualitySummary.js +58 -0
- package/dist/packages/core/src/domain/QualitySummary.js.map +1 -0
- package/dist/packages/core/src/domain/Sarif.js +121 -0
- package/dist/packages/core/src/domain/Sarif.js.map +1 -0
- package/dist/packages/core/src/infrastructure/GitContributionStager.js +1 -1
- package/dist/packages/core/src/infrastructure/GitContributionStager.js.map +1 -1
- package/dist/packages/core/src/infrastructure/HarnessConfigFile.js +21 -0
- package/dist/packages/core/src/infrastructure/HarnessConfigFile.js.map +1 -1
- package/dist/packages/core/src/infrastructure/QualityBaselineFile.js +67 -0
- package/dist/packages/core/src/infrastructure/QualityBaselineFile.js.map +1 -0
- package/dist/scripts/cli/commands/change/TicketCommand.js +1 -1
- package/dist/scripts/cli/commands/change/TicketCommand.js.map +1 -1
- package/dist/scripts/cli/commands/harness/RunCommand.js +212 -15
- package/dist/scripts/cli/commands/harness/RunCommand.js.map +1 -1
- package/dist/scripts/cli/commands/quality/CheckCommand.js +54 -3
- package/dist/scripts/cli/commands/quality/CheckCommand.js.map +1 -1
- package/dist/scripts/cli/commands/quality/QualityCommand.js +314 -0
- package/dist/scripts/cli/commands/quality/QualityCommand.js.map +1 -0
- package/dist/scripts/cli/commands/spec/DoneCommand.js +4 -1
- package/dist/scripts/cli/commands/spec/DoneCommand.js.map +1 -1
- package/dist/scripts/cli/commands/spec/StudioCommand.js +14 -0
- package/dist/scripts/cli/commands/spec/StudioCommand.js.map +1 -1
- package/dist/scripts/docs/nav.js +13 -2
- package/dist/scripts/docs/nav.js.map +1 -1
- package/dist/scripts/harness/prompt.js +4 -0
- package/dist/scripts/harness/prompt.js.map +1 -1
- package/dist/scripts/harness/report.js +13 -0
- package/dist/scripts/harness/report.js.map +1 -1
- package/dist/scripts/lib/quality-presets.js +378 -0
- package/dist/scripts/lib/quality-presets.js.map +1 -0
- package/dist/scripts/lib/quality-run.js +579 -0
- package/dist/scripts/lib/quality-run.js.map +1 -0
- package/dist/scripts/lib/sonar-local.js +308 -0
- package/dist/scripts/lib/sonar-local.js.map +1 -0
- package/dist/scripts/lib/studio-app-page.js +74 -11
- package/dist/scripts/lib/studio-app-page.js.map +1 -1
- package/dist/scripts/lib/studio-app.js +80 -0
- package/dist/scripts/lib/studio-app.js.map +1 -1
- package/dist/scripts/lib/studio-route.js +64 -1
- package/dist/scripts/lib/studio-route.js.map +1 -1
- package/dist/scripts/lib/surface.js +11 -0
- package/dist/scripts/lib/surface.js.map +1 -1
- package/dist/scripts/lib/ticket-keys.js +1 -1
- package/dist/scripts/lib/ticket-keys.js.map +1 -1
- package/dist/scripts/quality.js +10 -0
- package/dist/scripts/quality.js.map +1 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,40 @@ The release process is in [`docs/release-process.md`](docs/release-process.md).
|
|
|
9
9
|
|
|
10
10
|
## [Unreleased]
|
|
11
11
|
|
|
12
|
+
## [0.27.1] — 2026-10-28
|
|
13
|
+
|
|
14
|
+
0.27.0 reached ghcr.io only: its npm and GitHub Packages publish stopped on a quality check that failed on CI runners. This is that release, with the fix and the studio's new-project step working in an empty folder.
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- **A quality check run as the person has a home it can write**: in Docker on Linux, a check runs with your uid, and Semgrep failed when that uid was not the image's own user (uid 1001 on a CI runner) because it could not create its cache in `/`. It now runs with `HOME=/tmp`.
|
|
19
|
+
- **The studio stays up in an empty folder** (REQ-213): any request it does not serve, such as the browser's own `/favicon.ico`, made it read the matrix and exit when there was none, so the new-project step died on its first load. It answers 404 until the project exists. The step also says it asks five questions, not four.
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
|
|
23
|
+
- **The documentation shows the quality checks and the studio**: a band for each on the landing page, the studio under Start with a screenshot of every step, and the gate's section named after the tools it runs.
|
|
24
|
+
|
|
25
|
+
## [0.27.0] — 2026-10-28
|
|
26
|
+
|
|
27
|
+
Quality, not only tests: your team's checks in the gate — coverage and mutation of the lines a change adds, SpotBugs, PMD, Semgrep, secrets, dependencies, SonarQube and Conventional Commits — each in Docker, without an account, and only what a change adds fails.
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
|
|
31
|
+
- **Quality and security checks in the gate** (REQ-218, REQ-219, ADR-0040): `checks:` in `harness.config.yaml` names your team's tools — each with `when` (attempt, end, ci), whether it gates, and how it runs (Docker by default, local or auto). `check` runs them after the tests, `check --ci` adds the CI-only ones and fails a check that cannot run, and the harness runs them per attempt and before a requirement is kept.
|
|
32
|
+
- **Only what a change adds fails** (REQ-222, REQ-223): SARIF findings are compared with `.specgate/quality-baseline.json`; `specgate quality baseline --accept` records today's debt. Diff coverage (JaCoCo, LCOV, Cobertura) and mutation score (PIT, Stryker) are measured on the lines the change touched, against `diff_coverage` and `mutation_score`.
|
|
33
|
+
- **Presets for Maven, Gradle and Node** (REQ-225, REQ-230): `specgate quality init [--level basic|strict]` writes the checks for the stack it detects — JaCoCo, PIT, SpotBugs, PMD, Semgrep, gitleaks, osv-scanner, Vitest/Stryker — all in pinned Docker images, with dependency caches in named volumes. `quality list`, `quality doctor [--pull]` and `quality run` show and run them.
|
|
34
|
+
- **Conventional Commits** (REQ-234): `builtin:commits` checks each commit of the change against Conventional Commits 1.0.0, with `commit_types` to set the types.
|
|
35
|
+
- **SonarQube without an account** (REQ-226): `builtin:sonar` starts SonarQube Community in Docker on 127.0.0.1, analyses the change and judges its issues like any SARIF; the token stays in `.specgate/sonar.local`, ignored by git.
|
|
36
|
+
- **An agent that reviews** (REQ-227): `builtin:review` and `builtin:adversary` run a profile as reviewer of the diff; its verdict gates or advises.
|
|
37
|
+
- **Architecture as findings** (REQ-231): with `arch_sarif:`, only an architecture violation the change adds fails.
|
|
38
|
+
- **The quality of what was delivered** (REQ-220, REQ-221, REQ-228, REQ-229): each run record keeps its checks; `harness report` and the studio's report show diff coverage, mutation score and findings per requirement; the studio's Project page lists the checks and its new-project step asks for the level.
|
|
39
|
+
|
|
40
|
+
### Changed
|
|
41
|
+
|
|
42
|
+
- **Commit messages follow Conventional Commits** (REQ-234): a failed attempt is committed as `chore(REQ-NNN): attempt FAILED the gate` (resume still reads the old `wip` form), a green one as `feat(REQ-NNN): …`, and the agent's prompt asks for the same.
|
|
43
|
+
|
|
44
|
+
- **The studio commits the specification before a build** (REQ-233): the brief, approvals, answers and drafts the studio wrote are committed with the person's own git identity, so the harness finds the clean tree it needs. Any other uncommitted file stops the build, named, and is never committed.
|
|
45
|
+
|
|
12
46
|
## [0.26.0] — 2026-10-27
|
|
13
47
|
|
|
14
48
|
The studio becomes an app: from an empty folder to the report of what was built, step by step, without the commands. And a clean slate: everything a brief-to-app run left on the list, the test suite green on Windows.
|
package/README.md
CHANGED
|
@@ -89,6 +89,12 @@ you have:
|
|
|
89
89
|
- **Unattended delivery.** `specgate harness run` hands each pending requirement
|
|
90
90
|
to your coding agent in its own git worktree and keeps only what passes the
|
|
91
91
|
gate. → [The harness](docs/harness.md)
|
|
92
|
+
- **Quality, not only tests.** Coverage and mutation of the lines a change adds,
|
|
93
|
+
SpotBugs, PMD, Semgrep, secrets, dependencies, SonarQube and Conventional
|
|
94
|
+
Commits — each in Docker, no account, only new findings fail.
|
|
95
|
+
→ [Quality and security checks](docs/quality.md)
|
|
96
|
+
- **Without the commands.** `specgate studio` is the whole path as an app: from
|
|
97
|
+
an empty folder to the report of what was built. → [The studio](docs/studio.md)
|
|
92
98
|
- **Domain knowledge as a dependency.** Versioned domain packs install
|
|
93
99
|
requirements a team has already proved. → [Domain packs](docs/domain-packs.md)
|
|
94
100
|
- **Already on OpenSpec?** `specgate verify` checks what OpenSpec calls done
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* The two measures Specgate computes itself (ADR-0040 point 4): how much of
|
|
4
|
+
* the code a change touched its tests run, and how many of the mutants on
|
|
5
|
+
* those lines its tests kill. Read from the reports the project's tools
|
|
6
|
+
* already write — JaCoCo XML, LCOV, Cobertura; PIT `mutations.xml`, StrykerJS
|
|
7
|
+
* `mutation.json` — so no tool is bundled. Pure: the caller hands texts in.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.changedLines = changedLines;
|
|
11
|
+
exports.readJacoco = readJacoco;
|
|
12
|
+
exports.readLcov = readLcov;
|
|
13
|
+
exports.readCobertura = readCobertura;
|
|
14
|
+
exports.diffCoverage = diffCoverage;
|
|
15
|
+
exports.readPit = readPit;
|
|
16
|
+
exports.readStryker = readStryker;
|
|
17
|
+
exports.mutationScore = mutationScore;
|
|
18
|
+
/** Lines added or changed per file, from `git diff --unified=0`. */
|
|
19
|
+
function changedLines(diff) {
|
|
20
|
+
const out = new Map();
|
|
21
|
+
let file = "";
|
|
22
|
+
for (const line of diff.split(/\r?\n/)) {
|
|
23
|
+
const to = /^\+\+\+ (?:b\/)?(.+)$/.exec(line);
|
|
24
|
+
if (to) {
|
|
25
|
+
file = to[1] === "/dev/null" ? "" : to[1].trim();
|
|
26
|
+
if (file && !out.has(file))
|
|
27
|
+
out.set(file, new Set());
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
const hunk = /^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@/.exec(line);
|
|
31
|
+
if (hunk && file) {
|
|
32
|
+
const start = Number(hunk[1]);
|
|
33
|
+
const count = hunk[2] === undefined ? 1 : Number(hunk[2]);
|
|
34
|
+
for (let i = 0; i < count; i += 1)
|
|
35
|
+
out.get(file).add(start + i);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return out;
|
|
39
|
+
}
|
|
40
|
+
/** An attribute's value, in double or single quotes: PIT writes `status='KILLED'`. */
|
|
41
|
+
const attr = (tag, name) => (new RegExp(`\\b${name}=(?:"([^"]*)"|'([^']*)')`).exec(tag) || [])
|
|
42
|
+
.slice(1)
|
|
43
|
+
.find((v) => v !== undefined);
|
|
44
|
+
/** JaCoCo XML: `package/SourceFile.java` → its lines. */
|
|
45
|
+
function readJacoco(xml) {
|
|
46
|
+
const out = new Map();
|
|
47
|
+
const pkgRe = /<package\b([^>]*)>([\s\S]*?)<\/package>/g;
|
|
48
|
+
for (const pkg of xml.matchAll(pkgRe)) {
|
|
49
|
+
const pkgName = attr(pkg[1], "name") || "";
|
|
50
|
+
for (const src of pkg[2].matchAll(/<sourcefile\b([^>]*)>([\s\S]*?)<\/sourcefile>/g)) {
|
|
51
|
+
const key = `${pkgName ? `${pkgName}/` : ""}${attr(src[1], "name")}`;
|
|
52
|
+
const cov = { executable: new Set(), covered: new Set() };
|
|
53
|
+
for (const l of src[2].matchAll(/<line\b([^>]*)\/?>/g)) {
|
|
54
|
+
const nr = Number(attr(l[1], "nr"));
|
|
55
|
+
const mi = Number(attr(l[1], "mi") || 0);
|
|
56
|
+
const ci = Number(attr(l[1], "ci") || 0);
|
|
57
|
+
if (mi + ci > 0)
|
|
58
|
+
cov.executable.add(nr);
|
|
59
|
+
if (ci > 0)
|
|
60
|
+
cov.covered.add(nr);
|
|
61
|
+
}
|
|
62
|
+
out.set(key, cov);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return out;
|
|
66
|
+
}
|
|
67
|
+
/** LCOV: `SF:` path → its `DA:line,hits`. */
|
|
68
|
+
function readLcov(text) {
|
|
69
|
+
const out = new Map();
|
|
70
|
+
let cur = null;
|
|
71
|
+
for (const line of text.split(/\r?\n/)) {
|
|
72
|
+
if (line.startsWith("SF:")) {
|
|
73
|
+
cur = { executable: new Set(), covered: new Set() };
|
|
74
|
+
out.set(line.slice(3).trim().replace(/\\/g, "/"), cur);
|
|
75
|
+
}
|
|
76
|
+
else if (cur && line.startsWith("DA:")) {
|
|
77
|
+
const [nr, hits] = line.slice(3).split(",").map(Number);
|
|
78
|
+
cur.executable.add(nr);
|
|
79
|
+
if (hits > 0)
|
|
80
|
+
cur.covered.add(nr);
|
|
81
|
+
}
|
|
82
|
+
else if (line.startsWith("end_of_record"))
|
|
83
|
+
cur = null;
|
|
84
|
+
}
|
|
85
|
+
return out;
|
|
86
|
+
}
|
|
87
|
+
/** Cobertura: `<class filename>` → its `<line number hits>`. */
|
|
88
|
+
function readCobertura(xml) {
|
|
89
|
+
const out = new Map();
|
|
90
|
+
for (const cls of xml.matchAll(/<class\b([^>]*)>([\s\S]*?)<\/class>/g)) {
|
|
91
|
+
const file = (attr(cls[1], "filename") || "").replace(/\\/g, "/");
|
|
92
|
+
const cov = out.get(file) || { executable: new Set(), covered: new Set() };
|
|
93
|
+
for (const l of cls[2].matchAll(/<line\b([^>]*)\/?>/g)) {
|
|
94
|
+
const nr = Number(attr(l[1], "number"));
|
|
95
|
+
cov.executable.add(nr);
|
|
96
|
+
if (Number(attr(l[1], "hits") || 0) > 0)
|
|
97
|
+
cov.covered.add(nr);
|
|
98
|
+
}
|
|
99
|
+
out.set(file, cov);
|
|
100
|
+
}
|
|
101
|
+
return out;
|
|
102
|
+
}
|
|
103
|
+
/** The report's entry for a repository file: the same path, or one ending the other. */
|
|
104
|
+
function entryFor(map, file) {
|
|
105
|
+
const f = file.replace(/\\/g, "/");
|
|
106
|
+
if (map.has(f))
|
|
107
|
+
return map.get(f);
|
|
108
|
+
for (const [k, v] of map) {
|
|
109
|
+
const key = k.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
110
|
+
if (f.endsWith(`/${key}`) || key.endsWith(`/${f}`) || key === f)
|
|
111
|
+
return v;
|
|
112
|
+
}
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
115
|
+
const pct = (passed, total) => total === 0 ? null : Math.round((passed / total) * 1000) / 10;
|
|
116
|
+
/** Coverage of the executable lines a change touched. */
|
|
117
|
+
function diffCoverage(changed, report) {
|
|
118
|
+
let total = 0;
|
|
119
|
+
let passed = 0;
|
|
120
|
+
const misses = [];
|
|
121
|
+
for (const [file, lines] of changed) {
|
|
122
|
+
const cov = entryFor(report, file);
|
|
123
|
+
if (!cov)
|
|
124
|
+
continue;
|
|
125
|
+
for (const n of [...lines].sort((a, b) => a - b)) {
|
|
126
|
+
if (!cov.executable.has(n))
|
|
127
|
+
continue;
|
|
128
|
+
total += 1;
|
|
129
|
+
if (cov.covered.has(n))
|
|
130
|
+
passed += 1;
|
|
131
|
+
else
|
|
132
|
+
misses.push(`${file}:${n} not run by any test`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return { value: pct(passed, total), total, passed, misses };
|
|
136
|
+
}
|
|
137
|
+
/** PIT `mutations.xml`: KILLED and TIMED_OUT count as killed. */
|
|
138
|
+
function readPit(xml) {
|
|
139
|
+
const out = [];
|
|
140
|
+
for (const m of xml.matchAll(/<mutation\b([^>]*)>([\s\S]*?)<\/mutation>/g)) {
|
|
141
|
+
const tag = (name) => ((new RegExp(`<${name}>([\\s\\S]*?)</${name}>`).exec(m[2]) || [])[1] || "").trim();
|
|
142
|
+
const status = attr(m[1], "status") || "";
|
|
143
|
+
const cls = tag("mutatedClass").replace(/\$.*$/, "");
|
|
144
|
+
const source = tag("sourceFile");
|
|
145
|
+
const pkg = cls.includes(".") ? cls.slice(0, cls.lastIndexOf(".")).replace(/\./g, "/") : "";
|
|
146
|
+
out.push({
|
|
147
|
+
file: `${pkg ? `${pkg}/` : ""}${source}`,
|
|
148
|
+
line: Number(tag("lineNumber")),
|
|
149
|
+
killed: status === "KILLED" || status === "TIMED_OUT",
|
|
150
|
+
excluded: status === "NON_VIABLE" || status === "RUN_ERROR",
|
|
151
|
+
mutator: tag("mutator").split(".").pop() || "",
|
|
152
|
+
description: tag("description"),
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
return out;
|
|
156
|
+
}
|
|
157
|
+
/** StrykerJS `mutation.json` (mutation-testing-elements schema). */
|
|
158
|
+
function readStryker(text) {
|
|
159
|
+
const doc = JSON.parse(text);
|
|
160
|
+
const out = [];
|
|
161
|
+
for (const [file, f] of Object.entries(doc.files || {})) {
|
|
162
|
+
for (const m of f.mutants || []) {
|
|
163
|
+
const status = String(m.status || "");
|
|
164
|
+
out.push({
|
|
165
|
+
file: file.replace(/\\/g, "/"),
|
|
166
|
+
line: Number(m.location?.start?.line) || 0,
|
|
167
|
+
killed: status === "Killed" || status === "Timeout",
|
|
168
|
+
excluded: ["Ignored", "CompileError", "RuntimeError", "Pending"].includes(status),
|
|
169
|
+
mutator: String(m.mutatorName || ""),
|
|
170
|
+
description: m.replacement ? `replaced with ${m.replacement}` : "",
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return out;
|
|
175
|
+
}
|
|
176
|
+
/** The mutation score over the mutants on lines a change touched. */
|
|
177
|
+
function mutationScore(changed, mutants) {
|
|
178
|
+
let total = 0;
|
|
179
|
+
let passed = 0;
|
|
180
|
+
const misses = [];
|
|
181
|
+
const byFile = new Map();
|
|
182
|
+
for (const m of mutants)
|
|
183
|
+
byFile.set(m.file, [...(byFile.get(m.file) || []), m]);
|
|
184
|
+
for (const [file, lines] of changed) {
|
|
185
|
+
const list = entryFor(byFile, file) || [];
|
|
186
|
+
for (const m of list) {
|
|
187
|
+
if (m.excluded || !lines.has(m.line))
|
|
188
|
+
continue;
|
|
189
|
+
total += 1;
|
|
190
|
+
if (m.killed)
|
|
191
|
+
passed += 1;
|
|
192
|
+
else
|
|
193
|
+
misses.push(`${file}:${m.line} ${m.mutator} survived${m.description ? ` — ${m.description}` : ""}`);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return { value: pct(passed, total), total, passed, misses };
|
|
197
|
+
}
|
|
198
|
+
//# sourceMappingURL=ChangeMeasures.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChangeMeasures.js","sourceRoot":"","sources":["../../../../../packages/core/src/domain/ChangeMeasures.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Conventional Commits 1.0.0 (https://www.conventionalcommits.org/en/v1.0.0/),
|
|
4
|
+
* checked natively: the grammar is small and exact, so no tool is needed
|
|
5
|
+
* (REQ-234, ADR-0040 point 10). Pure.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.DEFAULT_TYPES = void 0;
|
|
9
|
+
exports.parseCommit = parseCommit;
|
|
10
|
+
exports.exempt = exempt;
|
|
11
|
+
/** commitlint's conventional types: feat and fix from the spec, the rest by convention. */
|
|
12
|
+
exports.DEFAULT_TYPES = [
|
|
13
|
+
"feat",
|
|
14
|
+
"fix",
|
|
15
|
+
"build",
|
|
16
|
+
"chore",
|
|
17
|
+
"ci",
|
|
18
|
+
"docs",
|
|
19
|
+
"perf",
|
|
20
|
+
"refactor",
|
|
21
|
+
"revert",
|
|
22
|
+
"style",
|
|
23
|
+
"test",
|
|
24
|
+
];
|
|
25
|
+
const HEADER = /^([A-Za-z]+)(?:\(([^()\r\n]*)\))?(!)?: (.*)$/;
|
|
26
|
+
/** A message parsed against the specification, with what it breaks. */
|
|
27
|
+
function parseCommit(message, types = exports.DEFAULT_TYPES) {
|
|
28
|
+
const lines = String(message || "")
|
|
29
|
+
.replace(/\r\n/g, "\n")
|
|
30
|
+
.replace(/\n+$/, "")
|
|
31
|
+
.split("\n");
|
|
32
|
+
const header = lines[0] || "";
|
|
33
|
+
const problems = [];
|
|
34
|
+
const m = HEADER.exec(header);
|
|
35
|
+
if (!m) {
|
|
36
|
+
const loose = /^([A-Za-z]+)(\([^)]*\))?!?:(\S|$)/.exec(header);
|
|
37
|
+
problems.push(loose
|
|
38
|
+
? "the colon must be followed by a space and a description — `type: description`"
|
|
39
|
+
: `no type — start with ${types.slice(0, 3).join(":, ")}: or another of ${types.length} types, e.g. "feat: add the booking form"`);
|
|
40
|
+
return { type: "", scope: "", breaking: false, description: header, problems };
|
|
41
|
+
}
|
|
42
|
+
const [, type, scope, bang, description] = m;
|
|
43
|
+
const known = types.map((t) => t.toLowerCase());
|
|
44
|
+
// The spec: units of information are not case sensitive, except BREAKING CHANGE.
|
|
45
|
+
if (!known.includes(type.toLowerCase())) {
|
|
46
|
+
problems.push(`"${type}" is not one of the types: ${types.join(", ")}`);
|
|
47
|
+
}
|
|
48
|
+
if (scope !== undefined && scope.trim() === "") {
|
|
49
|
+
problems.push("an empty scope — write `type(scope):` with a noun, or no parentheses");
|
|
50
|
+
}
|
|
51
|
+
if (!description.trim())
|
|
52
|
+
problems.push("no description after `type:`");
|
|
53
|
+
if (lines.length > 1 && lines[1].trim() !== "") {
|
|
54
|
+
problems.push("the body must start after one blank line");
|
|
55
|
+
}
|
|
56
|
+
let breaking = Boolean(bang);
|
|
57
|
+
for (const line of lines.slice(2)) {
|
|
58
|
+
if (/^BREAKING[ -]CHANGE: \S/.test(line))
|
|
59
|
+
breaking = true;
|
|
60
|
+
else if (/^breaking[ -]change\s*:/i.test(line)) {
|
|
61
|
+
problems.push("`BREAKING CHANGE:` must be written in capitals");
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return { type: type.toLowerCase(), scope: scope || "", breaking, description, problems };
|
|
65
|
+
}
|
|
66
|
+
/** Commits git writes, or that disappear in a rebase: not judged (merges are left out by the caller). */
|
|
67
|
+
function exempt(message, ci) {
|
|
68
|
+
const header = String(message || "").split("\n")[0];
|
|
69
|
+
if (/^Merge (branch|pull request|remote-tracking branch|[0-9a-f]{7,}|harness\/)/.test(header))
|
|
70
|
+
return true;
|
|
71
|
+
return !ci && /^(fixup|squash|amend)! /.test(header);
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=ConventionalCommit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConventionalCommit.js","sourceRoot":"","sources":["../../../../../packages/core/src/domain/ConventionalCommit.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HarnessConfig.js","sourceRoot":"","sources":["../../../../../packages/core/src/domain/HarnessConfig.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"HarnessConfig.js","sourceRoot":"","sources":["../../../../../packages/core/src/domain/HarnessConfig.ts"],"names":[],"mappings":";;;AAwFA,MAAa,aAAa;IAuBW;IAtB5B,MAAM,CAAU,QAAQ,GAAG,qBAAqB,CAAC;IACjD,MAAM,CAAU,gBAAgB,GAAoB;QACzD,KAAK,EAAE,EAAE;QACT,OAAO,EAAE,EAAE;QACX,WAAW,EAAE,CAAC;QACd,WAAW,EAAE,CAAC;QACd,YAAY,EAAE,EAAE;QAChB,IAAI,EAAE,KAAK;QACX,MAAM,EAAE,QAAQ;QAChB,KAAK,EAAE,EAAE;QACT,eAAe,EAAE,EAAE;QACnB,aAAa,EAAE,EAAE;QACjB,gBAAgB,EAAE,EAAE;QACpB,gBAAgB,EAAE,KAAK;QACvB,aAAa,EAAE,EAAE;QACjB,cAAc,EAAE,EAAE;QAClB,UAAU,EAAE,EAAE;QACd,aAAa,EAAE,EAAE;QACjB,cAAc,EAAE,EAAE;QAClB,YAAY,EAAE,EAAE;KACjB,CAAC;IAEF,YAAmC,QAAyB;QAAzB,aAAQ,GAAR,QAAQ,CAAiB;IAAG,CAAC;IAEzD,MAAM,CAAC,KAAK,CACjB,UAA2C,EAC3C,OAAiC;QAEjC,MAAM,IAAI,GAAG,UAAU,IAAI,EAAE,CAAC;QAC9B,OAAO,IAAI,aAAa,CAAC;YACvB,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,IAAI,aAAa,CAAC,gBAAgB,CAAC,KAAK;YAC1E,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,IAAI,CAAC,OAAO,IAAI,aAAa,CAAC,gBAAgB,CAAC,OAAO;YAClF,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,IAAI,CAAC,OAAO,IAAI,EAAE;YAC9C,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,EAAE;YAC7B,WAAW,EACT,OAAO,CAAC,WAAW,IAAI,IAAI,CAAC,WAAW,IAAI,aAAa,CAAC,gBAAgB,CAAC,WAAW;YACvF,WAAW,EACT,OAAO,CAAC,WAAW,IAAI,IAAI,CAAC,WAAW,IAAI,aAAa,CAAC,gBAAgB,CAAC,WAAW;YACvF,YAAY,EACV,OAAO,CAAC,YAAY,IAAI,IAAI,CAAC,YAAY,IAAI,aAAa,CAAC,gBAAgB,CAAC,YAAY;YAC1F,IAAI,EACF,OAAO,CAAC,IAAI,KAAK,SAAS;gBACxB,CAAC,CAAC,OAAO,CAAC,IAAI;gBACd,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,SAAS;oBACvB,CAAC,CAAC,IAAI,CAAC,IAAI;oBACX,CAAC,CAAC,aAAa,CAAC,gBAAgB,CAAC,IAAI;YAC3C,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,IAAI,aAAa,CAAC,gBAAgB,CAAC,MAAM;YAC9E,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,IAAI,aAAa,CAAC,gBAAgB,CAAC,KAAK;YAC1E,eAAe,EAAE,IAAI,CAAC,eAAe,IAAI,aAAa,CAAC,gBAAgB,CAAC,eAAe;YACvF,aAAa,EAAE,IAAI,CAAC,aAAa,IAAI,aAAa,CAAC,gBAAgB,CAAC,aAAa;YACjF,gBAAgB,EAAE,EAAE;YACpB,gBAAgB,EACd,IAAI,CAAC,gBAAgB,KAAK,SAAS;gBACjC,CAAC,CAAC,aAAa,CAAC,gBAAgB,CAAC,gBAAgB;gBACjD,CAAC,CAAC,IAAI,CAAC,gBAAgB,KAAK,IAAI;YACpC,aAAa,EAAE,IAAI,CAAC,aAAa,IAAI,aAAa,CAAC,gBAAgB,CAAC,aAAa;YACjF,uEAAuE;YACvE,uEAAuE;YACvE,6DAA6D;YAC7D,cAAc,EAAE,IAAI,CAAC,cAAc,IAAI,aAAa,CAAC,gBAAgB,CAAC,cAAc;YACpF,UAAU,EAAE,IAAI,CAAC,UAAU,IAAI,aAAa,CAAC,gBAAgB,CAAC,UAAU;YACxE,aAAa,EAAE,IAAI,CAAC,aAAa,IAAI,aAAa,CAAC,gBAAgB,CAAC,aAAa;YACjF,cAAc,EAAE,IAAI,CAAC,cAAc,IAAI,aAAa,CAAC,gBAAgB,CAAC,cAAc;YACpF,YAAY,EAAE,IAAI,CAAC,YAAY,IAAI,aAAa,CAAC,gBAAgB,CAAC,YAAY;SAC/E,CAAC,CAAC;IACL,CAAC;;AAlEH,sCAmEC"}
|
|
@@ -33,6 +33,7 @@ exports.STAGE_LABELS = void 0;
|
|
|
33
33
|
exports.summariseRuns = summariseRuns;
|
|
34
34
|
exports.parseFalseFailures = parseFalseFailures;
|
|
35
35
|
exports.sparkline = sparkline;
|
|
36
|
+
const QualitySummary_1 = require("./QualitySummary");
|
|
36
37
|
const RunBudget_1 = require("./RunBudget");
|
|
37
38
|
/** How an attempt ending is worth describing to a person. */
|
|
38
39
|
exports.STAGE_LABELS = Object.freeze({
|
|
@@ -123,6 +124,7 @@ function summariseRuns(runs, falseFailures = [], costPerRunHint = {}) {
|
|
|
123
124
|
estimatedCost: (0, RunBudget_1.estimateRunCost)(attemptProfiles, costPerRunHint),
|
|
124
125
|
falseFailures: falseCount,
|
|
125
126
|
realFailureRate: failed.length > 0 && marked.size > 0 ? (failed.length - falseCount) / failed.length : null,
|
|
127
|
+
quality: (0, QualitySummary_1.summariseQuality)(runs),
|
|
126
128
|
};
|
|
127
129
|
}
|
|
128
130
|
/** The ledger of human marks, one JSON object per line. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HarnessReport.js","sourceRoot":"","sources":["../../../../../packages/core/src/domain/HarnessReport.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;;;
|
|
1
|
+
{"version":3,"file":"HarnessReport.js","sourceRoot":"","sources":["../../../../../packages/core/src/domain/HarnessReport.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* The quality and security checks a team adds to the gate (ADR-0040).
|
|
4
|
+
*
|
|
5
|
+
* `harness.config.yaml` lists them under `checks:`; this module reads that
|
|
6
|
+
* list, refuses what cannot be run safely, and says which checks a stage runs.
|
|
7
|
+
* Pure: the caller hands the parsed YAML in.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.AGENT_BUILTINS = exports.BUILTINS = void 0;
|
|
11
|
+
exports.readQuality = readQuality;
|
|
12
|
+
exports.checksFor = checksFor;
|
|
13
|
+
exports.changedClasses = changedClasses;
|
|
14
|
+
exports.changedSources = changedSources;
|
|
15
|
+
exports.expandRun = expandRun;
|
|
16
|
+
/** Checks Specgate runs itself, without a tool: `run: builtin:commits` (REQ-234). */
|
|
17
|
+
exports.BUILTINS = ["builtin:commits", "builtin:sonar", "builtin:review", "builtin:adversary"];
|
|
18
|
+
/** Built-ins an agent performs: they run inside the harness only (REQ-227). */
|
|
19
|
+
exports.AGENT_BUILTINS = ["builtin:review", "builtin:adversary"];
|
|
20
|
+
const STAGES = ["attempt", "end", "ci"];
|
|
21
|
+
const RUNNERS = ["docker", "local", "auto"];
|
|
22
|
+
const FORMATS = ["jacoco", "lcov", "cobertura", "pit", "stryker"];
|
|
23
|
+
const CHECK_KEYS = new Set([
|
|
24
|
+
"name",
|
|
25
|
+
"run",
|
|
26
|
+
"when",
|
|
27
|
+
"gate",
|
|
28
|
+
"runner",
|
|
29
|
+
"image",
|
|
30
|
+
"network",
|
|
31
|
+
"shell",
|
|
32
|
+
"volumes",
|
|
33
|
+
"env",
|
|
34
|
+
"timeout",
|
|
35
|
+
"sarif",
|
|
36
|
+
"report",
|
|
37
|
+
"scope",
|
|
38
|
+
"profile",
|
|
39
|
+
]);
|
|
40
|
+
/** The thresholds a level means when the file does not set one. */
|
|
41
|
+
const LEVEL_THRESHOLDS = {
|
|
42
|
+
basic: { diffCoverage: 70, mutationScore: null },
|
|
43
|
+
strict: { diffCoverage: 85, mutationScore: 70 },
|
|
44
|
+
};
|
|
45
|
+
const relative = (p) => p !== "" && !/^([a-zA-Z]:)?[\\/]/.test(p) && !/(^|[\\/])\.\.([\\/]|$)/.test(p);
|
|
46
|
+
function list(value) {
|
|
47
|
+
if (value === undefined || value === null)
|
|
48
|
+
return [];
|
|
49
|
+
return (Array.isArray(value) ? value : [value]).map((v) => String(v).trim()).filter(Boolean);
|
|
50
|
+
}
|
|
51
|
+
function percent(value, key, errors) {
|
|
52
|
+
if (value === undefined || value === null || value === "")
|
|
53
|
+
return null;
|
|
54
|
+
const n = Number(value);
|
|
55
|
+
if (!Number.isFinite(n) || n < 0 || n > 100) {
|
|
56
|
+
errors.push(`\`${key}\` must be a percentage from 0 to 100, not "${String(value)}".`);
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
return n;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Read `quality`, `diff_coverage`, `mutation_score` and `checks` from the
|
|
63
|
+
* parsed file. Every problem is returned, worded for the person who wrote it.
|
|
64
|
+
*/
|
|
65
|
+
function readQuality(parsed) {
|
|
66
|
+
const errors = [];
|
|
67
|
+
const levelRaw = parsed.quality === undefined ? "" : String(parsed.quality).trim();
|
|
68
|
+
const level = (["basic", "strict", "custom", ""].includes(levelRaw) ? levelRaw : "");
|
|
69
|
+
if (levelRaw && !level) {
|
|
70
|
+
errors.push(`\`quality: ${levelRaw}\` is not a level. Use basic, strict or custom.`);
|
|
71
|
+
}
|
|
72
|
+
const defaults = LEVEL_THRESHOLDS[level] || { diffCoverage: null, mutationScore: null };
|
|
73
|
+
const diffCoverage = percent(parsed.diff_coverage, "diff_coverage", errors);
|
|
74
|
+
const mutationScore = percent(parsed.mutation_score, "mutation_score", errors);
|
|
75
|
+
const checks = [];
|
|
76
|
+
const raw = parsed.checks;
|
|
77
|
+
if (raw !== undefined && !Array.isArray(raw)) {
|
|
78
|
+
errors.push("`checks:` must be a list, each item starting with `- name:`.");
|
|
79
|
+
}
|
|
80
|
+
const seen = new Set();
|
|
81
|
+
for (const [i, item] of (Array.isArray(raw) ? raw : []).entries()) {
|
|
82
|
+
const where = `checks[${i + 1}]`;
|
|
83
|
+
if (!item || typeof item !== "object" || Array.isArray(item)) {
|
|
84
|
+
errors.push(`${where} is not a mapping with name: and run:.`);
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
const c = item;
|
|
88
|
+
const unknown = Object.keys(c).filter((k) => !CHECK_KEYS.has(k));
|
|
89
|
+
if (unknown.length) {
|
|
90
|
+
errors.push(`${where}: unknown key(s) ${unknown.join(", ")}. Known: ${[...CHECK_KEYS].join(", ")}.`);
|
|
91
|
+
}
|
|
92
|
+
const name = String(c.name ?? "").trim();
|
|
93
|
+
if (!/^[a-z0-9][a-z0-9-]*$/.test(name)) {
|
|
94
|
+
errors.push(`${where}: \`name\` must be lowercase words with dashes, e.g. spotbugs.`);
|
|
95
|
+
}
|
|
96
|
+
else if (seen.has(name)) {
|
|
97
|
+
errors.push(`${where}: the name ${name} is used twice.`);
|
|
98
|
+
}
|
|
99
|
+
seen.add(name);
|
|
100
|
+
const run = String(c.run ?? "").trim();
|
|
101
|
+
if (!run)
|
|
102
|
+
errors.push(`${where} (${name}): \`run\` is the command; it is missing.`);
|
|
103
|
+
const builtin = run.startsWith("builtin:");
|
|
104
|
+
if (builtin && !exports.BUILTINS.includes(run)) {
|
|
105
|
+
errors.push(`${where} (${name}): ${run} is not a built-in check. Known: ${exports.BUILTINS.join(", ")}.`);
|
|
106
|
+
}
|
|
107
|
+
const when = String(c.when ?? "attempt");
|
|
108
|
+
if (!STAGES.includes(when)) {
|
|
109
|
+
errors.push(`${where} (${name}): \`when: ${String(c.when)}\` — use attempt, end or ci.`);
|
|
110
|
+
}
|
|
111
|
+
const runner = String(c.runner ?? "auto");
|
|
112
|
+
if (!RUNNERS.includes(runner)) {
|
|
113
|
+
errors.push(`${where} (${name}): \`runner: ${String(c.runner)}\` — use docker, local or auto.`);
|
|
114
|
+
}
|
|
115
|
+
const image = String(c.image ?? "").trim();
|
|
116
|
+
if (runner === "docker" && !image && !builtin) {
|
|
117
|
+
errors.push(`${where} (${name}): \`runner: docker\` needs \`image:\`.`);
|
|
118
|
+
}
|
|
119
|
+
const env = list(c.env);
|
|
120
|
+
for (const e of env) {
|
|
121
|
+
if (e.includes("=")) {
|
|
122
|
+
errors.push(`${where} (${name}): \`env\` lists names only — "${e.split("=")[0]}=…" would put a secret in the repository.`);
|
|
123
|
+
}
|
|
124
|
+
else if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(e)) {
|
|
125
|
+
errors.push(`${where} (${name}): "${e}" is not an environment variable name.`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
const volumes = list(c.volumes);
|
|
129
|
+
for (const v of volumes) {
|
|
130
|
+
if (!/^[a-z0-9][a-z0-9_.-]*:\/[^\s]*$/.test(v)) {
|
|
131
|
+
errors.push(`${where} (${name}): volume "${v}" must be a named volume, name:/path — never a host folder.`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
const sarif = String(c.sarif ?? "").trim();
|
|
135
|
+
if (sarif && !relative(sarif)) {
|
|
136
|
+
errors.push(`${where} (${name}): \`sarif\` must be a path inside the project.`);
|
|
137
|
+
}
|
|
138
|
+
let report = null;
|
|
139
|
+
if (c.report !== undefined) {
|
|
140
|
+
const m = /^([a-z]+):(.+)$/.exec(String(c.report).trim());
|
|
141
|
+
if (!m || !FORMATS.includes(m[1]) || !relative(m[2].trim())) {
|
|
142
|
+
errors.push(`${where} (${name}): \`report\` is format:path, the format one of ${FORMATS.join(", ")}, the path inside the project.`);
|
|
143
|
+
}
|
|
144
|
+
else
|
|
145
|
+
report = { format: m[1], path: m[2].trim() };
|
|
146
|
+
}
|
|
147
|
+
const timeout = c.timeout === undefined ? 900 : Number(c.timeout);
|
|
148
|
+
if (!Number.isInteger(timeout) || timeout < 1) {
|
|
149
|
+
errors.push(`${where} (${name}): \`timeout\` is whole seconds.`);
|
|
150
|
+
}
|
|
151
|
+
const scope = String(c.scope ?? "diff");
|
|
152
|
+
if (scope !== "diff" && scope !== "all") {
|
|
153
|
+
errors.push(`${where} (${name}): \`scope\` is diff or all.`);
|
|
154
|
+
}
|
|
155
|
+
checks.push({
|
|
156
|
+
name,
|
|
157
|
+
run,
|
|
158
|
+
when,
|
|
159
|
+
gate: c.gate === undefined ? true : c.gate === true || c.gate === "true",
|
|
160
|
+
runner,
|
|
161
|
+
image,
|
|
162
|
+
network: c.network === undefined ? true : c.network === true || c.network === "true",
|
|
163
|
+
shell: c.shell === undefined ? true : c.shell === true || c.shell === "true",
|
|
164
|
+
volumes,
|
|
165
|
+
env,
|
|
166
|
+
timeout: Number.isInteger(timeout) && timeout > 0 ? timeout : 900,
|
|
167
|
+
sarif,
|
|
168
|
+
report,
|
|
169
|
+
scope: scope === "all" ? "all" : "diff",
|
|
170
|
+
profile: String(c.profile ?? "").trim(),
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
return {
|
|
174
|
+
config: {
|
|
175
|
+
level,
|
|
176
|
+
diffCoverage: diffCoverage ?? defaults.diffCoverage,
|
|
177
|
+
mutationScore: mutationScore ?? defaults.mutationScore,
|
|
178
|
+
checks,
|
|
179
|
+
commitTypes: list(parsed.commit_types),
|
|
180
|
+
},
|
|
181
|
+
errors,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* The checks a stage runs. `check` and `done` run attempt and end; `--ci`
|
|
186
|
+
* adds ci. The order is the file's: cheap first is the convention.
|
|
187
|
+
*/
|
|
188
|
+
function checksFor(config, stages) {
|
|
189
|
+
return config.checks.filter((c) => stages.includes(c.when));
|
|
190
|
+
}
|
|
191
|
+
/** Java classes of changed `src/main/java` files, for PIT's targetClasses. */
|
|
192
|
+
function changedClasses(files) {
|
|
193
|
+
return files
|
|
194
|
+
.map((f) => /(?:^|\/)src\/main\/java\/(.+)\.java$/.exec(f.replace(/\\/g, "/")))
|
|
195
|
+
.filter((m) => m !== null)
|
|
196
|
+
.map((m) => m[1].replace(/\//g, "."));
|
|
197
|
+
}
|
|
198
|
+
/** Changed TypeScript/JavaScript sources, tests left out, for Stryker's --mutate. */
|
|
199
|
+
function changedSources(files) {
|
|
200
|
+
return files.filter((f) => /\.(ts|tsx|js|jsx|mjs|cjs)$/.test(f) &&
|
|
201
|
+
!/(\.|\/)(test|spec)\.|(^|\/)(tests?|__tests__|e2e)\//.test(f));
|
|
202
|
+
}
|
|
203
|
+
/** The command with its placeholders filled. */
|
|
204
|
+
function expandRun(run, ctx) {
|
|
205
|
+
const values = {
|
|
206
|
+
"{req}": ctx.req,
|
|
207
|
+
"{base}": ctx.base,
|
|
208
|
+
"{changed_files}": ctx.changedFiles.join(" "),
|
|
209
|
+
"{changed_classes}": changedClasses(ctx.changedFiles).join(","),
|
|
210
|
+
"{changed_src}": changedSources(ctx.changedFiles).join(","),
|
|
211
|
+
"{report_dir}": ctx.reportDir,
|
|
212
|
+
};
|
|
213
|
+
let out = run;
|
|
214
|
+
for (const [k, v] of Object.entries(values))
|
|
215
|
+
out = out.split(k).join(v);
|
|
216
|
+
return out;
|
|
217
|
+
}
|
|
218
|
+
//# sourceMappingURL=QualityChecks.js.map
|