@3f-consulting/spec-controller-core 0.1.0-alpha.7 → 0.1.0-alpha.70
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 +3 -3
- package/dist/assemble/evidenceReconciliationFromSources.d.ts +5 -40
- package/dist/assemble/evidenceReconciliationFromSources.d.ts.map +1 -1
- package/dist/assemble/evidenceReconciliationFromSources.js +30 -325
- package/dist/assemble/evidenceReconciliationFromSources.js.map +1 -1
- package/dist/assemble/renderInput.d.ts +7 -73
- package/dist/assemble/renderInput.d.ts.map +1 -1
- package/dist/assemble/renderInput.js +3 -45
- package/dist/assemble/renderInput.js.map +1 -1
- package/dist/census/evidenceObligations.d.ts +11 -46
- package/dist/census/evidenceObligations.d.ts.map +1 -1
- package/dist/census/evidenceObligations.js +19 -25
- package/dist/census/evidenceObligations.js.map +1 -1
- package/dist/domain/evidenceOrder.d.ts +3 -0
- package/dist/domain/evidenceOrder.d.ts.map +1 -0
- package/dist/domain/evidenceOrder.js +15 -0
- package/dist/domain/evidenceOrder.js.map +1 -0
- package/dist/domain/evidenceReconciliation.d.ts +21 -391
- package/dist/domain/evidenceReconciliation.d.ts.map +1 -1
- package/dist/domain/evidenceReconciliation.js +87 -382
- package/dist/domain/evidenceReconciliation.js.map +1 -1
- package/dist/domain/featureCode.d.ts +4 -0
- package/dist/domain/featureCode.d.ts.map +1 -0
- package/dist/domain/featureCode.js +12 -0
- package/dist/domain/featureCode.js.map +1 -0
- package/dist/domain/journal.d.ts +8 -393
- package/dist/domain/journal.d.ts.map +1 -1
- package/dist/domain/journal.js +6 -118
- package/dist/domain/journal.js.map +1 -1
- package/dist/domain/ledger.d.ts +8 -328
- package/dist/domain/ledger.d.ts.map +1 -1
- package/dist/domain/ledger.js +23 -326
- package/dist/domain/ledger.js.map +1 -1
- package/dist/domain/messages.d.ts +213 -0
- package/dist/domain/messages.d.ts.map +1 -0
- package/dist/domain/messages.js +313 -0
- package/dist/domain/messages.js.map +1 -0
- package/dist/domain/outcome.d.ts +3 -0
- package/dist/domain/outcome.d.ts.map +1 -0
- package/dist/domain/outcome.js +2 -0
- package/dist/domain/outcome.js.map +1 -0
- package/dist/domain/posting.d.ts +8 -105
- package/dist/domain/posting.d.ts.map +1 -1
- package/dist/domain/posting.js +4 -56
- package/dist/domain/posting.js.map +1 -1
- package/dist/domain/qualityCheckFault.d.ts +3 -43
- package/dist/domain/qualityCheckFault.d.ts.map +1 -1
- package/dist/domain/qualityCheckFault.js +0 -24
- package/dist/domain/qualityCheckFault.js.map +1 -1
- package/dist/domain/qualityCheckReconciliation.d.ts +7 -280
- package/dist/domain/qualityCheckReconciliation.d.ts.map +1 -1
- package/dist/domain/qualityCheckReconciliation.js +63 -463
- package/dist/domain/qualityCheckReconciliation.js.map +1 -1
- package/dist/domain/qualityCheckReconciliationFault.d.ts +0 -19
- package/dist/domain/qualityCheckReconciliationFault.d.ts.map +1 -1
- package/dist/domain/qualityCheckReconciliationFault.js +1 -24
- package/dist/domain/qualityCheckReconciliationFault.js.map +1 -1
- package/dist/domain/scenarioCodeError.d.ts +16 -0
- package/dist/domain/scenarioCodeError.d.ts.map +1 -0
- package/dist/domain/scenarioCodeError.js +4 -0
- package/dist/domain/scenarioCodeError.js.map +1 -0
- package/dist/domain/scenarioReconciliation.d.ts +2 -207
- package/dist/domain/scenarioReconciliation.d.ts.map +1 -1
- package/dist/domain/scenarioReconciliation.js +4 -101
- package/dist/domain/scenarioReconciliation.js.map +1 -1
- package/dist/domain/scnAllocation.d.ts +27 -0
- package/dist/domain/scnAllocation.d.ts.map +1 -0
- package/dist/domain/scnAllocation.js +33 -0
- package/dist/domain/scnAllocation.js.map +1 -0
- package/dist/domain/verdictCode.d.ts +10 -0
- package/dist/domain/verdictCode.d.ts.map +1 -0
- package/dist/domain/verdictCode.js +16 -0
- package/dist/domain/verdictCode.js.map +1 -0
- package/dist/index.d.ts +14 -40
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -88
- package/dist/index.js.map +1 -1
- package/dist/internal.d.ts +3 -27
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +3 -94
- package/dist/internal.js.map +1 -1
- package/dist/lib/bareTerm.d.ts +0 -39
- package/dist/lib/bareTerm.d.ts.map +1 -1
- package/dist/lib/bareTerm.js +0 -39
- package/dist/lib/bareTerm.js.map +1 -1
- package/dist/lib/portablePath.d.ts.map +1 -1
- package/dist/lib/portablePath.js +2 -16
- package/dist/lib/portablePath.js.map +1 -1
- package/dist/lib/scnCitation.d.ts +0 -32
- package/dist/lib/scnCitation.d.ts.map +1 -1
- package/dist/lib/scnCitation.js +2 -42
- package/dist/lib/scnCitation.js.map +1 -1
- package/dist/model.d.ts +0 -23
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +0 -23
- package/dist/model.js.map +1 -1
- package/dist/parse/checkScriptsRunInCI.d.ts +5 -168
- package/dist/parse/checkScriptsRunInCI.d.ts.map +1 -1
- package/dist/parse/checkScriptsRunInCI.js +11 -171
- package/dist/parse/checkScriptsRunInCI.js.map +1 -1
- package/dist/parse/ciStepRecord.d.ts +4 -118
- package/dist/parse/ciStepRecord.d.ts.map +1 -1
- package/dist/parse/ciStepRecord.js +18 -225
- package/dist/parse/ciStepRecord.js.map +1 -1
- package/dist/parse/commandRuns.d.ts +0 -39
- package/dist/parse/commandRuns.d.ts.map +1 -1
- package/dist/parse/commandRuns.js +6 -67
- package/dist/parse/commandRuns.js.map +1 -1
- package/dist/parse/cucumber.d.ts +0 -53
- package/dist/parse/cucumber.d.ts.map +1 -1
- package/dist/parse/cucumber.js +42 -146
- package/dist/parse/cucumber.js.map +1 -1
- package/dist/parse/discoveryScope.d.ts +1 -46
- package/dist/parse/discoveryScope.d.ts.map +1 -1
- package/dist/parse/discoveryScope.js +2 -57
- package/dist/parse/discoveryScope.js.map +1 -1
- package/dist/parse/fitnessCitations.d.ts +1 -72
- package/dist/parse/fitnessCitations.d.ts.map +1 -1
- package/dist/parse/fitnessCitations.js +3 -55
- package/dist/parse/fitnessCitations.js.map +1 -1
- package/dist/parse/reconcilerSteps.d.ts +0 -46
- package/dist/parse/reconcilerSteps.d.ts.map +1 -1
- package/dist/parse/reconcilerSteps.js +2 -64
- package/dist/parse/reconcilerSteps.js.map +1 -1
- package/dist/parse/runningFitnessFunctions.d.ts +9 -0
- package/dist/parse/runningFitnessFunctions.d.ts.map +1 -0
- package/dist/parse/runningFitnessFunctions.js +57 -0
- package/dist/parse/runningFitnessFunctions.js.map +1 -0
- package/dist/parse/scenarioCodeErrors.d.ts +11 -0
- package/dist/parse/scenarioCodeErrors.d.ts.map +1 -0
- package/dist/parse/scenarioCodeErrors.js +78 -0
- package/dist/parse/scenarioCodeErrors.js.map +1 -0
- package/dist/parse/scenarios.d.ts +3 -228
- package/dist/parse/scenarios.d.ts.map +1 -1
- package/dist/parse/scenarios.js +20 -457
- package/dist/parse/scenarios.js.map +1 -1
- package/dist/parse/stepAccounting.d.ts +0 -46
- package/dist/parse/stepAccounting.d.ts.map +1 -1
- package/dist/parse/stepAccounting.js +1 -55
- package/dist/parse/stepAccounting.js.map +1 -1
- package/dist/parse/stepExclusions.d.ts +0 -47
- package/dist/parse/stepExclusions.d.ts.map +1 -1
- package/dist/parse/stepExclusions.js +2 -50
- package/dist/parse/stepExclusions.js.map +1 -1
- package/dist/parse/stepNames.d.ts +0 -27
- package/dist/parse/stepNames.d.ts.map +1 -1
- package/dist/parse/stepNames.js +0 -27
- package/dist/parse/stepNames.js.map +1 -1
- package/dist/parse/targetCorpus.d.ts +1 -78
- package/dist/parse/targetCorpus.d.ts.map +1 -1
- package/dist/parse/targetCorpus.js +4 -46
- package/dist/parse/targetCorpus.js.map +1 -1
- package/dist/parse/targetManifest.d.ts +8 -146
- package/dist/parse/targetManifest.d.ts.map +1 -1
- package/dist/parse/targetManifest.js +48 -198
- package/dist/parse/targetManifest.js.map +1 -1
- package/dist/parse/vitest.d.ts +0 -60
- package/dist/parse/vitest.d.ts.map +1 -1
- package/dist/parse/vitest.js +4 -83
- package/dist/parse/vitest.js.map +1 -1
- package/dist/provenance/provenance.d.ts +2 -110
- package/dist/provenance/provenance.d.ts.map +1 -1
- package/dist/provenance/provenance.js +2 -58
- package/dist/provenance/provenance.js.map +1 -1
- package/dist/render/behaviouralRunners.d.ts +0 -29
- package/dist/render/behaviouralRunners.d.ts.map +1 -1
- package/dist/render/behaviouralRunners.js +6 -69
- package/dist/render/behaviouralRunners.js.map +1 -1
- package/dist/render/configurationNotRead.d.ts +3 -0
- package/dist/render/configurationNotRead.d.ts.map +1 -0
- package/dist/render/configurationNotRead.js +17 -0
- package/dist/render/configurationNotRead.js.map +1 -0
- package/dist/render/discoveryScope.d.ts +0 -37
- package/dist/render/discoveryScope.d.ts.map +1 -1
- package/dist/render/discoveryScope.js +3 -39
- package/dist/render/discoveryScope.js.map +1 -1
- package/dist/render/evidenceGrid.d.ts +1 -35
- package/dist/render/evidenceGrid.d.ts.map +1 -1
- package/dist/render/evidenceGrid.js +21 -103
- package/dist/render/evidenceGrid.js.map +1 -1
- package/dist/render/excludedSteps.d.ts +0 -26
- package/dist/render/excludedSteps.d.ts.map +1 -1
- package/dist/render/excludedSteps.js +4 -32
- package/dist/render/excludedSteps.js.map +1 -1
- package/dist/render/fitnessFunctions.d.ts +3 -0
- package/dist/render/fitnessFunctions.d.ts.map +1 -0
- package/dist/render/fitnessFunctions.js +12 -0
- package/dist/render/fitnessFunctions.js.map +1 -0
- package/dist/render/json.d.ts +0 -11
- package/dist/render/json.d.ts.map +1 -1
- package/dist/render/json.js +0 -11
- package/dist/render/json.js.map +1 -1
- package/dist/render/markdown.d.ts +1 -55
- package/dist/render/markdown.d.ts.map +1 -1
- package/dist/render/markdown.js +128 -467
- package/dist/render/markdown.js.map +1 -1
- package/dist/render/provenanceSection.d.ts +0 -22
- package/dist/render/provenanceSection.d.ts.map +1 -1
- package/dist/render/provenanceSection.js +10 -53
- package/dist/render/provenanceSection.js.map +1 -1
- package/dist/render/reconcilerSteps.d.ts +0 -25
- package/dist/render/reconcilerSteps.d.ts.map +1 -1
- package/dist/render/reconcilerSteps.js +5 -30
- package/dist/render/reconcilerSteps.js.map +1 -1
- package/dist/render/runVerdict.d.ts +0 -38
- package/dist/render/runVerdict.d.ts.map +1 -1
- package/dist/render/runVerdict.js +62 -129
- package/dist/render/runVerdict.js.map +1 -1
- package/dist/render/scenarioCodeErrorsSection.d.ts +3 -0
- package/dist/render/scenarioCodeErrorsSection.d.ts.map +1 -0
- package/dist/render/scenarioCodeErrorsSection.js +45 -0
- package/dist/render/scenarioCodeErrorsSection.js.map +1 -0
- package/dist/render/stepAccounting.d.ts +0 -36
- package/dist/render/stepAccounting.d.ts.map +1 -1
- package/dist/render/stepAccounting.js +5 -49
- package/dist/render/stepAccounting.js.map +1 -1
- package/dist/render/testVolume.d.ts +0 -25
- package/dist/render/testVolume.d.ts.map +1 -1
- package/dist/render/testVolume.js +4 -35
- package/dist/render/testVolume.js.map +1 -1
- package/package.json +4 -1
- package/dist/domain/checkCharacteristics.d.ts +0 -88
- package/dist/domain/checkCharacteristics.d.ts.map +0 -1
- package/dist/domain/checkCharacteristics.js +0 -109
- package/dist/domain/checkCharacteristics.js.map +0 -1
- package/dist/domain/fitnessChecks.d.ts +0 -79
- package/dist/domain/fitnessChecks.d.ts.map +0 -1
- package/dist/domain/fitnessChecks.js +0 -81
- package/dist/domain/fitnessChecks.js.map +0 -1
- package/dist/domain/qualityCheckFaultMessages.d.ts +0 -43
- package/dist/domain/qualityCheckFaultMessages.d.ts.map +0 -1
- package/dist/domain/qualityCheckFaultMessages.js +0 -38
- package/dist/domain/qualityCheckFaultMessages.js.map +0 -1
- package/dist/lib/featureCode.d.ts +0 -21
- package/dist/lib/featureCode.d.ts.map +0 -1
- package/dist/lib/featureCode.js +0 -24
- package/dist/lib/featureCode.js.map +0 -1
- package/dist/parse/corpusCodeFaults.d.ts +0 -76
- package/dist/parse/corpusCodeFaults.d.ts.map +0 -1
- package/dist/parse/corpusCodeFaults.js +0 -121
- package/dist/parse/corpusCodeFaults.js.map +0 -1
- package/dist/parse/corpusFaults.d.ts +0 -124
- package/dist/parse/corpusFaults.d.ts.map +0 -1
- package/dist/parse/corpusFaults.js +0 -72
- package/dist/parse/corpusFaults.js.map +0 -1
- package/dist/parse/corpusGrammarFaults.d.ts +0 -71
- package/dist/parse/corpusGrammarFaults.d.ts.map +0 -1
- package/dist/parse/corpusGrammarFaults.js +0 -292
- package/dist/parse/corpusGrammarFaults.js.map +0 -1
- package/dist/parse/runningStaticChecks.d.ts +0 -125
- package/dist/parse/runningStaticChecks.d.ts.map +0 -1
- package/dist/parse/runningStaticChecks.js +0 -316
- package/dist/parse/runningStaticChecks.js.map +0 -1
- package/dist/render/staticChecks.d.ts +0 -23
- package/dist/render/staticChecks.d.ts.map +0 -1
- package/dist/render/staticChecks.js +0 -69
- package/dist/render/staticChecks.js.map +0 -1
|
@@ -1,53 +1,7 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* THE RECONCILER'S OWN STEPS (@SCN-USG-014, 3F-3343) — which steps of a target's pipeline are this
|
|
3
|
-
* reconciliation rather than something it reconciles, and how the report says so.
|
|
4
|
-
*
|
|
5
|
-
* THE SECOND EXCLUSION, AND THE ONLY ONE NOBODY CONFIGURES. A behavioural runner is excluded by a
|
|
6
|
-
* rule over what the target named and a non-check by the consumer's own list; this one is excluded
|
|
7
|
-
* BY CONSTRUCTION, because the run that computes the books cannot be a row in them. The
|
|
8
|
-
* distinction is not a nicety: a `notChecks` pair produces the identical report over the identical
|
|
9
|
-
* pipeline, and the two answers part company only at the consumer who has written nothing — whose
|
|
10
|
-
* very first run would otherwise report their own reconciler as an uncited fitness check, and go
|
|
11
|
-
* on doing so until they learned to configure it away.
|
|
12
|
-
*
|
|
13
|
-
* A CITATION ON EITHER IS UNSATISFIABLE, WHICH IS WHAT MAKES IT CONSTRUCTION RATHER THAN JUDGEMENT.
|
|
14
|
-
* The step record is written BEFORE the reconciliation reads it — necessarily, since that record
|
|
15
|
-
* is its input — so no run's record can ever carry the reconciling step's own outcome, and no
|
|
16
|
-
* scenario can ever be shown to have been answered by it. A demand nothing could satisfy is not a
|
|
17
|
-
* check somebody failed to cite. It is not a check.
|
|
18
|
-
*
|
|
19
|
-
* TWO HALVES, RECOGNISED TWO WAYS, AND NEITHER IS A LIST OF NAMES.
|
|
20
|
-
*
|
|
21
|
-
* - THE RUN: a step whose command runs this tool's own reconciling invocation, compared as whole
|
|
22
|
-
* adjacent shell tokens and followed through the manifest scripts a step invokes — the runner
|
|
23
|
-
* rule's own comparison (`parse/commandRuns`), because a pipeline invokes a binary through a
|
|
24
|
-
* script alias far more often than it writes its name. ADJACENT is what keeps the same binary
|
|
25
|
-
* run for another purpose a candidate: this repository's own pipeline runs `spec-controller
|
|
26
|
-
* tags` beside its balance step, and that is an ordinary step of the pipeline being reconciled.
|
|
27
|
-
* - THE RECORD: a step carrying GitHub's own step-record expression, which is the only way that
|
|
28
|
-
* record can be produced. Read off the step's `env:` and its command, wherever the consumer
|
|
29
|
-
* wrote it, and not off its title — a step called `Dump this run's step record` that produces
|
|
30
|
-
* no record is an ordinary step, and one called anything at all that produces the record is
|
|
31
|
-
* the dump.
|
|
32
|
-
*
|
|
33
|
-
* THE INVOCATION IS INJECTED, NEVER ASSUMED. How this product is invoked at a consumer's command
|
|
34
|
-
* line is a fact the application edge holds (`ingest/ingestQualityChecks.ts`), like the script
|
|
35
|
-
* prefixes and the workflow names beside it; the core is handed it as data. A run told no
|
|
36
|
-
* invocation recognises no reconciling step, which is the safe direction — a candidate too many,
|
|
37
|
-
* visible on the report, rather than a step taken off the books by a rule nobody supplied.
|
|
38
|
-
*
|
|
39
|
-
* THE ACCOUNT AND THE SEAM COME OFF ONE RULE. `isReconciler` re-asks the same question of a single
|
|
40
|
-
* step rather than consulting the list this module built, so the account the report prints and the
|
|
41
|
-
* steps discovery skipped cannot come to disagree — a step named on the report as the reconciler
|
|
42
|
-
* while its check sits on the books is a report that contradicts itself in one page.
|
|
43
|
-
*/
|
|
44
1
|
import { type CiWorkflowStep } from "./checkScriptsRunInCI.js";
|
|
45
2
|
import type { ReconcilerStep } from "../domain/evidenceReconciliation.js";
|
|
46
|
-
/** What a run's pipeline yielded of the reconciler — the account, and the one answer per step. */
|
|
47
3
|
export interface ReconcilerSteps {
|
|
48
|
-
/** The steps that are the reconciler, in the order the pipeline runs them. */
|
|
49
4
|
readonly steps: readonly ReconcilerStep[];
|
|
50
|
-
/** Whether this step is the reconciler rather than a step of the pipeline it reconciles. */
|
|
51
5
|
readonly isReconciler: (step: CiWorkflowStep) => boolean;
|
|
52
6
|
}
|
|
53
7
|
export declare function reconcilerSteps(ciSources: readonly string[], ciSourceNames: readonly string[], invocation: string, packageJson: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reconcilerSteps.d.ts","sourceRoot":"","sources":["../../src/parse/reconcilerSteps.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"reconcilerSteps.d.ts","sourceRoot":"","sources":["../../src/parse/reconcilerSteps.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAGhF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAC;AAE1E,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,KAAK,EAAE,SAAS,cAAc,EAAE,CAAC;IAC1C,QAAQ,CAAC,YAAY,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,OAAO,CAAC;CAC1D;AAoBD,wBAAgB,eAAe,CAC7B,SAAS,EAAE,SAAS,MAAM,EAAE,EAC5B,aAAa,EAAE,SAAS,MAAM,EAAE,EAChC,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GAChD,eAAe,CAWjB"}
|
|
@@ -1,67 +1,11 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* THE RECONCILER'S OWN STEPS (@SCN-USG-014, 3F-3343) — which steps of a target's pipeline are this
|
|
3
|
-
* reconciliation rather than something it reconciles, and how the report says so.
|
|
4
|
-
*
|
|
5
|
-
* THE SECOND EXCLUSION, AND THE ONLY ONE NOBODY CONFIGURES. A behavioural runner is excluded by a
|
|
6
|
-
* rule over what the target named and a non-check by the consumer's own list; this one is excluded
|
|
7
|
-
* BY CONSTRUCTION, because the run that computes the books cannot be a row in them. The
|
|
8
|
-
* distinction is not a nicety: a `notChecks` pair produces the identical report over the identical
|
|
9
|
-
* pipeline, and the two answers part company only at the consumer who has written nothing — whose
|
|
10
|
-
* very first run would otherwise report their own reconciler as an uncited fitness check, and go
|
|
11
|
-
* on doing so until they learned to configure it away.
|
|
12
|
-
*
|
|
13
|
-
* A CITATION ON EITHER IS UNSATISFIABLE, WHICH IS WHAT MAKES IT CONSTRUCTION RATHER THAN JUDGEMENT.
|
|
14
|
-
* The step record is written BEFORE the reconciliation reads it — necessarily, since that record
|
|
15
|
-
* is its input — so no run's record can ever carry the reconciling step's own outcome, and no
|
|
16
|
-
* scenario can ever be shown to have been answered by it. A demand nothing could satisfy is not a
|
|
17
|
-
* check somebody failed to cite. It is not a check.
|
|
18
|
-
*
|
|
19
|
-
* TWO HALVES, RECOGNISED TWO WAYS, AND NEITHER IS A LIST OF NAMES.
|
|
20
|
-
*
|
|
21
|
-
* - THE RUN: a step whose command runs this tool's own reconciling invocation, compared as whole
|
|
22
|
-
* adjacent shell tokens and followed through the manifest scripts a step invokes — the runner
|
|
23
|
-
* rule's own comparison (`parse/commandRuns`), because a pipeline invokes a binary through a
|
|
24
|
-
* script alias far more often than it writes its name. ADJACENT is what keeps the same binary
|
|
25
|
-
* run for another purpose a candidate: this repository's own pipeline runs `spec-controller
|
|
26
|
-
* tags` beside its balance step, and that is an ordinary step of the pipeline being reconciled.
|
|
27
|
-
* - THE RECORD: a step carrying GitHub's own step-record expression, which is the only way that
|
|
28
|
-
* record can be produced. Read off the step's `env:` and its command, wherever the consumer
|
|
29
|
-
* wrote it, and not off its title — a step called `Dump this run's step record` that produces
|
|
30
|
-
* no record is an ordinary step, and one called anything at all that produces the record is
|
|
31
|
-
* the dump.
|
|
32
|
-
*
|
|
33
|
-
* THE INVOCATION IS INJECTED, NEVER ASSUMED. How this product is invoked at a consumer's command
|
|
34
|
-
* line is a fact the application edge holds (`ingest/ingestQualityChecks.ts`), like the script
|
|
35
|
-
* prefixes and the workflow names beside it; the core is handed it as data. A run told no
|
|
36
|
-
* invocation recognises no reconciling step, which is the safe direction — a candidate too many,
|
|
37
|
-
* visible on the report, rather than a step taken off the books by a rule nobody supplied.
|
|
38
|
-
*
|
|
39
|
-
* THE ACCOUNT AND THE SEAM COME OFF ONE RULE. `isReconciler` re-asks the same question of a single
|
|
40
|
-
* step rather than consulting the list this module built, so the account the report prints and the
|
|
41
|
-
* steps discovery skipped cannot come to disagree — a step named on the report as the reconciler
|
|
42
|
-
* while its check sits on the books is a report that contradicts itself in one page.
|
|
43
|
-
*/
|
|
44
1
|
import { ciWorkflowSteps } from "./checkScriptsRunInCI.js";
|
|
45
2
|
import { commandRuns } from "./commandRuns.js";
|
|
46
3
|
import { qualifiedStepName } from "./stepNames.js";
|
|
47
|
-
/**
|
|
48
|
-
* GitHub'S OWN EXPRESSION FOR THE RUN'S STEP RECORD, whitespace-stripped and lowercased to compare
|
|
49
|
-
* against — its function names are case-insensitive and its expressions tolerate spacing, so
|
|
50
|
-
* `${{ toJSON(steps) }}` and `${{tojson(steps)}}` are one expression and get one answer.
|
|
51
|
-
*/
|
|
52
4
|
const STEP_RECORD_EXPRESSION = "tojson(steps)";
|
|
53
|
-
/** Does this step produce the run's own step record — the input the reconciliation reads? */
|
|
54
5
|
function producesTheStepRecord(step) {
|
|
55
|
-
|
|
6
|
+
const written = "runs" in step ? [...step.env, step.runs] : step.env;
|
|
7
|
+
return written.some((text) => text.replace(/\s/g, "").toLowerCase().includes(STEP_RECORD_EXPRESSION));
|
|
56
8
|
}
|
|
57
|
-
/**
|
|
58
|
-
* Which half of the reconciler this step is, or nothing at all.
|
|
59
|
-
*
|
|
60
|
-
* THE RUN IS ASKED FIRST, so a step that both reconciles and dumps is named as the reconciliation
|
|
61
|
-
* rather than as its input. Either way it is off the books; what the order settles is only which
|
|
62
|
-
* of the two sentences the report prints, and the stronger fact about such a step is that it runs
|
|
63
|
-
* the reconciliation.
|
|
64
|
-
*/
|
|
65
9
|
function roleOf(step, invocation, scripts) {
|
|
66
10
|
if ("runs" in step && commandRuns(step.runs, invocation, scripts))
|
|
67
11
|
return "reconciles";
|
|
@@ -70,14 +14,8 @@ function roleOf(step, invocation, scripts) {
|
|
|
70
14
|
export function reconcilerSteps(ciSources, ciSourceNames, invocation, packageJson) {
|
|
71
15
|
const scripts = packageJson.scripts ?? {};
|
|
72
16
|
return {
|
|
73
|
-
// THE WALK, of which every other reader on this axis takes its own projection (3F-3352) — the
|
|
74
|
-
// same parse, so the step this account names is the step discovery skipped.
|
|
75
17
|
steps: ciWorkflowSteps(ciSources).flatMap((step) => {
|
|
76
18
|
const role = roleOf(step, invocation, scripts);
|
|
77
|
-
// NAMED BY ITS IDENTITY WHERE ITS SOURCE HAS NO NAME. The recognition never depended on the
|
|
78
|
-
// name — a citation on this step is unsatisfiable whatever file it lives in — so a run given
|
|
79
|
-
// no name for a source must not go quiet about a step it set aside. It says which step, in
|
|
80
|
-
// the string GitHub itself displays, and only the qualification is missing.
|
|
81
19
|
return role === undefined
|
|
82
20
|
? []
|
|
83
21
|
: [{ step: qualifiedStepName(step, ciSourceNames) ?? step.identity, role }];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reconcilerSteps.js","sourceRoot":"","sources":["../../src/parse/reconcilerSteps.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"reconcilerSteps.js","sourceRoot":"","sources":["../../src/parse/reconcilerSteps.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAuB,MAAM,0BAA0B,CAAC;AAChF,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAQnD,MAAM,sBAAsB,GAAG,eAAe,CAAC;AAE/C,SAAS,qBAAqB,CAAC,IAAoB;IACjD,MAAM,OAAO,GAAG,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;IACrE,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAC3B,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,sBAAsB,CAAC,CACvE,CAAC;AACJ,CAAC;AAED,SAAS,MAAM,CACb,IAAoB,EACpB,UAAkB,EAClB,OAAyC;IAEzC,IAAI,MAAM,IAAI,IAAI,IAAI,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,CAAC;QAAE,OAAO,YAAY,CAAC;IACvF,OAAO,qBAAqB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;AAC7D,CAAC;AAED,MAAM,UAAU,eAAe,CAC7B,SAA4B,EAC5B,aAAgC,EAChC,UAAkB,EAClB,WAAiD;IAEjD,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,IAAI,EAAE,CAAC;IAC1C,OAAO;QACL,KAAK,EAAE,eAAe,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;YACjD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;YAC/C,OAAO,IAAI,KAAK,SAAS;gBACvB,CAAC,CAAC,EAAE;gBACJ,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,iBAAiB,CAAC,IAAI,EAAE,aAAa,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QAChF,CAAC,CAAC;QACF,YAAY,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,CAAC,KAAK,SAAS;KACxE,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { FitnessEvidenceObservation } from "../model.js";
|
|
2
|
+
import { type CiWorkflowStep, type PackageJsonScripts } from "./checkScriptsRunInCI.js";
|
|
3
|
+
import type { BehaviouralRunner } from "../domain/evidenceReconciliation.js";
|
|
4
|
+
import type { ScriptCitation } from "./fitnessCitations.js";
|
|
5
|
+
export declare function isCandidateStep(step: CiWorkflowStep, packageJson: PackageJsonScripts, runners: Readonly<Record<string, string | null>>, isExcludedFromDiscovery: (step: CiWorkflowStep) => boolean): boolean;
|
|
6
|
+
export declare function runsNamedRunner(step: CiWorkflowStep, packageJson: PackageJsonScripts, runners: Readonly<Record<string, string | null>>): boolean;
|
|
7
|
+
export declare function runningFitnessFunctions(ciSources: readonly string[], packageJson: PackageJsonScripts, runners: Readonly<Record<string, string | null>>, citedScn?: (script: string, citedByStep?: string) => ScriptCitation | null, isExcludedFromDiscovery?: (step: CiWorkflowStep) => boolean): FitnessEvidenceObservation[];
|
|
8
|
+
export declare function recognisedRunners(ciSources: readonly string[], packageJson: PackageJsonScripts, runners: Readonly<Record<string, string | null>>): BehaviouralRunner[];
|
|
9
|
+
//# sourceMappingURL=runningFitnessFunctions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runningFitnessFunctions.d.ts","sourceRoot":"","sources":["../../src/parse/runningFitnessFunctions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AAE9D,OAAO,EAGL,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACxB,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AAC7E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAkC5D,wBAAgB,eAAe,CAC7B,IAAI,EAAE,cAAc,EACpB,WAAW,EAAE,kBAAkB,EAC/B,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,EAChD,uBAAuB,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,OAAO,GACzD,OAAO,CAET;AAED,wBAAgB,eAAe,CAC7B,IAAI,EAAE,cAAc,EACpB,WAAW,EAAE,kBAAkB,EAC/B,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,GAC/C,OAAO,CAET;AAED,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,SAAS,MAAM,EAAE,EAC5B,WAAW,EAAE,kBAAkB,EAC/B,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,EAChD,QAAQ,GAAE,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,KAAK,cAAc,GAAG,IAAiB,EACtF,uBAAuB,GAAE,CAAC,IAAI,EAAE,cAAc,KAAK,OAAqB,GACvE,0BAA0B,EAAE,CAoB9B;AAED,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,SAAS,MAAM,EAAE,EAC5B,WAAW,EAAE,kBAAkB,EAC/B,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,GAC/C,iBAAiB,EAAE,CASrB"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { commandRuns } from "./commandRuns.js";
|
|
2
|
+
import { ciWorkflowSteps, commandInvokesScript, } from "./checkScriptsRunInCI.js";
|
|
3
|
+
const UP_TO_LAST_PIPE = /^.*(?<!\|)\|(?!\|)/;
|
|
4
|
+
function finalStages(command) {
|
|
5
|
+
return command
|
|
6
|
+
.replace(/\\\r?\n/g, " ")
|
|
7
|
+
.split(/\r?\n/)
|
|
8
|
+
.map((line) => line.replace(UP_TO_LAST_PIPE, ""))
|
|
9
|
+
.join("\n");
|
|
10
|
+
}
|
|
11
|
+
function namedRunnersAt(step, scripts, runners) {
|
|
12
|
+
if (!("runs" in step))
|
|
13
|
+
return [];
|
|
14
|
+
const command = finalStages(step.runs);
|
|
15
|
+
const unpiped = Object.fromEntries(Object.entries(scripts).map(([name, body]) => [name, finalStages(body)]));
|
|
16
|
+
return Object.entries(runners).filter((entry) => entry[1] !== null && commandRuns(command, entry[1], unpiped));
|
|
17
|
+
}
|
|
18
|
+
function handleOf(step, scripts) {
|
|
19
|
+
if (!("runs" in step))
|
|
20
|
+
return step.identity;
|
|
21
|
+
const invoked = Object.keys(scripts).filter((name) => commandInvokesScript(step.runs, name));
|
|
22
|
+
return invoked[0] ?? step.identity;
|
|
23
|
+
}
|
|
24
|
+
export function isCandidateStep(step, packageJson, runners, isExcludedFromDiscovery) {
|
|
25
|
+
return !isExcludedFromDiscovery(step) && !runsNamedRunner(step, packageJson, runners);
|
|
26
|
+
}
|
|
27
|
+
export function runsNamedRunner(step, packageJson, runners) {
|
|
28
|
+
return namedRunnersAt(step, packageJson.scripts ?? {}, runners).length > 0;
|
|
29
|
+
}
|
|
30
|
+
export function runningFitnessFunctions(ciSources, packageJson, runners, citedScn = () => null, isExcludedFromDiscovery = () => false) {
|
|
31
|
+
const scripts = packageJson.scripts ?? {};
|
|
32
|
+
const candidates = ciWorkflowSteps(ciSources).filter((step) => isCandidateStep(step, packageJson, runners, isExcludedFromDiscovery));
|
|
33
|
+
return candidates
|
|
34
|
+
.map((step) => {
|
|
35
|
+
const fitnessFunction = handleOf(step, scripts);
|
|
36
|
+
const citation = citedScn(fitnessFunction, step.id);
|
|
37
|
+
return {
|
|
38
|
+
qualityCheck: "fitness",
|
|
39
|
+
fitnessFunction,
|
|
40
|
+
exists: true,
|
|
41
|
+
enforcedOverRealSource: step.abortsJob,
|
|
42
|
+
...(citation !== null
|
|
43
|
+
? { scnId: step.id ?? citation.scnId }
|
|
44
|
+
: {}),
|
|
45
|
+
};
|
|
46
|
+
})
|
|
47
|
+
.sort((a, b) => a.fitnessFunction.localeCompare(b.fitnessFunction));
|
|
48
|
+
}
|
|
49
|
+
export function recognisedRunners(ciSources, packageJson, runners) {
|
|
50
|
+
const scripts = packageJson.scripts ?? {};
|
|
51
|
+
return ciWorkflowSteps(ciSources).flatMap((step) => namedRunnersAt(step, scripts, runners).map(([tier, runner]) => ({
|
|
52
|
+
tier,
|
|
53
|
+
runner,
|
|
54
|
+
step: step.identity,
|
|
55
|
+
})));
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=runningFitnessFunctions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runningFitnessFunctions.js","sourceRoot":"","sources":["../../src/parse/runningFitnessFunctions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ScenarioCodeError, ScenarioCodePopulation } from "../domain/scenarioCodeError.js";
|
|
2
|
+
export interface CorpusFile {
|
|
3
|
+
slug: string;
|
|
4
|
+
featureCode: string | null;
|
|
5
|
+
source: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function duplicateFeatureCodes(features: readonly CorpusFile[]): ScenarioCodeError[];
|
|
8
|
+
export declare function foreignScenarioCodes(features: readonly CorpusFile[]): ScenarioCodeError[];
|
|
9
|
+
export declare function scenarioCodePopulationOf(features: readonly CorpusFile[]): ScenarioCodePopulation;
|
|
10
|
+
export declare function scenarioCodeErrorsOf(features: readonly CorpusFile[]): ScenarioCodeError[];
|
|
11
|
+
//# sourceMappingURL=scenarioCodeErrors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scenarioCodeErrors.d.ts","sourceRoot":"","sources":["../../src/parse/scenarioCodeErrors.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AAIhG,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,SAAS,UAAU,EAAE,GAAG,iBAAiB,EAAE,CAW1F;AA6BD,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,SAAS,UAAU,EAAE,GAAG,iBAAiB,EAAE,CAoBzF;AAYD,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,SAAS,UAAU,EAAE,GAAG,sBAAsB,CAEhG;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,SAAS,UAAU,EAAE,GAAG,iBAAiB,EAAE,CAMzF"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { featureCodeOf } from "../domain/featureCode.js";
|
|
2
|
+
import { parseTaggedScenarios } from "./scenarios.js";
|
|
3
|
+
import { CORE_MESSAGES, CoreMessage } from "../domain/messages.js";
|
|
4
|
+
export function duplicateFeatureCodes(features) {
|
|
5
|
+
const faults = [];
|
|
6
|
+
for (const [code, files] of headerFilesByCode(features)) {
|
|
7
|
+
if (files.length < 2)
|
|
8
|
+
continue;
|
|
9
|
+
faults.push({
|
|
10
|
+
kind: "duplicate-feature-code",
|
|
11
|
+
files,
|
|
12
|
+
message: CORE_MESSAGES[CoreMessage.DuplicateFeatureCode](code, files.length, files.join(", ")),
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
return faults;
|
|
16
|
+
}
|
|
17
|
+
function headerFilesByCode(features) {
|
|
18
|
+
const filesByCode = new Map();
|
|
19
|
+
for (const file of features) {
|
|
20
|
+
if (file.featureCode === null)
|
|
21
|
+
continue;
|
|
22
|
+
filesByCode.set(file.featureCode, [...(filesByCode.get(file.featureCode) ?? []), `${file.slug}.feature`]);
|
|
23
|
+
}
|
|
24
|
+
return filesByCode;
|
|
25
|
+
}
|
|
26
|
+
function foreignMessage(file, scnId, named, carriers) {
|
|
27
|
+
const fileName = `${file.slug}.feature`;
|
|
28
|
+
if (carriers.length === 1) {
|
|
29
|
+
return CORE_MESSAGES[CoreMessage.ForeignScnCodeOneCarrier](fileName, file.featureCode, scnId, named, carriers[0]);
|
|
30
|
+
}
|
|
31
|
+
if (carriers.length > 1) {
|
|
32
|
+
return CORE_MESSAGES[CoreMessage.ForeignScnCodeManyCarriers](fileName, file.featureCode, scnId, named, carriers.length, carriers.join(", "));
|
|
33
|
+
}
|
|
34
|
+
return CORE_MESSAGES[CoreMessage.ForeignScnCodeNoCarrier](fileName, file.featureCode, scnId, named);
|
|
35
|
+
}
|
|
36
|
+
export function foreignScenarioCodes(features) {
|
|
37
|
+
const carriersByCode = headerFilesByCode(features);
|
|
38
|
+
const faults = [];
|
|
39
|
+
for (const file of features) {
|
|
40
|
+
if (file.featureCode === null)
|
|
41
|
+
continue;
|
|
42
|
+
const coded = { ...file, featureCode: file.featureCode };
|
|
43
|
+
for (const scenario of parseTaggedScenarios(file.source)) {
|
|
44
|
+
const named = featureCodeOf(scenario.scnId);
|
|
45
|
+
if (named === null || named === file.featureCode)
|
|
46
|
+
continue;
|
|
47
|
+
const carriers = carriersByCode.get(named) ?? [];
|
|
48
|
+
faults.push({
|
|
49
|
+
kind: "foreign-scn-code",
|
|
50
|
+
files: [`${file.slug}.feature`],
|
|
51
|
+
namedFeatureCode: named,
|
|
52
|
+
namedFeatureFiles: carriers,
|
|
53
|
+
message: foreignMessage(coded, scenario.scnId, named, carriers),
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return faults;
|
|
58
|
+
}
|
|
59
|
+
function noFeatureCodeFiles(features) {
|
|
60
|
+
return features
|
|
61
|
+
.filter((file) => file.featureCode === null && parseTaggedScenarios(file.source).length > 0)
|
|
62
|
+
.map((file) => ({
|
|
63
|
+
kind: "no-feature-code",
|
|
64
|
+
files: [`${file.slug}.feature`],
|
|
65
|
+
message: CORE_MESSAGES[CoreMessage.NoFeatureCode](`${file.slug}.feature`),
|
|
66
|
+
}));
|
|
67
|
+
}
|
|
68
|
+
export function scenarioCodePopulationOf(features) {
|
|
69
|
+
return { featureFiles: features.length, featureCodes: headerFilesByCode(features).size };
|
|
70
|
+
}
|
|
71
|
+
export function scenarioCodeErrorsOf(features) {
|
|
72
|
+
return [
|
|
73
|
+
...duplicateFeatureCodes(features),
|
|
74
|
+
...foreignScenarioCodes(features),
|
|
75
|
+
...noFeatureCodeFiles(features),
|
|
76
|
+
];
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=scenarioCodeErrors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scenarioCodeErrors.js","sourceRoot":"","sources":["../../src/parse/scenarioCodeErrors.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,239 +1,14 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The SCENARIO reader — parse spec-controller's own `features/**\/*.feature` source
|
|
3
|
-
* into evidence obligations: per scenario, `{ scnId, evidenceObligations }`, with
|
|
4
|
-
* each (kind, level) drawn from the scenario's evidence tags (@unit → runtime/unit,
|
|
5
|
-
* @integration → runtime/integration, @e2e → runtime/e2e, @performance →
|
|
6
|
-
* runtime/performance — the evidence-obligation reading).
|
|
7
|
-
*
|
|
8
|
-
* One of the three separated inputs to the reconciler (obligations / observations /
|
|
9
|
-
* static checks) — the embryonic obligation-side adapter, deliberately not a registry (v1).
|
|
10
|
-
*
|
|
11
|
-
* Approach: scan TAG LINES (a line whose first non-blank char is `@` and whose
|
|
12
|
-
* every whitespace-separated token is a tag) for an @SCN-<FFF>-<NNN> id and any
|
|
13
|
-
* co-located evidence-level tags. A scenario's @SCN id and its level tags sit on
|
|
14
|
-
* the same accumulated tag block immediately above the Scenario keyword, so a tag
|
|
15
|
-
* line carrying an @SCN id contributes that scenario's evidenceObligations from the level
|
|
16
|
-
* tags found across the contiguous tag block.
|
|
17
|
-
*
|
|
18
|
-
* The `lint` quality-check is raised by a scenario's REGISTERED bare check tag, STEPS OR NONE
|
|
19
|
-
* (`fitnessObligationsOf`, @SCN-LNT-006): the tag says which axis a scenario is on and the steps say
|
|
20
|
-
* nothing about it (3F-3115). The retired `@lint=<guard>` form — where the scenario
|
|
21
|
-
* named a runnable npm script and the run was matched back to it BY NAME — raises nothing
|
|
22
|
-
* (@SCN-LNT-007): it supplies no citation, so anything it raised could never be credited under
|
|
23
|
-
* the one posting rule and would read `missing` for ever. The form is inert in the READER, which
|
|
24
|
-
* is what makes it retired rather than merely unused.
|
|
25
|
-
*
|
|
26
|
-
* Parent: @SCN-LDG-001.
|
|
27
|
-
*/
|
|
28
1
|
import type { Scenario, QualityCheck } from "../model.js";
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Recognise a `<quality-check>pending` tag (evidence-manifesto §11B) — return its deferred
|
|
32
|
-
* quality-check, or `null` when the bare tag is not one of the five recognised `<qc>pending`
|
|
33
|
-
* (a bare tier tag, an unknown `<x>pending`, or bare `pending`). The pure per-tag helper
|
|
34
|
-
* `parseScenarios` uses to derive a pending obligation.
|
|
35
|
-
*/
|
|
2
|
+
export declare const SCN_CODE: RegExp;
|
|
36
3
|
export declare function pendingQualityCheck(tag: string): QualityCheck | null;
|
|
37
|
-
/**
|
|
38
|
-
* Every recognised `<quality-check>pending` spelling, derived from the map above rather than
|
|
39
|
-
* listed again (@SCN-STG-002, 3F-3302).
|
|
40
|
-
*
|
|
41
|
-
* WHY A LIST AND NOT JUST THE PREDICATE. `pendingQualityCheck` answers "is THIS tag one", which
|
|
42
|
-
* is all an obligation needs. The tag-grammar rule needs the other direction too — the words to
|
|
43
|
-
* measure an unrecognised tag AGAINST, so it can name the tier a typo resembles — and a list
|
|
44
|
-
* written out over there would agree with this map by diligence and then drift the first time a
|
|
45
|
-
* quality-check is added.
|
|
46
|
-
*/
|
|
47
|
-
export declare const PENDING_QUALITY_CHECK_TAGS: readonly string[];
|
|
48
|
-
/**
|
|
49
|
-
* The bare tags that name a RUNTIME evidence tier, derived from the map above (@SCN-STG-002,
|
|
50
|
-
* 3F-3302). Exported for the same reason as the pending list beside it, and kept beneath the map
|
|
51
|
-
* it reads so the two can never be edited apart.
|
|
52
|
-
*/
|
|
53
|
-
export declare const RUNTIME_QUALITY_CHECK_TAGS: readonly string[];
|
|
54
|
-
/**
|
|
55
|
-
* Count every raw `@SCN-FFF-NNN` occurrence across the WHOLE source — including the
|
|
56
|
-
* non-tag-line context (prose, comments, step text) the tag-line `parseScenarios`
|
|
57
|
-
* deliberately ignores. A sibling read over the same source; `parseScenarios` is
|
|
58
|
-
* unchanged. Each scenario contributes exactly one tag-line occurrence, so
|
|
59
|
-
* the delta against `parseScenarios(...).length` is precisely the ids seen in non-tag
|
|
60
|
-
* context.
|
|
61
|
-
*/
|
|
62
4
|
export declare function countScnOccurrences(source: string): number;
|
|
63
|
-
/**
|
|
64
|
-
* The PROSE-ONLY @SCN codes (@SCN-RPT-015) — codes that appear in non-tag
|
|
65
|
-
* context (prose / comments / step text) but are NEVER an @SCN tag ANYWHERE in the
|
|
66
|
-
* corpus: dangling references. A CROSS-CORPUS set difference `proseCodes − tagCodes`
|
|
67
|
-
* over ALL sources (unique, sorted): per source each line is inspected — a tag line
|
|
68
|
-
* contributes its @SCN tokens to the TAG set; any other line contributes its @SCN
|
|
69
|
-
* matches (the leading `@` stripped) to the PROSE set. The union across files is
|
|
70
|
-
* load-bearing: a code tagged in one file but mentioned in prose in another is NOT
|
|
71
|
-
* prose-only. Distinct from `countScnOccurrences`'s raw count (occurrences, not unique
|
|
72
|
-
* dangling codes). The bare code (e.g. `SCN-FOO-001`) is its own locator.
|
|
73
|
-
*/
|
|
74
|
-
export declare function proseOnlyCodes(sources: string[]): string[];
|
|
75
|
-
/**
|
|
76
|
-
* Parse the UNTAGGED scenarios — Gherkin scenario headers whose preceding contiguous
|
|
77
|
-
* tag block carries no `@SCN` id (@SCN-RPT-014). Mirrors `parseScenarios`'s
|
|
78
|
-
* tag-block accumulation: a tag line accumulates the block; any non-tag line closes it.
|
|
79
|
-
* At each scenario header, the just-accumulated block is checked for an `@SCN` — if it
|
|
80
|
-
* has none, the scenario is untagged (returns its name). The obligation-side counterpart
|
|
81
|
-
* to the evidenceObservations aggregate's anomaly terms: a scenario with no evidence anchor.
|
|
82
|
-
*/
|
|
83
5
|
export declare function parseUntaggedScenarios(source: string): string[];
|
|
84
|
-
/**
|
|
85
|
-
* The one word a CONVERTED check's scenario carries — the axis, and nothing about the subject.
|
|
86
|
-
*
|
|
87
|
-
* It is a literal rather than a registered tag because it names no characteristic: `checkTags` is
|
|
88
|
-
* the answer to "which words are checks here", and this word is the answer to "which axis is this
|
|
89
|
-
* scenario on", which is the same question `unit` and `integration` answer for the other axis. A
|
|
90
|
-
* target does not get to spell it differently for the reason nobody spells `@unit` differently.
|
|
91
|
-
*/
|
|
92
6
|
export declare const FITNESS_AXIS_TAG = "fitness";
|
|
93
|
-
/**
|
|
94
|
-
* The scenarios ON the fitness axis that no configured row NAMES (@SCN-LNT-020) — a corpus that has
|
|
95
|
-
* half-converted a check: the tag moved and the row was never written.
|
|
96
|
-
*
|
|
97
|
-
* IT RAISES NOTHING AND THAT IS NOT NEGOTIABLE. Such a scenario has said which axis it is on and
|
|
98
|
-
* then said nothing about what it asserts; there is no characteristic to raise an obligation FOR,
|
|
99
|
-
* and reaching for the nearest word is the near-match courtesy the portfolio roster already
|
|
100
|
-
* refuses. So `convertedFitnessObligationsOf` above answers the empty list, and this reads the same
|
|
101
|
-
* two facts — the axis tag, and the row's absence — to say WHO.
|
|
102
|
-
*
|
|
103
|
-
* THE RUN ALREADY REDS ON IT, through no rule of this function's. A converted check's scenario
|
|
104
|
-
* carries the axis tag and its `@SCN` and nothing else, so a scenario no row names reconciles to
|
|
105
|
-
* zero rows on BOTH sides and is out of balance through the degenerate `both-missing` item — canon's
|
|
106
|
-
* row for exactly this profile (Scenario Exists, Evidence Obligation None, Evidence Observation
|
|
107
|
-
* None). No outcome is minted here, and none is needed.
|
|
108
|
-
*
|
|
109
|
-
* WHAT IS ADDED IS THE SENTENCE. That degenerate item cannot say WHY: its own gloss is about a
|
|
110
|
-
* scenario carrying no `@SCN`, and this one carries one. So the run NAMES these, count and id, where
|
|
111
|
-
* it already names the other corpus-shape faults — facts only, no prescribed cure, and the reader
|
|
112
|
-
* is left with the one remedy there is, which is to write the row.
|
|
113
|
-
*
|
|
114
|
-
* IT READS THE WALK IT IS HANDED rather than taking a source of its own, and it reads the same
|
|
115
|
-
* `FITNESS_AXIS_TAG` and the same registry the obligation rule reads. A second walk would be free to
|
|
116
|
-
* disagree about which scenario it is looking at, and a corpus naming one scenario while the rule
|
|
117
|
-
* raised nothing for another is precisely the disagreement `parseTaggedScenarios` was extracted to
|
|
118
|
-
* foreclose.
|
|
119
|
-
*
|
|
120
|
-
* NAMED ONCE however many of a scenario's effective tags name the axis (@SCN-LDG-020) — naming it
|
|
121
|
-
* twice would put one remedy on the report twice and make the count say there are two
|
|
122
|
-
* half-converted checks where there is one.
|
|
123
|
-
*/
|
|
124
|
-
export declare function unconfiguredFitnessScenarios(scenarios: readonly TaggedScenario[], fitnessChecks: FitnessCheckIndex): string[];
|
|
125
|
-
/**
|
|
126
|
-
* THE CONFIGURED ROWS THE CORPUS CARRIES NO SCENARIO FOR (3F-3472, @SCN-LNT-027) — the mirror of
|
|
127
|
-
* `unconfiguredFitnessScenarios` directly above, in MANIFEST order.
|
|
128
|
-
*
|
|
129
|
-
* THE RUN DOES NOT ALREADY RED ON IT, WHICH IS THE WHOLE DIFFERENCE BETWEEN THE TWO. Its mirror
|
|
130
|
-
* adds only a sentence, because a scenario no row names already reconciles to zero rows on both
|
|
131
|
-
* sides and is out of balance through the degenerate item. A row no scenario names raised NOTHING:
|
|
132
|
-
* the obligations travel with the scenarios, so a row with no scenario contributed a characteristic
|
|
133
|
-
* nobody asked for and the run read balanced over a check that was declared and never specified.
|
|
134
|
-
* `double-entry-manifesto.md` names that shape exactly — a ledger catches a credit that never
|
|
135
|
-
* arrived and is blind to a debit that was never raised.
|
|
136
|
-
*
|
|
137
|
-
* IT READS THE WALK IT IS HANDED, for its mirror's reason: a second walk would be free to disagree
|
|
138
|
-
* about which scenarios the corpus holds, and a row raised against a corpus the obligations were
|
|
139
|
-
* not taken from is the phantom-row fault (@SCN-LNT-009) reached from the manifest side.
|
|
140
|
-
*
|
|
141
|
-
* EVERY `@SCN`-CARRYING SCENARIO COUNTS, NOT THE `@fitness` ONES ALONE. The claim is that the
|
|
142
|
-
* corpus carries no scenario for the row — so a scenario carrying the row's code and saying nothing
|
|
143
|
-
* about the fitness axis is still a scenario somebody wrote under that code, and minting a debit
|
|
144
|
-
* beside it would report a check nobody has specified where one has been started.
|
|
145
|
-
*/
|
|
146
|
-
export declare function unspecifiedFitnessRows(scenarios: readonly TaggedScenario[], fitnessChecks: FitnessCheckIndex): UnspecifiedFitnessRow[];
|
|
147
|
-
/**
|
|
148
|
-
* One `@SCN`-carrying scenario as the corpus READS it, before any obligation rule is applied:
|
|
149
|
-
* its id and its EFFECTIVE tag set (its own tags, then everything it inherits from its `Rule:`
|
|
150
|
-
* and `Feature:`).
|
|
151
|
-
*
|
|
152
|
-
* Extracted so a second corpus reader cannot grow a second tag-inheritance walk. That walk is
|
|
153
|
-
* where both of `parseScenarios`'s historical false-greens lived — the UNDER-READ (a hoisted
|
|
154
|
-
* tier tag invisible, so its obligation was never raised) and the OVER-READ (a tag block above a
|
|
155
|
-
* `Rule:` emitted as a scenario). A reader that re-derived "which tags does this scenario carry"
|
|
156
|
-
* would be free to reproduce either one alone, silently, exactly as the retired hand-rolled scan
|
|
157
|
-
* did beside cucumber's own parse.
|
|
158
|
-
*/
|
|
159
7
|
export interface TaggedScenario {
|
|
160
|
-
/** The bare scenario id, e.g. `SCN-LDG-001` (no leading @). */
|
|
161
8
|
scnId: string;
|
|
162
|
-
/** The scenario's OWN tags first, then its inherited ones — bare, no leading @. */
|
|
163
9
|
tags: readonly string[];
|
|
164
|
-
|
|
165
|
-
* The scenario's EXTENT in the source — 1-based and INCLUSIVE, so `lines.slice(startLine - 1,
|
|
166
|
-
* endLine)` is exactly this scenario's text (@SCN-SSM-010, 3F-3044). It rides on this walk for the
|
|
167
|
-
* reason the walk was extracted at all, sharpened by what an extent is FOR: a second pass over the
|
|
168
|
-
* same file would be free to disagree with this one about which scenario it is looking at, and the
|
|
169
|
-
* caller that wants an extent is asking which scenario some text belongs to — so a disagreeing
|
|
170
|
-
* second pass is precisely how that question gets the neighbour's answer.
|
|
171
|
-
*
|
|
172
|
-
* `startLine` is the lesser of the scenario's first OWN tag line and its keyword line — an
|
|
173
|
-
* inherited `Rule:`/`Feature:` tag is not part of this scenario's text. `endLine` is the line
|
|
174
|
-
* before the next block starts (a scenario, a `Rule:` — or its first tag line — a `Background:`,
|
|
175
|
-
* or EOF), TRIMMED BACK over trailing blank and comment lines.
|
|
176
|
-
*
|
|
177
|
-
* The trim is load-bearing rather than tidiness: without it a blank line or a comment sitting
|
|
178
|
-
* between two scenarios belongs to the preceding one, and an edit there reads as a change to a
|
|
179
|
-
* scenario it is not part of — neighbour-inheritance rebuilt at a smaller scale, which is the one
|
|
180
|
-
* outcome @SCN-SSM-010 rules out.
|
|
181
|
-
*
|
|
182
|
-
* Derived from AST locations rather than from step positions, so docstrings, data tables and
|
|
183
|
-
* `Examples:` blocks are covered with no special case.
|
|
184
|
-
*/
|
|
185
|
-
startLine: number;
|
|
186
|
-
/** The last line of this scenario's text — see `startLine`. 1-based, inclusive. */
|
|
187
|
-
endLine: number;
|
|
10
|
+
name: string;
|
|
188
11
|
}
|
|
189
|
-
/**
|
|
190
|
-
* Read every `@SCN`-carrying scenario with its EFFECTIVE tags — the corpus walk `parseScenarios`
|
|
191
|
-
* is built on, and the same walk any other whole-corpus tag question is answered from.
|
|
192
|
-
*
|
|
193
|
-
* The obligation rule is deliberately NOT applied here: what a scenario TAGS and what it OWES are
|
|
194
|
-
* different questions, and the second is `obligationsFromTags`'. Keeping them apart is what lets
|
|
195
|
-
* the citation seam ask the first without inheriting a reading of the second.
|
|
196
|
-
*
|
|
197
|
-
* WHY THE WALK IS THE AST'S AND NOT A SCAN'S. This was a hand-rolled TAG-LINE SCAN that saw only
|
|
198
|
-
* the contiguous tag block directly above a `Scenario:`. Gherkin does not work that way — a
|
|
199
|
-
* scenario INHERITS the tags of its `Feature:` and of any enclosing `Rule:`. Two bugs followed,
|
|
200
|
-
* and both were false-greens:
|
|
201
|
-
*
|
|
202
|
-
* UNDER-READ. An evidence tier hoisted to the Feature/Rule line — idiomatic, valid Gherkin,
|
|
203
|
-
* exactly what an author does with a tier shared by every scenario beneath — was INVISIBLE. The
|
|
204
|
-
* obligation was never RAISED, so its missing evidence could never reconcile `missing`, and the
|
|
205
|
-
* run read BALANCED (exit 0) while cucumber named a tier nothing proved. Unlike the corrupt-
|
|
206
|
-
* file false-green (3F-1767), this one fires on WELL-WRITTEN files — which makes it likelier.
|
|
207
|
-
*
|
|
208
|
-
* OVER-READ. Any non-tag line flushed the accumulated block, so a tag block above a `Rule:` was
|
|
209
|
-
* emitted AS IF it were a scenario. The corpus did not merely miss scenarios — it INVENTED them.
|
|
210
|
-
*
|
|
211
|
-
* EVERY tag inherits, `@SCN` included: parity with cucumber is the goal, and excluding one would
|
|
212
|
-
* invent a rule cucumber does not have. A hoisted `@SCN` therefore gives every scenario beneath it
|
|
213
|
-
* the same id — a corpus-authoring fault, but a VISIBLE one (whether it should red is a deferred
|
|
214
|
-
* policy question, 3F-1774's sibling).
|
|
215
|
-
*
|
|
216
|
-
* An UNPARSEABLE source THROWS, from `parseFeatureDocument` — it never yields an empty corpus, for
|
|
217
|
-
* the reason recorded there.
|
|
218
|
-
*/
|
|
219
12
|
export declare function parseTaggedScenarios(source: string): TaggedScenario[];
|
|
220
|
-
|
|
221
|
-
* Parse the SCENARIO CORPUS — the ledger's DEBIT side — from the REAL Gherkin AST (@SCN-LDG-020,
|
|
222
|
-
* 3F-1775), the same parser cucumber uses. So the scenarios spec-controller reconciles carry
|
|
223
|
-
* EXACTLY the tags cucumber gives them: one reading of the file, not two.
|
|
224
|
-
*
|
|
225
|
-
* The corpus walk is `parseTaggedScenarios`'; this is the OBLIGATION rule applied over it. An
|
|
226
|
-
* unparseable source still THROWS from the walk rather than yielding an empty corpus.
|
|
227
|
-
*
|
|
228
|
-
* `checkTags` — the registry's bare check tags (@SCN-LNT-006) — is ADDITIVE and defaults to none, so
|
|
229
|
-
* `parseScenarios` keeps its place on the v1 barrel and every existing caller
|
|
230
|
-
* reads exactly the corpus it read before. A target that has registered nothing raises no fitness
|
|
231
|
-
* obligations, which is what lets the bare-tag reading land ahead of the corpus sweep that uses it.
|
|
232
|
-
*
|
|
233
|
-
* `fitnessChecks` — the target's CONFIGURED ROWS (@SCN-LNT-018) — is trailing and optional for the
|
|
234
|
-
* same reason, and carries the scenario's own `scnId` into the obligation rule: a converted check's
|
|
235
|
-
* characteristic is keyed by the row it is owed on, so the rule cannot be applied to a tag set
|
|
236
|
-
* alone. Empty by default, so a target that has converted nothing raises nothing on this route.
|
|
237
|
-
*/
|
|
238
|
-
export declare function parseScenarios(source: string, deferralTags?: readonly string[], checkTags?: readonly string[], fitnessChecks?: FitnessCheckIndex): Scenario[];
|
|
13
|
+
export declare function parseScenarios(source: string, deferralTags?: readonly string[]): Scenario[];
|
|
239
14
|
//# sourceMappingURL=scenarios.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scenarios.d.ts","sourceRoot":"","sources":["../../src/parse/scenarios.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"scenarios.d.ts","sourceRoot":"","sources":["../../src/parse/scenarios.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAsB,YAAY,EAAuB,MAAM,aAAa,CAAC;AAEnG,eAAO,MAAM,QAAQ,QAAmC,CAAC;AAUzD,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAEpE;AAiBD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAE1D;AAKD,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAiB/D;AAED,eAAO,MAAM,gBAAgB,YAAY,CAAC;AAuC1C,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;CACd;AAYD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,EAAE,CA4BrE;AAED,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EACd,YAAY,GAAE,SAAS,MAAM,EAAO,GACnC,QAAQ,EAAE,CAKZ"}
|