@nielspeter/eess-crossvalidate 0.4.0 → 0.5.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/README.md +24 -1
- package/dist/files.d.ts.map +1 -1
- package/dist/files.js +3 -27
- package/dist/files.js.map +1 -1
- package/dist/gherkin-ts.d.ts +6 -5
- package/dist/gherkin-ts.d.ts.map +1 -1
- package/dist/gherkin-ts.js +43 -41
- package/dist/gherkin-ts.js.map +1 -1
- package/dist/md-gherkin.d.ts +5 -3
- package/dist/md-gherkin.d.ts.map +1 -1
- package/dist/md-gherkin.js +16 -21
- package/dist/md-gherkin.js.map +1 -1
- package/dist/md-mermaid-er.d.ts +5 -3
- package/dist/md-mermaid-er.d.ts.map +1 -1
- package/dist/md-mermaid-er.js +13 -17
- package/dist/md-mermaid-er.js.map +1 -1
- package/dist/md-mermaid.d.ts +41 -6
- package/dist/md-mermaid.d.ts.map +1 -1
- package/dist/md-mermaid.js +147 -18
- package/dist/md-mermaid.js.map +1 -1
- package/dist/md-ts.d.ts.map +1 -1
- package/dist/md-ts.js.map +1 -1
- package/dist/mermaid-ts.d.ts.map +1 -1
- package/dist/mermaid-ts.js +3 -9
- package/dist/mermaid-ts.js.map +1 -1
- package/dist/shared.d.ts +61 -0
- package/dist/shared.d.ts.map +1 -0
- package/dist/shared.js +63 -0
- package/dist/shared.js.map +1 -0
- package/package.json +7 -6
package/README.md
CHANGED
|
@@ -113,13 +113,36 @@ the citing test's own `file`/`line`.
|
|
|
113
113
|
## Markdown ↔ Mermaid
|
|
114
114
|
|
|
115
115
|
```typescript
|
|
116
|
-
import {
|
|
116
|
+
import {
|
|
117
|
+
embeddedDiagramsMatchCode,
|
|
118
|
+
embeddedDiagramStats,
|
|
119
|
+
} from '@nielspeter/eess-crossvalidate/md-mermaid'
|
|
117
120
|
```
|
|
118
121
|
|
|
119
122
|
A ```mermaid fence embedded in a Markdown page must match the code it claims to
|
|
120
123
|
describe — a diagram that drifts from the source is a document that lies while
|
|
121
124
|
looking authoritative.
|
|
122
125
|
|
|
126
|
+
Only **class diagrams** are compared. A fence declaring another kind
|
|
127
|
+
(`sequenceDiagram`, `flowchart`, `gantt`, …) is skipped as a different artifact,
|
|
128
|
+
not treated as a broken class diagram; a fence whose kind is unrecognised is
|
|
129
|
+
still handed to the parser, so an unknown diagram costs a loud finding rather
|
|
130
|
+
than silent coverage loss. `embeddedDiagramStats` reports what was compared —
|
|
131
|
+
`documents`, `diagrams`, and the `skipped` count — so a pass is evidence rather
|
|
132
|
+
than a default:
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
const docs = corpus({ roots: ['docs/architecture.md'] })
|
|
136
|
+
embeddedDiagramsMatchCode(docs, project('tsconfig.json'), { completeness: 'both' })
|
|
137
|
+
|
|
138
|
+
const stats = embeddedDiagramStats(docs)
|
|
139
|
+
if (stats.diagrams === 0) throw new Error('selected zero class diagrams — green-but-empty')
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
`diagrams` counts fences **selected**, not classes compared — a fence that turns
|
|
143
|
+
out not to parse is selected and then reported. Pair the guard with
|
|
144
|
+
`completeness: 'both'` if you also want an emptied diagram to fail.
|
|
145
|
+
|
|
123
146
|
## Markdown ↔ Mermaid ER
|
|
124
147
|
|
|
125
148
|
```typescript
|
package/dist/files.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../src/files.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAG9D,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAE9D;;;;GAIG;AACH,MAAM,WAAW,SAAS;IACxB,yEAAyE;IACzE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,mEAAmE;IACnE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACzB;AAED,6BAA6B;AAC7B,MAAM,WAAW,YAAY;IAC3B,0EAA0E;IAC1E,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAAA;IACzC,mEAAmE;IACnE,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;IACrB,8EAA8E;IAC9E,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACnC,2DAA2D;IAC3D,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,kEAAkE;IAClE,QAAQ,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,WAAW,CAAA;CACpD;
|
|
1
|
+
{"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../src/files.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAG9D,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAE9D;;;;GAIG;AACH,MAAM,WAAW,SAAS;IACxB,yEAAyE;IACzE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,mEAAmE;IACnE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACzB;AAED,6BAA6B;AAC7B,MAAM,WAAW,YAAY;IAC3B,0EAA0E;IAC1E,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAAA;IACzC,mEAAmE;IACnE,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;IACrB,8EAA8E;IAC9E,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACnC,2DAA2D;IAC3D,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,kEAAkE;IAClE,QAAQ,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,WAAW,CAAA;CACpD;AAaD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,KAAK,CAAC,IAAI,EAAE,YAAY,GAAG,SAAS,CAAC,SAAS,CAAC,CAgB9D"}
|
package/dist/files.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { join
|
|
1
|
+
import { walkFiles } from '@nielspeter/eess/internal';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
3
|
import picomatch from 'picomatch';
|
|
4
4
|
// Directories never walked — deps, build output, VCS. Mirrors the corpus walk.
|
|
5
5
|
const BUILTIN_IGNORE_DIRS = new Set([
|
|
@@ -11,30 +11,6 @@ const BUILTIN_IGNORE_DIRS = new Set([
|
|
|
11
11
|
'.nuxt',
|
|
12
12
|
'.vercel',
|
|
13
13
|
]);
|
|
14
|
-
function toPosix(p) {
|
|
15
|
-
return sep === '/' ? p : p.split(sep).join('/');
|
|
16
|
-
}
|
|
17
|
-
function walk(dir, root, acc) {
|
|
18
|
-
let entries;
|
|
19
|
-
try {
|
|
20
|
-
entries = readdirSync(dir, { withFileTypes: true });
|
|
21
|
-
}
|
|
22
|
-
catch (err) {
|
|
23
|
-
void err; // unreadable dir (permissions, dangling symlink) — deliberately skipped
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
for (const e of entries) {
|
|
27
|
-
const abs = join(dir, e.name);
|
|
28
|
-
if (e.isDirectory()) {
|
|
29
|
-
if (BUILTIN_IGNORE_DIRS.has(e.name))
|
|
30
|
-
continue;
|
|
31
|
-
walk(abs, root, acc);
|
|
32
|
-
}
|
|
33
|
-
else if (e.isFile()) {
|
|
34
|
-
acc.push(toPosix(relative(root, abs)));
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
14
|
/**
|
|
39
15
|
* Turn a set of files into a `Selection` — the recurring "the code side is a
|
|
40
16
|
* set of files" case (an ADR index binds to `adr/*.md`, a manifest binds to
|
|
@@ -55,7 +31,7 @@ function walk(dir, root, acc) {
|
|
|
55
31
|
export function files(opts) {
|
|
56
32
|
const root = opts.cwd ?? process.cwd();
|
|
57
33
|
const all = [];
|
|
58
|
-
|
|
34
|
+
all.push(...walkFiles(root, root, BUILTIN_IGNORE_DIRS));
|
|
59
35
|
const globs = typeof opts.glob === 'string' ? [opts.glob] : [...opts.glob];
|
|
60
36
|
const matchesGlob = picomatch(globs);
|
|
61
37
|
const matchesIgnore = opts.ignore && opts.ignore.length > 0 ? picomatch([...opts.ignore]) : () => false;
|
package/dist/files.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"files.js","sourceRoot":"","sources":["../src/files.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"files.js","sourceRoot":"","sources":["../src/files.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAA;AACrD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,SAAS,MAAM,WAAW,CAAA;AAgCjC,+EAA+E;AAC/E,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC;IAClC,cAAc;IACd,MAAM;IACN,MAAM;IACN,UAAU;IACV,SAAS;IACT,OAAO;IACP,SAAS;CACV,CAAC,CAAA;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,KAAK,CAAC,IAAkB;IACtC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAA;IACtC,MAAM,GAAG,GAAa,EAAE,CAAA;IACxB,GAAG,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,mBAAmB,CAAC,CAAC,CAAA;IAEvD,MAAM,KAAK,GAAG,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAA;IAC1E,MAAM,WAAW,GAAG,SAAS,CAAC,KAAK,CAAC,CAAA;IACpC,MAAM,aAAa,GACjB,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,KAAK,CAAA;IAEnF,MAAM,QAAQ,GAAgB,GAAG;SAC9B,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;SACxD,IAAI,EAAE;SACN,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAA;IAE1D,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAA;AACjE,CAAC"}
|
package/dist/gherkin-ts.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type PresetReportOptions, type CollectResult } from '@nielspeter/eess';
|
|
2
2
|
import { type ArchProject } from '@nielspeter/eess-ts';
|
|
3
3
|
import type { FeatureSet, GherkinScenario } from '@nielspeter/eess-gherkin';
|
|
4
|
-
export { finishPreset } from '@nielspeter/eess';
|
|
4
|
+
export { finishPreset, collectResult } from '@nielspeter/eess';
|
|
5
|
+
export type { CollectResult } from '@nielspeter/eess';
|
|
5
6
|
export type { ArchViolation, PresetReportOptions } from '@nielspeter/eess';
|
|
6
7
|
/**
|
|
7
8
|
* Custom citation extractor — receives one `it('…')` title and returns the
|
|
@@ -58,7 +59,7 @@ declare function defaultExtract(itTitle: string): ExtractedTestCitation | undefi
|
|
|
58
59
|
* Resolves a citation; it does NOT claim the test exercises the scenario's
|
|
59
60
|
* steps — that is Tier 2, still open (plan 0079).
|
|
60
61
|
*/
|
|
61
|
-
export declare function scenarioTestsResolve(project: ArchProject, set: FeatureSet, options?: ScenarioTestsResolveOptions):
|
|
62
|
+
export declare function scenarioTestsResolve(project: ArchProject, set: FeatureSet, options?: ScenarioTestsResolveOptions): CollectResult;
|
|
62
63
|
/**
|
|
63
64
|
* Every test citation, keyed by the scenario it cites (`relPath title`) —
|
|
64
65
|
* exported (plan 0145) so a consumer can report where a citation lives, not
|
|
@@ -83,7 +84,7 @@ export declare function citedScenarioSites(project: ArchProject, set: FeatureSet
|
|
|
83
84
|
* Coverage means "a test cites this scenario", not "a test exercises its steps"
|
|
84
85
|
* (Tier 2, still open — plan 0079).
|
|
85
86
|
*/
|
|
86
|
-
export declare function scenariosCovered(project: ArchProject, set: FeatureSet, options?: ScenariosCoveredOptions):
|
|
87
|
+
export declare function scenariosCovered(project: ArchProject, set: FeatureSet, options?: ScenariosCoveredOptions): CollectResult;
|
|
87
88
|
export interface ScenarioExemptionsCurrentOptions extends PresetReportOptions {
|
|
88
89
|
/**
|
|
89
90
|
* Which scenarios are currently exempt from the coverage requirement.
|
|
@@ -116,7 +117,7 @@ export interface ScenarioExemptionsCurrentOptions extends PresetReportOptions {
|
|
|
116
117
|
* who wants a skipped-placeholder citation to NOT trigger staleness narrows
|
|
117
118
|
* `isExempt` to exclude it (or tags it `@wip @tracked` and narrows on that).
|
|
118
119
|
*/
|
|
119
|
-
export declare function scenarioExemptionsCurrent(project: ArchProject, set: FeatureSet, options: ScenarioExemptionsCurrentOptions):
|
|
120
|
+
export declare function scenarioExemptionsCurrent(project: ArchProject, set: FeatureSet, options: ScenarioExemptionsCurrentOptions): CollectResult;
|
|
120
121
|
/** Count citing tests / scenarios for a caller's non-vacuity summary line. */
|
|
121
122
|
export declare function scenarioTestStats(project: ArchProject, set: FeatureSet, options?: ScenarioTestsResolveOptions): {
|
|
122
123
|
citations: number;
|
package/dist/gherkin-ts.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gherkin-ts.d.ts","sourceRoot":"","sources":["../src/gherkin-ts.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"gherkin-ts.d.ts","sourceRoot":"","sources":["../src/gherkin-ts.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,mBAAmB,EAExB,KAAK,aAAa,EACnB,MAAM,kBAAkB,CAAA;AAEzB,OAAO,EAAS,KAAK,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAC7D,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAK3E,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAG9D,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AACrD,YAAY,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AAE1E;;;;;GAKG;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,OAAO,EAAE,MAAM,KAAK,qBAAqB,GAAG,SAAS,CAAA;AAE1F,MAAM,WAAW,2BAA4B,SAAQ,mBAAmB;IACtE;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,qBAAqB,CAAA;CACzC;AAED,MAAM,WAAW,uBAAwB,SAAQ,mBAAmB;IAClE,gGAAgG;IAChG,QAAQ,CAAC,OAAO,CAAC,EAAE,qBAAqB,CAAA;IACxC;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,eAAe,KAAK,OAAO,CAAA;CAC1D;AAED,MAAM,WAAW,qBAAqB;IACpC,mEAAmE;IACnE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,gCAAgC;IAChC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CACvB;AAED;qEACqE;AACrE,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACtB;AAQD,uEAAuE;AACvE,iBAAS,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,qBAAqB,GAAG,SAAS,CAM1E;AAsCD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,WAAW,EACpB,GAAG,EAAE,UAAU,EACf,OAAO,GAAE,2BAAgC,GACxC,aAAa,CAmDf;AAUD;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,WAAW,EACpB,GAAG,EAAE,UAAU,EACf,OAAO,EAAE,qBAAqB,GAC7B,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAa/B;AAWD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,WAAW,EACpB,GAAG,EAAE,UAAU,EACf,OAAO,GAAE,uBAA4B,GACpC,aAAa,CAkBf;AAED,MAAM,WAAW,gCAAiC,SAAQ,mBAAmB;IAC3E;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,eAAe,KAAK,OAAO,CAAA;IACzD,4EAA4E;IAC5E,QAAQ,CAAC,OAAO,CAAC,EAAE,qBAAqB,CAAA;CACzC;AAID;;;;;;;;;;;;;GAaG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,WAAW,EACpB,GAAG,EAAE,UAAU,EACf,OAAO,EAAE,gCAAgC,GACxC,aAAa,CA2Bf;AAED,8EAA8E;AAC9E,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,WAAW,EACpB,GAAG,EAAE,UAAU,EACf,OAAO,GAAE,2BAAgC,GACxC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAM1C;AAGD,OAAO,EAAE,cAAc,EAAE,CAAA"}
|
package/dist/gherkin-ts.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { finishPreset } from '@nielspeter/eess';
|
|
1
|
+
import { finishPreset, collectResult, } from '@nielspeter/eess';
|
|
2
|
+
import { featurePaths, violationsFor } from './shared.js';
|
|
2
3
|
import { calls } from '@nielspeter/eess-ts';
|
|
3
4
|
import path from 'node:path';
|
|
4
5
|
import { itOrTestTitleOf } from './it-title.js';
|
|
5
6
|
// Kernel re-exports (plan 0089 — standalone sufficiency): see mermaid-ts.ts.
|
|
6
|
-
export { finishPreset } from '@nielspeter/eess';
|
|
7
|
+
export { finishPreset, collectResult } from '@nielspeter/eess';
|
|
7
8
|
// The gherkin↔ts citation convention (plan 0080): a test names the scenario it
|
|
8
9
|
// proves in its `it()` title — a feature path (unique `/`-boundary suffix, like
|
|
9
10
|
// md↔gherkin) then the scenario title, separated by `›` or `·`.
|
|
@@ -48,21 +49,11 @@ function itTitles(project) {
|
|
|
48
49
|
return out;
|
|
49
50
|
}
|
|
50
51
|
/** Resolve a cited path against the set: exact relPath, or unique `/`-boundary suffix. */
|
|
51
|
-
|
|
52
|
-
const all = set.features().map((f) => f.relPath);
|
|
53
|
-
if (all.includes(path))
|
|
54
|
-
return [path];
|
|
55
|
-
return all.filter((rel) => rel.endsWith(`/${path}`));
|
|
56
|
-
}
|
|
57
|
-
const v = (site, message, because) => ({
|
|
58
|
-
rule: RULE,
|
|
59
|
-
ruleId: 'crossval/scenario-tests-resolve',
|
|
52
|
+
const v = violationsFor(RULE, 'crossval/scenario-tests-resolve', (site) => ({
|
|
60
53
|
element: `${site.file}:${site.line}`,
|
|
61
54
|
file: site.file,
|
|
62
55
|
line: site.line,
|
|
63
|
-
|
|
64
|
-
because,
|
|
65
|
-
});
|
|
56
|
+
}));
|
|
66
57
|
/**
|
|
67
58
|
* Cross-validate that every scenario citation in the *test* AST resolves against
|
|
68
59
|
* the loaded feature set — the mirror image of `scenarioCitationsResolve`, whose
|
|
@@ -82,36 +73,41 @@ export function scenarioTestsResolve(project, set, options = {}) {
|
|
|
82
73
|
const extract = options.extract ?? defaultExtract;
|
|
83
74
|
const scenarioKeys = new Set(set.scenarios().map((s) => `${s.relPath} ${s.title}`));
|
|
84
75
|
const violations = [];
|
|
76
|
+
let examined = 0;
|
|
77
|
+
const paths = featurePaths(set);
|
|
85
78
|
for (const site of itTitles(project)) {
|
|
86
79
|
const cite = extract(site.title);
|
|
87
80
|
if (cite === undefined)
|
|
88
81
|
continue; // not a scenario-citing test
|
|
89
|
-
|
|
90
|
-
|
|
82
|
+
// AFTER the `continue`, deliberately — ADR-014 §2: "a count taken before the
|
|
83
|
+
// loop's own `continue` is the same mistake one line earlier." The unit this
|
|
84
|
+
// rule examines is a CITATION it resolved, not every `it()` in the project;
|
|
85
|
+
// counting titles would report a healthy denominator for a suite that cites
|
|
86
|
+
// nothing at all, which is the exact state this rule exists to notice.
|
|
87
|
+
examined++;
|
|
88
|
+
const resolved = paths.resolve(cite.path);
|
|
89
|
+
if (resolved.kind === 'none') {
|
|
91
90
|
violations.push(v(site, `cites \`${cite.path}\` — no such feature file in the set`, 'a test citing a missing behavior spec is a dangling reference'));
|
|
92
91
|
continue;
|
|
93
92
|
}
|
|
94
|
-
if (resolved.
|
|
95
|
-
violations.push(v(site, `cites \`${cite.path}\` — ambiguous, matches ${resolved.length} feature files (${resolved.join(', ')})`, 'an ambiguous citation cannot be mechanically resolved; cite a longer suffix'));
|
|
93
|
+
if (resolved.kind === 'ambiguous') {
|
|
94
|
+
violations.push(v(site, `cites \`${cite.path}\` — ambiguous, matches ${String(resolved.files.length)} feature files (${resolved.files.join(', ')})`, 'an ambiguous citation cannot be mechanically resolved; cite a longer suffix'));
|
|
96
95
|
continue;
|
|
97
96
|
}
|
|
98
|
-
|
|
99
|
-
|
|
97
|
+
// `none` and `ambiguous` already returned above, so this is exact or unique.
|
|
98
|
+
const rel = resolved.file;
|
|
99
|
+
if (!scenarioKeys.has(`${rel} ${cite.title}`)) {
|
|
100
100
|
violations.push(v(site, `cites '${cite.title}' in \`${rel}\` — no such scenario in that feature file`, 'a renamed or deleted scenario must not silently orphan the test that proves it'));
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
|
-
return finishPreset(violations, options);
|
|
103
|
+
return finishPreset(collectResult(violations, { examined }), options);
|
|
104
104
|
}
|
|
105
105
|
const COVER_RULE = 'every scenario should be proven by a citing test';
|
|
106
|
-
const sv = (
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
line: scenario.line,
|
|
112
|
-
message,
|
|
113
|
-
because,
|
|
114
|
-
});
|
|
106
|
+
const sv = violationsFor(COVER_RULE, 'crossval/scenarios-covered', (s) => ({
|
|
107
|
+
element: `${s.relPath} › ${s.title}`,
|
|
108
|
+
file: s.file,
|
|
109
|
+
line: s.line,
|
|
110
|
+
}));
|
|
115
111
|
/**
|
|
116
112
|
* Every test citation, keyed by the scenario it cites (`relPath title`) —
|
|
117
113
|
* exported (plan 0145) so a consumer can report where a citation lives, not
|
|
@@ -123,12 +119,15 @@ const sv = (scenario, message, because) => ({
|
|
|
123
119
|
*/
|
|
124
120
|
export function citedScenarioSites(project, set, extract) {
|
|
125
121
|
const sites = new Map();
|
|
122
|
+
const paths = featurePaths(set);
|
|
126
123
|
for (const site of itTitles(project)) {
|
|
127
124
|
const cite = extract(site.title);
|
|
128
125
|
if (cite === undefined)
|
|
129
126
|
continue;
|
|
130
|
-
const resolved =
|
|
131
|
-
|
|
127
|
+
const resolved = paths.resolve(cite.path);
|
|
128
|
+
// Unambiguous only: `exact` and `unique` both name one file; `ambiguous`
|
|
129
|
+
// and `none` name none, and this map is keyed on a real path.
|
|
130
|
+
const rel = resolved.kind === 'exact' || resolved.kind === 'unique' ? resolved.file : undefined;
|
|
132
131
|
if (rel !== undefined)
|
|
133
132
|
sites.set(`${rel} ${cite.title}`, site);
|
|
134
133
|
}
|
|
@@ -156,12 +155,14 @@ export function scenariosCovered(project, set, options = {}) {
|
|
|
156
155
|
const extract = options.extract ?? defaultExtract;
|
|
157
156
|
const include = options.include ?? (() => true);
|
|
158
157
|
const covered = citedScenarioKeys(project, set, extract);
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
158
|
+
// The unit is every scenario this rule CONSIDERED, not the ones that failed —
|
|
159
|
+
// counting the misses would report `examined: 0` on a perfectly healthy run.
|
|
160
|
+
const considered = set.scenarios().filter(include);
|
|
161
|
+
const examined = considered.length;
|
|
162
|
+
const violations = considered
|
|
162
163
|
.filter((s) => !covered.has(`${s.relPath} ${s.title}`))
|
|
163
164
|
.map((s) => sv(s, 'no test cites this scenario', 'an unproven use-case flow is a spec with no gate behind it'));
|
|
164
|
-
return finishPreset(violations, options);
|
|
165
|
+
return finishPreset(collectResult(violations, { examined }), options);
|
|
165
166
|
}
|
|
166
167
|
const EXEMPTION_RULE = 'an exempt scenario should have its exemption removed once a test cites it';
|
|
167
168
|
/**
|
|
@@ -181,10 +182,11 @@ const EXEMPTION_RULE = 'an exempt scenario should have its exemption removed onc
|
|
|
181
182
|
export function scenarioExemptionsCurrent(project, set, options) {
|
|
182
183
|
const extract = options.extract ?? defaultExtract;
|
|
183
184
|
const sites = citedScenarioSites(project, set, extract);
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
185
|
+
// Every exemption this rule weighed. A run with no exemptions declared
|
|
186
|
+
// examines nothing and says so, rather than passing silently.
|
|
187
|
+
const exempt = set.scenarios().filter((s) => options.isExempt(s));
|
|
188
|
+
const examined = exempt.length;
|
|
189
|
+
const violations = exempt.flatMap((s) => {
|
|
188
190
|
const site = sites.get(`${s.relPath} ${s.title}`);
|
|
189
191
|
if (site === undefined)
|
|
190
192
|
return [];
|
|
@@ -203,7 +205,7 @@ export function scenarioExemptionsCurrent(project, set, options) {
|
|
|
203
205
|
},
|
|
204
206
|
];
|
|
205
207
|
});
|
|
206
|
-
return finishPreset(violations, options);
|
|
208
|
+
return finishPreset(collectResult(violations, { examined }), options);
|
|
207
209
|
}
|
|
208
210
|
/** Count citing tests / scenarios for a caller's non-vacuity summary line. */
|
|
209
211
|
export function scenarioTestStats(project, set, options = {}) {
|
package/dist/gherkin-ts.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gherkin-ts.js","sourceRoot":"","sources":["../src/gherkin-ts.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"gherkin-ts.js","sourceRoot":"","sources":["../src/gherkin-ts.ts"],"names":[],"mappings":"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"}
|
package/dist/md-gherkin.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import type { CollectResult } from '@nielspeter/eess';
|
|
2
|
+
import { type PresetReportOptions } from '@nielspeter/eess';
|
|
2
3
|
import type { Corpus } from '@nielspeter/eess-md';
|
|
3
4
|
import type { FeatureSet } from '@nielspeter/eess-gherkin';
|
|
4
|
-
export { finishPreset } from '@nielspeter/eess';
|
|
5
|
+
export { finishPreset, collectResult } from '@nielspeter/eess';
|
|
6
|
+
export type { CollectResult } from '@nielspeter/eess';
|
|
5
7
|
export type { ArchViolation, PresetReportOptions } from '@nielspeter/eess';
|
|
6
8
|
export interface ScenarioCitationsResolveOptions extends PresetReportOptions {
|
|
7
9
|
/** Glob selecting the markdown documents to scan. Default `**` (whole corpus). */
|
|
@@ -32,7 +34,7 @@ declare function defaultExtract(line: string): ExtractedCitation[];
|
|
|
32
34
|
* files), or the cited scenario title doesn't exist in that file. Citations
|
|
33
35
|
* inside fenced code blocks never count.
|
|
34
36
|
*/
|
|
35
|
-
export declare function scenarioCitationsResolve(corpus: Corpus, set: FeatureSet, options?: ScenarioCitationsResolveOptions):
|
|
37
|
+
export declare function scenarioCitationsResolve(corpus: Corpus, set: FeatureSet, options?: ScenarioCitationsResolveOptions): CollectResult;
|
|
36
38
|
/** Count citations/scenarios for a caller's non-vacuity summary line. */
|
|
37
39
|
export declare function scenarioCitationStats(corpus: Corpus, set: FeatureSet, options?: ScenarioCitationsResolveOptions): {
|
|
38
40
|
citations: number;
|
package/dist/md-gherkin.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"md-gherkin.d.ts","sourceRoot":"","sources":["../src/md-gherkin.ts"],"names":[],"mappings":"AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"md-gherkin.d.ts","sourceRoot":"","sources":["../src/md-gherkin.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAErD,OAAO,EAGL,KAAK,mBAAmB,EAEzB,MAAM,kBAAkB,CAAA;AACzB,OAAO,KAAK,EAAE,MAAM,EAAc,MAAM,qBAAqB,CAAA;AAC7D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAA;AAG1D,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAG9D,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AACrD,YAAY,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AAE1E,MAAM,WAAW,+BAAgC,SAAQ,mBAAmB;IAC1E,kFAAkF;IAClF,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;IACrB;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,SAAS,iBAAiB,EAAE,CAAA;CAClE;AAED,MAAM,WAAW,iBAAiB;IAChC,mEAAmE;IACnE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,kEAAkE;IAClE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CACxB;AAaD,iBAAS,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAUzD;AAoCD;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,UAAU,EACf,OAAO,GAAE,+BAAoC,GAC5C,aAAa,CA+Cf;AAED,yEAAyE;AACzE,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,UAAU,EACf,OAAO,GAAE,+BAAoC,GAC5C;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAQ5D;AAGD,OAAO,EAAE,cAAc,EAAE,CAAA"}
|
package/dist/md-gherkin.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import picomatch from 'picomatch';
|
|
2
|
-
import {
|
|
2
|
+
import { featurePaths, violationsFor } from './shared.js';
|
|
3
|
+
import { finishPreset, collectResult, } from '@nielspeter/eess';
|
|
3
4
|
// Kernel re-exports (plan 0089 — standalone sufficiency): see mermaid-ts.ts.
|
|
4
|
-
export { finishPreset } from '@nielspeter/eess';
|
|
5
|
+
export { finishPreset, collectResult } from '@nielspeter/eess';
|
|
5
6
|
// The eess scenario-citation convention (plan 0069, frozen at plan-ready):
|
|
6
7
|
// a backticked feature path, then — optionally, same line — a quoted title.
|
|
7
8
|
const FEATURE_PATH_RE = /`([^`\n]+\.feature)`/g;
|
|
@@ -41,21 +42,11 @@ function extractCitations(corpus, dir, extract) {
|
|
|
41
42
|
return out;
|
|
42
43
|
}
|
|
43
44
|
/** Resolve a cited path against the set: exact relPath, or unique `/`-boundary suffix. */
|
|
44
|
-
|
|
45
|
-
const all = set.features().map((f) => f.relPath);
|
|
46
|
-
if (all.includes(path))
|
|
47
|
-
return [path];
|
|
48
|
-
return all.filter((rel) => rel.endsWith(`/${path}`));
|
|
49
|
-
}
|
|
50
|
-
const v = (c, message, because) => ({
|
|
51
|
-
rule: RULE,
|
|
52
|
-
ruleId: 'crossval/scenario-citations-resolve',
|
|
45
|
+
const v = violationsFor(RULE, 'crossval/scenario-citations-resolve', (c) => ({
|
|
53
46
|
element: `${c.doc.relPath}:${c.line}`,
|
|
54
47
|
file: c.doc.file,
|
|
55
48
|
line: c.line,
|
|
56
|
-
|
|
57
|
-
because,
|
|
58
|
-
});
|
|
49
|
+
}));
|
|
59
50
|
/**
|
|
60
51
|
* Cross-validate that every scenario citation in the markdown corpus resolves
|
|
61
52
|
* against the loaded feature set — the md↔gherkin pairing (plan 0069 Phase 2),
|
|
@@ -73,22 +64,26 @@ export function scenarioCitationsResolve(corpus, set, options = {}) {
|
|
|
73
64
|
const citations = extractCitations(corpus, dir, extract);
|
|
74
65
|
const scenarioKeys = new Set(set.scenarios().map((s) => `${s.relPath}\0${s.title}`));
|
|
75
66
|
const violations = [];
|
|
67
|
+
let examined = 0;
|
|
68
|
+
const paths = featurePaths(set);
|
|
76
69
|
for (const c of citations) {
|
|
77
|
-
|
|
78
|
-
|
|
70
|
+
examined++;
|
|
71
|
+
const resolved = paths.resolve(c.path);
|
|
72
|
+
if (resolved.kind === 'none') {
|
|
79
73
|
violations.push(v(c, `cites \`${c.path}\` — no such feature file in the set`, 'a story that cites a missing behavior spec is a dangling reference'));
|
|
80
74
|
continue;
|
|
81
75
|
}
|
|
82
|
-
if (resolved.
|
|
83
|
-
violations.push(v(c, `cites \`${c.path}\` — ambiguous, matches ${resolved.length} feature files (${resolved.join(', ')})`, 'an ambiguous citation cannot be mechanically resolved; cite a longer suffix'));
|
|
76
|
+
if (resolved.kind === 'ambiguous') {
|
|
77
|
+
violations.push(v(c, `cites \`${c.path}\` — ambiguous, matches ${String(resolved.files.length)} feature files (${resolved.files.join(', ')})`, 'an ambiguous citation cannot be mechanically resolved; cite a longer suffix'));
|
|
84
78
|
continue;
|
|
85
79
|
}
|
|
86
|
-
|
|
87
|
-
|
|
80
|
+
// `none` and `ambiguous` already returned above, so this is exact or unique.
|
|
81
|
+
const rel = resolved.file;
|
|
82
|
+
if (c.title !== undefined && !scenarioKeys.has(`${rel}\0${c.title}`)) {
|
|
88
83
|
violations.push(v(c, `cites '${c.title}' in \`${rel}\` — no such scenario in that feature file`, 'a renamed or deleted scenario must not silently orphan the story that cites it'));
|
|
89
84
|
}
|
|
90
85
|
}
|
|
91
|
-
return finishPreset(violations, options);
|
|
86
|
+
return finishPreset(collectResult(violations, { examined }), options);
|
|
92
87
|
}
|
|
93
88
|
/** Count citations/scenarios for a caller's non-vacuity summary line. */
|
|
94
89
|
export function scenarioCitationStats(corpus, set, options = {}) {
|
package/dist/md-gherkin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"md-gherkin.js","sourceRoot":"","sources":["../src/md-gherkin.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"md-gherkin.js","sourceRoot":"","sources":["../src/md-gherkin.ts"],"names":[],"mappings":"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"}
|
package/dist/md-mermaid-er.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import type { CollectResult } from '@nielspeter/eess';
|
|
2
|
+
import { type PresetReportOptions } from '@nielspeter/eess';
|
|
2
3
|
import type { Corpus, MdDocument } from '@nielspeter/eess-md';
|
|
3
|
-
export { finishPreset } from '@nielspeter/eess';
|
|
4
|
+
export { finishPreset, collectResult } from '@nielspeter/eess';
|
|
5
|
+
export type { CollectResult } from '@nielspeter/eess';
|
|
4
6
|
export type { ArchViolation, PresetReportOptions } from '@nielspeter/eess';
|
|
5
7
|
export interface TableErAgreeOptions extends PresetReportOptions {
|
|
6
8
|
/** Glob selecting the documents to check. Default `**`. */
|
|
@@ -34,7 +36,7 @@ export interface TableErAgreeOptions extends PresetReportOptions {
|
|
|
34
36
|
* `undefined`, are skipped — gate diagram *presence* separately with
|
|
35
37
|
* `docs()` conformance if the corpus requires one.
|
|
36
38
|
*/
|
|
37
|
-
export declare function tableErAgree(corpus: Corpus, options: TableErAgreeOptions):
|
|
39
|
+
export declare function tableErAgree(corpus: Corpus, options: TableErAgreeOptions): CollectResult;
|
|
38
40
|
/** Count compared docs/entities/attributes for a caller's non-vacuity summary. */
|
|
39
41
|
export declare function tableErStats(corpus: Corpus, options: TableErAgreeOptions): {
|
|
40
42
|
docs: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"md-mermaid-er.d.ts","sourceRoot":"","sources":["../src/md-mermaid-er.ts"],"names":[],"mappings":"AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"md-mermaid-er.d.ts","sourceRoot":"","sources":["../src/md-mermaid-er.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AACrD,OAAO,EAGL,KAAK,mBAAmB,EAEzB,MAAM,kBAAkB,CAAA;AAEzB,OAAO,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AAI7D,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAG9D,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AACrD,YAAY,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AAE1E,MAAM,WAAW,mBAAoB,SAAQ,mBAAmB;IAC9D,2DAA2D;IAC3D,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;IACtB;;;;OAIG;IACH,QAAQ,CAAC,KAAK,EAAE;QACd,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;QACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;QACrB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KACvB,CAAA;IACD;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,UAAU,KAAK,MAAM,GAAG,SAAS,CAAA;CACzD;AAgCD;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,mBAAmB,GAAG,aAAa,CAkGxF;AAED,kFAAkF;AAClF,wBAAgB,YAAY,CAC1B,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,mBAAmB,GAC3B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAiBxD"}
|
package/dist/md-mermaid-er.js
CHANGED
|
@@ -1,19 +1,12 @@
|
|
|
1
1
|
import picomatch from 'picomatch';
|
|
2
|
-
import { finishPreset } from '@nielspeter/eess';
|
|
2
|
+
import { finishPreset, collectResult, } from '@nielspeter/eess';
|
|
3
|
+
import { violationsFor } from './shared.js';
|
|
3
4
|
import { parseErDiagram, collectEntities } from '@nielspeter/eess-mermaid';
|
|
4
5
|
// Kernel re-exports (plan 0089 — standalone sufficiency): see mermaid-ts.ts.
|
|
5
|
-
export { finishPreset } from '@nielspeter/eess';
|
|
6
|
+
export { finishPreset, collectResult } from '@nielspeter/eess';
|
|
6
7
|
const RULE = 'entity property tables and their erDiagram should agree';
|
|
7
8
|
const ER_HEADER = /^\s*erDiagram\b/;
|
|
8
|
-
const v = (
|
|
9
|
-
rule: RULE,
|
|
10
|
-
ruleId: 'crossval/table-er-agree',
|
|
11
|
-
element: doc.relPath,
|
|
12
|
-
file: doc.file,
|
|
13
|
-
line,
|
|
14
|
-
message,
|
|
15
|
-
because,
|
|
16
|
-
});
|
|
9
|
+
const v = violationsFor(RULE, 'crossval/table-er-agree', ({ doc, line }) => ({ element: doc.relPath, file: doc.file, line }));
|
|
17
10
|
function erEntitiesOf(doc) {
|
|
18
11
|
return doc.codeBlocks
|
|
19
12
|
.filter((b) => (b.lang === 'mermaid' || b.lang === null) && ER_HEADER.test(b.value))
|
|
@@ -42,6 +35,8 @@ function erEntitiesOf(doc) {
|
|
|
42
35
|
export function tableErAgree(corpus, options) {
|
|
43
36
|
const inDocs = picomatch(options.docs ?? '**');
|
|
44
37
|
const violations = [];
|
|
38
|
+
// ER blocks compared, not documents walked.
|
|
39
|
+
let examined = 0;
|
|
45
40
|
for (const doc of corpus.documents()) {
|
|
46
41
|
if (!inDocs(doc.relPath))
|
|
47
42
|
continue;
|
|
@@ -54,8 +49,9 @@ export function tableErAgree(corpus, options) {
|
|
|
54
49
|
// A block that is not standard Mermaid ER syntax is itself drift — flag
|
|
55
50
|
// it (never crash, never silently skip) and compare what did parse.
|
|
56
51
|
for (const b of blocks) {
|
|
52
|
+
examined++;
|
|
57
53
|
if (b.parseError !== undefined) {
|
|
58
|
-
violations.push(v(doc, b.line, `erDiagram does not parse as standard Mermaid ER syntax: ${b.parseError}`, 'a diagram the standard grammar rejects cannot be validated — fix the syntax'));
|
|
54
|
+
violations.push(v({ doc, line: b.line }, `erDiagram does not parse as standard Mermaid ER syntax: ${b.parseError}`, 'a diagram the standard grammar rejects cannot be validated — fix the syntax'));
|
|
59
55
|
}
|
|
60
56
|
}
|
|
61
57
|
if (blocks.every((b) => b.parseError !== undefined))
|
|
@@ -63,13 +59,13 @@ export function tableErAgree(corpus, options) {
|
|
|
63
59
|
const entity = blocks.flatMap((b) => b.entities).find((e) => e.name === entityName);
|
|
64
60
|
const diagramLine = blocks[0]?.line ?? 1;
|
|
65
61
|
if (entity === undefined) {
|
|
66
|
-
violations.push(v(doc, diagramLine, `erDiagram does not declare entity '${entityName}'`, 'the diagram and the document must describe the same entity'));
|
|
62
|
+
violations.push(v({ doc, line: diagramLine }, `erDiagram does not declare entity '${entityName}'`, 'the diagram and the document must describe the same entity'));
|
|
67
63
|
continue;
|
|
68
64
|
}
|
|
69
65
|
const table = doc.tables.find((t) => t.sectionPath.some((h) => options.table.section.test(h)) &&
|
|
70
66
|
t.header.some((h) => options.table.name.test(h)));
|
|
71
67
|
if (table === undefined) {
|
|
72
|
-
violations.push(v(doc, diagramLine, `no property table matching section ${String(options.table.section)} to compare the erDiagram against`, 'attributes ⊆ properties is only checkable when the table exists'));
|
|
68
|
+
violations.push(v({ doc, line: diagramLine }, `no property table matching section ${String(options.table.section)} to compare the erDiagram against`, 'attributes ⊆ properties is only checkable when the table exists'));
|
|
73
69
|
continue;
|
|
74
70
|
}
|
|
75
71
|
const nameIdx = table.header.findIndex((h) => options.table.name.test(h));
|
|
@@ -89,15 +85,15 @@ export function tableErAgree(corpus, options) {
|
|
|
89
85
|
for (const attr of entity.attributes) {
|
|
90
86
|
const tableType = typeByName.get(attr.name);
|
|
91
87
|
if (tableType === undefined) {
|
|
92
|
-
violations.push(v(doc, diagramLine, `erDiagram attribute '${attr.name}' of '${entityName}' is not a row of the property table`, 'a diagram attribute the table does not carry is drift between two views of one entity'));
|
|
88
|
+
violations.push(v({ doc, line: diagramLine }, `erDiagram attribute '${attr.name}' of '${entityName}' is not a row of the property table`, 'a diagram attribute the table does not carry is drift between two views of one entity'));
|
|
93
89
|
continue;
|
|
94
90
|
}
|
|
95
91
|
if (typeIdx >= 0 && tableType.toLowerCase() !== attr.type.toLowerCase()) {
|
|
96
|
-
violations.push(v(doc, diagramLine, `type of '${attr.name}' disagrees: table says '${tableType}', erDiagram says '${attr.type}'`, 'the two representations must state the same type'));
|
|
92
|
+
violations.push(v({ doc, line: diagramLine }, `type of '${attr.name}' disagrees: table says '${tableType}', erDiagram says '${attr.type}'`, 'the two representations must state the same type'));
|
|
97
93
|
}
|
|
98
94
|
}
|
|
99
95
|
}
|
|
100
|
-
return finishPreset(violations, options);
|
|
96
|
+
return finishPreset(collectResult(violations, { examined }), options);
|
|
101
97
|
}
|
|
102
98
|
/** Count compared docs/entities/attributes for a caller's non-vacuity summary. */
|
|
103
99
|
export function tableErStats(corpus, options) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"md-mermaid-er.js","sourceRoot":"","sources":["../src/md-mermaid-er.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"md-mermaid-er.js","sourceRoot":"","sources":["../src/md-mermaid-er.ts"],"names":[],"mappings":"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"}
|
package/dist/md-mermaid.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type Direction, type PresetReportOptions, type CollectResult } from '@nielspeter/eess';
|
|
2
2
|
import type { Corpus } from '@nielspeter/eess-md';
|
|
3
3
|
import { type ArchProject } from '@nielspeter/eess-ts';
|
|
4
|
-
export {
|
|
4
|
+
export { finishPreset, collectResult } from '@nielspeter/eess';
|
|
5
|
+
export type { CollectResult } from '@nielspeter/eess';
|
|
6
|
+
export { correspondence } from '@nielspeter/eess';
|
|
5
7
|
export type { ArchViolation, Direction, PresetReportOptions } from '@nielspeter/eess';
|
|
6
8
|
export interface EmbeddedDiagramsMatchCodeOptions extends PresetReportOptions {
|
|
7
9
|
/** Glob (matched against a class's directory) restricting which TS classes participate. */
|
|
@@ -14,10 +16,43 @@ export interface EmbeddedDiagramsMatchCodeOptions extends PresetReportOptions {
|
|
|
14
16
|
readonly completeness?: Direction;
|
|
15
17
|
}
|
|
16
18
|
/**
|
|
17
|
-
* Cross-validate Mermaid diagrams embedded as fenced ```mermaid blocks
|
|
18
|
-
* markdown corpus against TypeScript code
|
|
19
|
-
* exactly like a standalone `.mmd` file, with violations pointing at the
|
|
19
|
+
* Cross-validate Mermaid **class diagrams** embedded as fenced ```mermaid blocks
|
|
20
|
+
* in the markdown corpus against TypeScript code, with violations pointing at the
|
|
20
21
|
* markdown file and the fence line. Composed from the kernel `correspondence()`.
|
|
22
|
+
*
|
|
23
|
+
* **Scope.** Only class diagrams are compared. A fence declaring another kind
|
|
24
|
+
* (`sequenceDiagram`, `flowchart`, `gantt`, …) is skipped as a different
|
|
25
|
+
* artifact — see {@link embeddedDiagramStats}'s `skipped` for how many. A fence
|
|
26
|
+
* whose kind is unrecognised is still parsed, so an unknown diagram costs a loud
|
|
27
|
+
* finding rather than silent coverage loss.
|
|
28
|
+
*
|
|
29
|
+
* **This preset does not fail on an empty selection.** A corpus with no class
|
|
30
|
+
* diagrams returns no violations. Gate on {@link embeddedDiagramStats} if a
|
|
31
|
+
* non-empty run is what you mean to assert.
|
|
21
32
|
*/
|
|
22
|
-
export declare function embeddedDiagramsMatchCode(corpus: Corpus, project: ArchProject, options?: EmbeddedDiagramsMatchCodeOptions):
|
|
33
|
+
export declare function embeddedDiagramsMatchCode(corpus: Corpus, project: ArchProject, options?: EmbeddedDiagramsMatchCodeOptions): CollectResult;
|
|
34
|
+
/** What a run examined — a caller's non-vacuity evidence (ADR-010). */
|
|
35
|
+
export interface EmbeddedDiagramStats {
|
|
36
|
+
/** Documents holding at least one fence this binding selects. */
|
|
37
|
+
readonly documents: number;
|
|
38
|
+
/**
|
|
39
|
+
* Fences selected for comparison. A fence that turns out not to parse is
|
|
40
|
+
* selected and then reported, not compared — so this is the size of the
|
|
41
|
+
* attempted set, not of the succeeded one.
|
|
42
|
+
*/
|
|
43
|
+
readonly diagrams: number;
|
|
44
|
+
/**
|
|
45
|
+
* Mermaid fences skipped as another diagram kind. A selector that silently
|
|
46
|
+
* drops units is the failure this binding already shipped once, so the count
|
|
47
|
+
* is reported rather than left implicit (bug 0209).
|
|
48
|
+
*/
|
|
49
|
+
readonly skipped: number;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Count what {@link embeddedDiagramsMatchCode} would compare, so a caller can
|
|
53
|
+
* tell "no drift" from "nothing looked at". A green run over zero diagrams is
|
|
54
|
+
* not evidence, and this binding is otherwise unable to say which it produced
|
|
55
|
+
* (bug 0209). Mirrors md-mermaid-er's stats export.
|
|
56
|
+
*/
|
|
57
|
+
export declare function embeddedDiagramStats(corpus: Corpus): EmbeddedDiagramStats;
|
|
23
58
|
//# sourceMappingURL=md-mermaid.d.ts.map
|
package/dist/md-mermaid.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"md-mermaid.d.ts","sourceRoot":"","sources":["../src/md-mermaid.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,
|
|
1
|
+
{"version":3,"file":"md-mermaid.d.ts","sourceRoot":"","sources":["../src/md-mermaid.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,SAAS,EACd,KAAK,mBAAmB,EAExB,KAAK,aAAa,EACnB,MAAM,kBAAkB,CAAA;AAEzB,OAAO,KAAK,EAAE,MAAM,EAAc,MAAM,qBAAqB,CAAA;AAE7D,OAAO,EAAwB,KAAK,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAI5E,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAG9D,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AACjD,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AAuDrF,MAAM,WAAW,gCAAiC,SAAQ,mBAAmB;IAC3E,2FAA2F;IAC3F,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,CAAA;CAClC;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,WAAW,EACpB,OAAO,GAAE,gCAAqC,GAC7C,aAAa,CA6Df;AA2BD,uEAAuE;AACvE,MAAM,WAAW,oBAAoB;IACnC,iEAAiE;IACjE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACzB;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,oBAAoB,CAazE"}
|
package/dist/md-mermaid.js
CHANGED
|
@@ -1,34 +1,121 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { finishPreset, collectResult, } from '@nielspeter/eess';
|
|
2
|
+
import { correspondence } from '@nielspeter/eess';
|
|
2
3
|
import { diagram, classes as mmdClasses } from '@nielspeter/eess-mermaid';
|
|
3
4
|
import { classes as tsClasses } from '@nielspeter/eess-ts';
|
|
5
|
+
import { identifyTsClass } from './shared.js';
|
|
4
6
|
// Kernel re-exports (plan 0089 — standalone sufficiency): see mermaid-ts.ts.
|
|
5
|
-
export {
|
|
7
|
+
export { finishPreset, collectResult } from '@nielspeter/eess';
|
|
8
|
+
export { correspondence } from '@nielspeter/eess';
|
|
9
|
+
// A fence's language tag says it is Mermaid; it does not say which DIAGRAM it
|
|
10
|
+
// is, and `diagram()` only ever parses a class diagram. Selecting on the tag
|
|
11
|
+
// alone fed sequence/flow/state/gantt fences to the class-diagram parser, which
|
|
12
|
+
// threw out of the preset and abandoned every diagram in the corpus (bug 0209).
|
|
13
|
+
//
|
|
14
|
+
// So we select on content — but by EXCLUDING the diagram kinds we know are
|
|
15
|
+
// something else, never by requiring the `classDiagram` keyword. An allowlist
|
|
16
|
+
// is fail-open: it drops anything it fails to recognise, silently, and review
|
|
17
|
+
// measured exactly that (a `%%{init}%%` theme directive ahead of the keyword
|
|
18
|
+
// parses fine and was skipped). A denylist is fail-closed: an unrecognised
|
|
19
|
+
// header reaches `diagram()`, which either parses it or produces an attributed
|
|
20
|
+
// finding. A future Mermaid diagram kind therefore costs a false positive that
|
|
21
|
+
// is loud, not coverage that vanishes.
|
|
22
|
+
// Kinds we know eess-mermaid cannot parse but which ARE legal Mermaid. Used only
|
|
23
|
+
// to phrase the finding honestly — they still reach the parser (fail-closed), and
|
|
24
|
+
// blaming the author's syntax for a grammar gap is the wrong attribution.
|
|
25
|
+
const KNOWN_UNMODELLED = /^(?:classDiagram-v2)\b/;
|
|
26
|
+
const FOREIGN_HEADER = /^(?:sequenceDiagram|flowchart|graph|stateDiagram(?:-v2)?|erDiagram|gantt|journey|pie|gitGraph|mindmap|timeline|quadrantChart|requirementDiagram|sankey(?:-beta)?|xychart(?:-beta)?|block(?:-beta)?|packet(?:-beta)?|kanban|architecture(?:-beta)?|radar(?:-beta)?|treemap(?:-beta)?|zenuml|info|C4(?:Context|Container|Component|Dynamic|Deployment))\b/;
|
|
27
|
+
// Mermaid's grammar treats `%%…` lines as hidden terminals and permits a
|
|
28
|
+
// `---` frontmatter block, so the diagram keyword is not necessarily the first
|
|
29
|
+
// thing in the fence. Find the first line that actually declares the kind.
|
|
30
|
+
function declaredKind(body) {
|
|
31
|
+
const lines = body.split(/\r?\n/);
|
|
32
|
+
let i = 0;
|
|
33
|
+
if (lines[0]?.trim() === '---') {
|
|
34
|
+
i = 1;
|
|
35
|
+
while (i < lines.length && lines[i]?.trim() !== '---')
|
|
36
|
+
i += 1;
|
|
37
|
+
i += 1;
|
|
38
|
+
}
|
|
39
|
+
let inDirective = false;
|
|
40
|
+
for (; i < lines.length; i += 1) {
|
|
41
|
+
const line = lines[i]?.trim() ?? '';
|
|
42
|
+
if (line === '')
|
|
43
|
+
continue;
|
|
44
|
+
// `%%{ … }%%` may span lines. Track it, or the continuation line gets read
|
|
45
|
+
// as the declared kind — measured: a multi-line init block ahead of a
|
|
46
|
+
// sequenceDiagram made it selected, and `skipped` reported 0 (review).
|
|
47
|
+
if (inDirective) {
|
|
48
|
+
if (line.endsWith('}%%'))
|
|
49
|
+
inDirective = false;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (line.startsWith('%%{') && !line.endsWith('}%%')) {
|
|
53
|
+
inDirective = true;
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
if (line.startsWith('%%'))
|
|
57
|
+
continue;
|
|
58
|
+
return line;
|
|
59
|
+
}
|
|
60
|
+
return '';
|
|
61
|
+
}
|
|
6
62
|
/**
|
|
7
|
-
* Cross-validate Mermaid diagrams embedded as fenced ```mermaid blocks
|
|
8
|
-
* markdown corpus against TypeScript code
|
|
9
|
-
* exactly like a standalone `.mmd` file, with violations pointing at the
|
|
63
|
+
* Cross-validate Mermaid **class diagrams** embedded as fenced ```mermaid blocks
|
|
64
|
+
* in the markdown corpus against TypeScript code, with violations pointing at the
|
|
10
65
|
* markdown file and the fence line. Composed from the kernel `correspondence()`.
|
|
66
|
+
*
|
|
67
|
+
* **Scope.** Only class diagrams are compared. A fence declaring another kind
|
|
68
|
+
* (`sequenceDiagram`, `flowchart`, `gantt`, …) is skipped as a different
|
|
69
|
+
* artifact — see {@link embeddedDiagramStats}'s `skipped` for how many. A fence
|
|
70
|
+
* whose kind is unrecognised is still parsed, so an unknown diagram costs a loud
|
|
71
|
+
* finding rather than silent coverage loss.
|
|
72
|
+
*
|
|
73
|
+
* **This preset does not fail on an empty selection.** A corpus with no class
|
|
74
|
+
* diagrams returns no violations. Gate on {@link embeddedDiagramStats} if a
|
|
75
|
+
* non-empty run is what you mean to assert.
|
|
11
76
|
*/
|
|
12
77
|
export function embeddedDiagramsMatchCode(corpus, project, options = {}) {
|
|
13
78
|
const scope = options.scope ?? '**/src/**';
|
|
14
79
|
const direction = options.completeness ?? 'left-to-right';
|
|
15
|
-
const right = tsClasses(project)
|
|
16
|
-
.that()
|
|
17
|
-
.resideInFolder(scope)
|
|
18
|
-
.select({
|
|
80
|
+
const right = tsClasses(project).that().resideInFolder(scope).select({
|
|
19
81
|
label: 'TS class',
|
|
20
|
-
identify:
|
|
21
|
-
name: c.getName() ?? '<anonymous>',
|
|
22
|
-
file: c.getSourceFile().getFilePath(),
|
|
23
|
-
line: c.getStartLineNumber(),
|
|
24
|
-
}),
|
|
82
|
+
identify: identifyTsClass,
|
|
25
83
|
});
|
|
26
84
|
const violations = [];
|
|
85
|
+
// Diagram BLOCKS compared, never documents scanned — counting one layer too
|
|
86
|
+
// high reads healthy on a corpus whose every diagram was skipped.
|
|
87
|
+
let examined = 0;
|
|
27
88
|
for (const doc of corpus.documents()) {
|
|
28
|
-
for (const block of doc
|
|
29
|
-
|
|
89
|
+
for (const block of classDiagramBlocks(doc)) {
|
|
90
|
+
examined++;
|
|
91
|
+
let d;
|
|
92
|
+
try {
|
|
93
|
+
d = diagram(block.value);
|
|
94
|
+
}
|
|
95
|
+
catch (e) {
|
|
96
|
+
// A fence that DECLARES classDiagram and still will not parse is a real
|
|
97
|
+
// finding about this document — report it against the markdown file and
|
|
98
|
+
// fence line rather than throwing out of the preset (bug 0209).
|
|
99
|
+
violations.push({
|
|
100
|
+
rule: 'embedded diagrams should parse as Mermaid',
|
|
101
|
+
ruleId: 'crossval/embedded-diagram',
|
|
102
|
+
element: doc.relPath,
|
|
103
|
+
file: doc.file,
|
|
104
|
+
line: block.line,
|
|
105
|
+
message: `embedded ${kindOf(block.value)} does not parse as a Mermaid class diagram: ${detailOf(e)}` +
|
|
106
|
+
(KNOWN_UNMODELLED.test(kindOf(block.value))
|
|
107
|
+
? ' — this is legal Mermaid that eess-mermaid does not model yet, not a syntax error in your document'
|
|
108
|
+
: ''),
|
|
109
|
+
because: 'A diagram that cannot be parsed cannot be compared against code, so it silently stops constraining it.',
|
|
110
|
+
// Deliberately offers ONE remedy. The earlier text ended "or remove the
|
|
111
|
+
// fence if it is not a class diagram" — review measured that an agent
|
|
112
|
+
// taking that branch turns red into green over a document whose drift
|
|
113
|
+
// is still there. A remedy that remediates by deleting the evidence is
|
|
114
|
+
// not a remedy (ADR-009 rule 2).
|
|
115
|
+
suggestion: 'Fix the diagram syntax so it parses as a Mermaid class diagram. If this fence is a diagram kind eess-mermaid does not model, report it rather than deleting the fence.',
|
|
116
|
+
});
|
|
30
117
|
continue;
|
|
31
|
-
|
|
118
|
+
}
|
|
32
119
|
const left = mmdClasses(d).select({
|
|
33
120
|
label: `diagram class (in ${doc.relPath})`,
|
|
34
121
|
// point violations at the markdown file + fence line, not the parsed diagram
|
|
@@ -41,6 +128,48 @@ export function embeddedDiagramsMatchCode(corpus, project, options = {}) {
|
|
|
41
128
|
.violations());
|
|
42
129
|
}
|
|
43
130
|
}
|
|
44
|
-
return finishPreset(violations, options);
|
|
131
|
+
return finishPreset(collectResult(violations, { examined }), options);
|
|
132
|
+
}
|
|
133
|
+
/** The declared kind of a fence, for phrasing a finding. */
|
|
134
|
+
function kindOf(body) {
|
|
135
|
+
const kind = declaredKind(body).split(/[\s{]/)[0] ?? '';
|
|
136
|
+
return kind === '' ? 'diagram' : kind;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* The informative line of a parse failure. `MermaidUnitParseError`'s message is
|
|
140
|
+
* a constant prefix followed by the real lexer/parser errors, so taking line 0
|
|
141
|
+
* yields `MermaidUnit parse failed:` and no diagnosis at all — measured. The ER
|
|
142
|
+
* sibling takes line 1 for the same reason.
|
|
143
|
+
*/
|
|
144
|
+
function detailOf(e) {
|
|
145
|
+
if (!(e instanceof Error))
|
|
146
|
+
return String(e);
|
|
147
|
+
const lines = e.message.split('\n');
|
|
148
|
+
return lines[1] ?? lines[0] ?? e.message;
|
|
149
|
+
}
|
|
150
|
+
/** The class-diagram fences of one document — the blocks this binding models. */
|
|
151
|
+
function classDiagramBlocks(doc) {
|
|
152
|
+
return doc.codeBlocks.filter((b) => b.lang === 'mermaid' && !FOREIGN_HEADER.test(declaredKind(b.value)));
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Count what {@link embeddedDiagramsMatchCode} would compare, so a caller can
|
|
156
|
+
* tell "no drift" from "nothing looked at". A green run over zero diagrams is
|
|
157
|
+
* not evidence, and this binding is otherwise unable to say which it produced
|
|
158
|
+
* (bug 0209). Mirrors md-mermaid-er's stats export.
|
|
159
|
+
*/
|
|
160
|
+
export function embeddedDiagramStats(corpus) {
|
|
161
|
+
let documents = 0;
|
|
162
|
+
let diagrams = 0;
|
|
163
|
+
let skipped = 0;
|
|
164
|
+
for (const doc of corpus.documents()) {
|
|
165
|
+
const mermaid = doc.codeBlocks.filter((b) => b.lang === 'mermaid');
|
|
166
|
+
const blocks = classDiagramBlocks(doc);
|
|
167
|
+
skipped += mermaid.length - blocks.length;
|
|
168
|
+
if (blocks.length === 0)
|
|
169
|
+
continue;
|
|
170
|
+
documents += 1;
|
|
171
|
+
diagrams += blocks.length;
|
|
172
|
+
}
|
|
173
|
+
return { documents, diagrams, skipped };
|
|
45
174
|
}
|
|
46
175
|
//# sourceMappingURL=md-mermaid.js.map
|
package/dist/md-mermaid.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"md-mermaid.js","sourceRoot":"","sources":["../src/md-mermaid.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,
|
|
1
|
+
{"version":3,"file":"md-mermaid.js","sourceRoot":"","sources":["../src/md-mermaid.ts"],"names":[],"mappings":"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"}
|
package/dist/md-ts.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"md-ts.d.ts","sourceRoot":"","sources":["../src/md-ts.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"md-ts.d.ts","sourceRoot":"","sources":["../src/md-ts.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AACjD,OAAO,EAAS,KAAK,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAI7D,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AACjD,YAAY,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAEjD,MAAM,WAAW,0BAA0B;IACzC,uDAAuD;IACvD,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;IACrB,+DAA+D;IAC/D,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IAClC,uIAAuI;IACvI,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAA;CAClC;AA6CD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,0BAA+B,GACvC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAYrC;AAqCD;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,WAAW,EACpB,OAAO,GAAE,0BAA+B,GACvC,IAAI,CA8CN"}
|
package/dist/md-ts.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"md-ts.js","sourceRoot":"","sources":["../src/md-ts.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"md-ts.js","sourceRoot":"","sources":["../src/md-ts.ts"],"names":[],"mappings":"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"}
|
package/dist/mermaid-ts.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mermaid-ts.d.ts","sourceRoot":"","sources":["../src/mermaid-ts.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"mermaid-ts.d.ts","sourceRoot":"","sources":["../src/mermaid-ts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAEjD,OAAO,EAAyB,KAAK,WAAW,IAAI,cAAc,EAAE,MAAM,0BAA0B,CAAA;AACpG,OAAO,EAAwB,KAAK,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAO5E,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AACjD,YAAY,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAEjD,MAAM,WAAW,yBAAyB;IACxC;uEACmE;IACnE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB;;;OAGG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,CAAA;CAClC;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,WAAW,EACpB,OAAO,GAAE,yBAA8B,GACtC,IAAI,CAqBN"}
|
package/dist/mermaid-ts.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { correspondence } from '@nielspeter/eess';
|
|
2
2
|
import { classes as mmdClasses } from '@nielspeter/eess-mermaid';
|
|
3
3
|
import { classes as tsClasses } from '@nielspeter/eess-ts';
|
|
4
|
+
import { identifyTsClass } from './shared.js';
|
|
4
5
|
// Kernel re-exports (plan 0089 — standalone sufficiency): crossvalidate is
|
|
5
6
|
// the family's binding tool, so unlike the other dialects it MUST re-export
|
|
6
7
|
// what its own body imports — a caller composing a custom cross-dialect
|
|
@@ -22,16 +23,9 @@ export function diagramMatchesCode(diagram, project, options = {}) {
|
|
|
22
23
|
label: 'diagram class',
|
|
23
24
|
identify: (c) => ({ name: c.name }),
|
|
24
25
|
});
|
|
25
|
-
const right = tsClasses(project)
|
|
26
|
-
.that()
|
|
27
|
-
.resideInFolder(scope)
|
|
28
|
-
.select({
|
|
26
|
+
const right = tsClasses(project).that().resideInFolder(scope).select({
|
|
29
27
|
label: 'TS class',
|
|
30
|
-
identify:
|
|
31
|
-
name: c.getName() ?? '<anonymous>',
|
|
32
|
-
file: c.getSourceFile().getFilePath(),
|
|
33
|
-
line: c.getStartLineNumber(),
|
|
34
|
-
}),
|
|
28
|
+
identify: identifyTsClass,
|
|
35
29
|
});
|
|
36
30
|
correspondence({ left, right })
|
|
37
31
|
.should()
|
package/dist/mermaid-ts.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mermaid-ts.js","sourceRoot":"","sources":["../src/mermaid-ts.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"mermaid-ts.js","sourceRoot":"","sources":["../src/mermaid-ts.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AACjD,OAAO,EAAE,OAAO,IAAI,UAAU,EAAsC,MAAM,0BAA0B,CAAA;AACpG,OAAO,EAAE,OAAO,IAAI,SAAS,EAAoB,MAAM,qBAAqB,CAAA;AAC5E,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAE7C,2EAA2E;AAC3E,4EAA4E;AAC5E,wEAAwE;AACxE,uCAAuC;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAcjD;;;;;;;;;GASG;AACH,MAAM,UAAU,kBAAkB,CAChC,OAAuB,EACvB,OAAoB,EACpB,UAAqC,EAAE;IAEvC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,WAAW,CAAA;IAE1C,MAAM,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC;QACtC,KAAK,EAAE,eAAe;QACtB,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;KACpC,CAAC,CAAA;IAEF,MAAM,KAAK,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC;QACnE,KAAK,EAAE,UAAU;QACjB,QAAQ,EAAE,eAAe;KAC1B,CAAC,CAAA;IAEF,cAAc,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;SAC5B,MAAM,EAAE;SACR,UAAU,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,YAAY,IAAI,MAAM,EAAE,CAAC;SACzD,IAAI,CAAC;QACJ,EAAE,EAAE,+BAA+B;QACnC,OAAO,EAAE,4DAA4D;KACtE,CAAC;SACD,KAAK,EAAE,CAAA;AACZ,CAAC"}
|
package/dist/shared.d.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { ClassDeclaration } from 'ts-morph';
|
|
2
|
+
import type { ArchViolation, ElementInfo } from '@nielspeter/eess';
|
|
3
|
+
import { type PathSuffixIndex } from '@nielspeter/eess/internal';
|
|
4
|
+
import type { FeatureSet } from '@nielspeter/eess-gherkin';
|
|
5
|
+
export type { ArchViolation, ElementInfo };
|
|
6
|
+
/**
|
|
7
|
+
* Conventions every binding in this package shares.
|
|
8
|
+
*
|
|
9
|
+
* Each of these was duplicated byte-for-byte across two bindings, which
|
|
10
|
+
* `no-copy-paste` reported at 100%. They are conventions rather than
|
|
11
|
+
* coincidences: how a TS class is named in a finding, and how a cited feature
|
|
12
|
+
* path is resolved, must be the same answer in every binding or two gates
|
|
13
|
+
* disagree about the same file.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* How a TS class appears in a correspondence finding.
|
|
17
|
+
*
|
|
18
|
+
* `<anonymous>` rather than omitting the name: a nameless class still occupies a
|
|
19
|
+
* position in the diagram comparison, and a finding that names nothing cannot be
|
|
20
|
+
* acted on.
|
|
21
|
+
*/
|
|
22
|
+
export declare function identifyTsClass(c: ClassDeclaration): ElementInfo;
|
|
23
|
+
/**
|
|
24
|
+
* A prepared index of the set's feature paths, for resolving citations.
|
|
25
|
+
*
|
|
26
|
+
* An exact `relPath` wins outright. Otherwise the citation is treated as a
|
|
27
|
+
* SUFFIX — `login.feature` matches `specs/auth/login.feature` — so a document
|
|
28
|
+
* can cite a feature without repeating the corpus root it already declared. An
|
|
29
|
+
* ambiguous citation comes back with every candidate, so the caller reports it
|
|
30
|
+
* as ambiguous instead of silently resolving to whichever file the walk reached
|
|
31
|
+
* first.
|
|
32
|
+
*
|
|
33
|
+
* **Bug 0257: the resolution itself is the kernel's now.** This used to be
|
|
34
|
+
* `resolveFeature(path, set)` with its own copy of the algorithm —
|
|
35
|
+
* `eess-md`'s `pointer-resolve.ts` had the same one, down to the exact-wins
|
|
36
|
+
* precedence and the "cite a longer suffix" remedy. What remains here is the
|
|
37
|
+
* binding: which paths go in. Built once per binding rather than rebuilt per
|
|
38
|
+
* citation, which the old two-argument shape forced.
|
|
39
|
+
*/
|
|
40
|
+
export declare function featurePaths(set: FeatureSet): PathSuffixIndex;
|
|
41
|
+
/**
|
|
42
|
+
* A binding's violation constructor: the rule and its id fixed once, the site
|
|
43
|
+
* turned into `element`/`file`/`line` by the binding's own `locate`.
|
|
44
|
+
*
|
|
45
|
+
* Four bindings had written this out by hand — `no-copy-paste` reported three
|
|
46
|
+
* of them at 100% (the fourth escaped only because it took `(doc, line)` as two
|
|
47
|
+
* arguments instead of one site).
|
|
48
|
+
*
|
|
49
|
+
* `locate` is a callback and not a field list because the sites genuinely
|
|
50
|
+
* differ: a test citation locates by `file:line`, a scenario by
|
|
51
|
+
* `relPath › title`, a document by `relPath`. What must NOT differ is that
|
|
52
|
+
* every finding carries all three — a cross-validation violation with no
|
|
53
|
+
* `file`, or with an `element` a reader cannot find in either artifact, names
|
|
54
|
+
* drift without saying where it is (ADR-009 rule 2).
|
|
55
|
+
*/
|
|
56
|
+
export declare function violationsFor<Site>(rule: string, ruleId: string, locate: (site: Site) => {
|
|
57
|
+
element: string;
|
|
58
|
+
file: string;
|
|
59
|
+
line: number;
|
|
60
|
+
}): (site: Site, message: string, because: string) => ArchViolation;
|
|
61
|
+
//# sourceMappingURL=shared.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../src/shared.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAChD,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAClE,OAAO,EAAmB,KAAK,eAAe,EAAE,MAAM,2BAA2B,CAAA;AACjF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAA;AAM1D,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,CAAA;AAE1C;;;;;;;;GAQG;AAEH;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,gBAAgB,GAAG,WAAW,CAMhE;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,UAAU,GAAG,eAAe,CAE7D;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAChC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACtE,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,aAAa,CAEjE"}
|
package/dist/shared.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { pathSuffixIndex } from '@nielspeter/eess/internal';
|
|
2
|
+
/**
|
|
3
|
+
* Conventions every binding in this package shares.
|
|
4
|
+
*
|
|
5
|
+
* Each of these was duplicated byte-for-byte across two bindings, which
|
|
6
|
+
* `no-copy-paste` reported at 100%. They are conventions rather than
|
|
7
|
+
* coincidences: how a TS class is named in a finding, and how a cited feature
|
|
8
|
+
* path is resolved, must be the same answer in every binding or two gates
|
|
9
|
+
* disagree about the same file.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* How a TS class appears in a correspondence finding.
|
|
13
|
+
*
|
|
14
|
+
* `<anonymous>` rather than omitting the name: a nameless class still occupies a
|
|
15
|
+
* position in the diagram comparison, and a finding that names nothing cannot be
|
|
16
|
+
* acted on.
|
|
17
|
+
*/
|
|
18
|
+
export function identifyTsClass(c) {
|
|
19
|
+
return {
|
|
20
|
+
name: c.getName() ?? '<anonymous>',
|
|
21
|
+
file: c.getSourceFile().getFilePath(),
|
|
22
|
+
line: c.getStartLineNumber(),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* A prepared index of the set's feature paths, for resolving citations.
|
|
27
|
+
*
|
|
28
|
+
* An exact `relPath` wins outright. Otherwise the citation is treated as a
|
|
29
|
+
* SUFFIX — `login.feature` matches `specs/auth/login.feature` — so a document
|
|
30
|
+
* can cite a feature without repeating the corpus root it already declared. An
|
|
31
|
+
* ambiguous citation comes back with every candidate, so the caller reports it
|
|
32
|
+
* as ambiguous instead of silently resolving to whichever file the walk reached
|
|
33
|
+
* first.
|
|
34
|
+
*
|
|
35
|
+
* **Bug 0257: the resolution itself is the kernel's now.** This used to be
|
|
36
|
+
* `resolveFeature(path, set)` with its own copy of the algorithm —
|
|
37
|
+
* `eess-md`'s `pointer-resolve.ts` had the same one, down to the exact-wins
|
|
38
|
+
* precedence and the "cite a longer suffix" remedy. What remains here is the
|
|
39
|
+
* binding: which paths go in. Built once per binding rather than rebuilt per
|
|
40
|
+
* citation, which the old two-argument shape forced.
|
|
41
|
+
*/
|
|
42
|
+
export function featurePaths(set) {
|
|
43
|
+
return pathSuffixIndex(set.features().map((f) => f.relPath));
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* A binding's violation constructor: the rule and its id fixed once, the site
|
|
47
|
+
* turned into `element`/`file`/`line` by the binding's own `locate`.
|
|
48
|
+
*
|
|
49
|
+
* Four bindings had written this out by hand — `no-copy-paste` reported three
|
|
50
|
+
* of them at 100% (the fourth escaped only because it took `(doc, line)` as two
|
|
51
|
+
* arguments instead of one site).
|
|
52
|
+
*
|
|
53
|
+
* `locate` is a callback and not a field list because the sites genuinely
|
|
54
|
+
* differ: a test citation locates by `file:line`, a scenario by
|
|
55
|
+
* `relPath › title`, a document by `relPath`. What must NOT differ is that
|
|
56
|
+
* every finding carries all three — a cross-validation violation with no
|
|
57
|
+
* `file`, or with an `element` a reader cannot find in either artifact, names
|
|
58
|
+
* drift without saying where it is (ADR-009 rule 2).
|
|
59
|
+
*/
|
|
60
|
+
export function violationsFor(rule, ruleId, locate) {
|
|
61
|
+
return (site, message, because) => ({ rule, ruleId, ...locate(site), message, because });
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=shared.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../src/shared.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAwB,MAAM,2BAA2B,CAAA;AASjF;;;;;;;;GAQG;AAEH;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,CAAmB;IACjD,OAAO;QACL,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,IAAI,aAAa;QAClC,IAAI,EAAE,CAAC,CAAC,aAAa,EAAE,CAAC,WAAW,EAAE;QACrC,IAAI,EAAE,CAAC,CAAC,kBAAkB,EAAE;KAC7B,CAAA;AACH,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,YAAY,CAAC,GAAe;IAC1C,OAAO,eAAe,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAA;AAC9D,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,aAAa,CAC3B,IAAY,EACZ,MAAc,EACd,MAAuE;IAEvE,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAA;AAC1F,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nielspeter/eess-crossvalidate",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "Cross-validation presets for the eess family — bind two dialects' artifacts and fail when they drift.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -50,6 +50,7 @@
|
|
|
50
50
|
"license": "MIT",
|
|
51
51
|
"scripts": {
|
|
52
52
|
"prepublishOnly": "npm run build",
|
|
53
|
+
"prebuild": "rm -rf dist",
|
|
53
54
|
"build": "tsc -p tsconfig.build.json",
|
|
54
55
|
"test": "vitest run",
|
|
55
56
|
"typecheck": "tsc --noEmit"
|
|
@@ -62,14 +63,14 @@
|
|
|
62
63
|
"markdown"
|
|
63
64
|
],
|
|
64
65
|
"dependencies": {
|
|
65
|
-
"@nielspeter/eess": "^0.
|
|
66
|
+
"@nielspeter/eess": "^0.5.1",
|
|
66
67
|
"picomatch": "^4.0.4"
|
|
67
68
|
},
|
|
68
69
|
"peerDependencies": {
|
|
69
|
-
"@nielspeter/eess-ts": ">=0.
|
|
70
|
-
"@nielspeter/eess-mermaid": ">=0.
|
|
71
|
-
"@nielspeter/eess-md": ">=0.
|
|
72
|
-
"@nielspeter/eess-gherkin": ">=0.
|
|
70
|
+
"@nielspeter/eess-ts": ">=0.5.1",
|
|
71
|
+
"@nielspeter/eess-mermaid": ">=0.4.1",
|
|
72
|
+
"@nielspeter/eess-md": ">=0.6.1",
|
|
73
|
+
"@nielspeter/eess-gherkin": ">=0.4.0"
|
|
73
74
|
},
|
|
74
75
|
"peerDependenciesMeta": {
|
|
75
76
|
"@nielspeter/eess-ts": {
|