@anselmdk/feature-spec-md 0.1.1 → 0.2.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 +94 -50
- package/SPEC_FORMAT.md +200 -38
- package/dist/cli.js +178 -28
- package/dist/cli.js.map +1 -1
- package/dist/featureSpecs.d.ts +34 -0
- package/dist/featureSpecs.d.ts.map +1 -0
- package/dist/featureSpecs.js +240 -0
- package/dist/featureSpecs.js.map +1 -0
- package/dist/filePatterns.d.ts.map +1 -1
- package/dist/filePatterns.js +4 -0
- package/dist/filePatterns.js.map +1 -1
- package/dist/html.d.ts +3 -0
- package/dist/html.d.ts.map +1 -1
- package/dist/html.js +3 -0
- package/dist/html.js.map +1 -1
- package/dist/index.d.ts +3 -34
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -338
- package/dist/index.js.map +1 -1
- package/dist/playwright.d.ts.map +1 -1
- package/dist/playwright.js +13 -21
- package/dist/playwright.js.map +1 -1
- package/dist/reportTemplate.d.ts +4 -1
- package/dist/reportTemplate.d.ts.map +1 -1
- package/dist/reportTemplate.js +251 -21
- package/dist/reportTemplate.js.map +1 -1
- package/dist/screenshots.d.ts.map +1 -1
- package/dist/screenshots.js +4 -0
- package/dist/screenshots.js.map +1 -1
- package/dist/specDocuments.d.ts +86 -0
- package/dist/specDocuments.d.ts.map +1 -0
- package/dist/specDocuments.js +351 -0
- package/dist/specDocuments.js.map +1 -0
- package/dist/specMarkdown.d.ts +26 -0
- package/dist/specMarkdown.d.ts.map +1 -0
- package/dist/specMarkdown.js +126 -0
- package/dist/specMarkdown.js.map +1 -0
- package/dist/testImplementationReport.d.ts +53 -0
- package/dist/testImplementationReport.d.ts.map +1 -0
- package/dist/testImplementationReport.js +160 -0
- package/dist/testImplementationReport.js.map +1 -0
- package/dist/types.d.ts +76 -11
- package/dist/types.d.ts.map +1 -1
- package/docs/releasing.md +107 -0
- package/docs/spec-driven-flow.md +175 -0
- package/package.json +12 -2
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-document parsing, validation, graph checks, and coverage aggregation
|
|
3
|
+
* for model, feature, stack, and design spec documents.
|
|
4
|
+
*/
|
|
5
|
+
import { readFile } from "node:fs/promises";
|
|
6
|
+
import { expandFilePatterns } from "./filePatterns.js";
|
|
7
|
+
import { buildCoverageSummary, parseFeatureSpec, parseTestReferences, validateCoverage, validateFeatureSpec, } from "./featureSpecs.js";
|
|
8
|
+
import { dedupeTestReferences, lineForOffset, modelIdPattern, parseMarkdownDocument, parseRuleItems, sectionBounds, sectionText, trimBlankLines, } from "./specMarkdown.js";
|
|
9
|
+
export function parseSpecDocument(source, options = {}) {
|
|
10
|
+
const filePath = options.filePath ?? "<inline>";
|
|
11
|
+
const kind = options.kind ?? kindFromPath(filePath);
|
|
12
|
+
if (kind === "model")
|
|
13
|
+
return parseModelSpec(source, { filePath });
|
|
14
|
+
if (kind === "stack")
|
|
15
|
+
return parseStackSpec(source, { filePath });
|
|
16
|
+
if (kind === "design")
|
|
17
|
+
return parseDesignSpec(source, { filePath });
|
|
18
|
+
return { ...parseFeatureSpec(source, { filePath }), kind: "feature" };
|
|
19
|
+
}
|
|
20
|
+
export function parseModelSpec(source, options = {}) {
|
|
21
|
+
const filePath = options.filePath ?? "<inline>";
|
|
22
|
+
const parsed = parseMarkdownDocument(source);
|
|
23
|
+
return {
|
|
24
|
+
kind: "model",
|
|
25
|
+
filePath,
|
|
26
|
+
frontmatter: parsed.frontmatter,
|
|
27
|
+
title: parsed.title,
|
|
28
|
+
purpose: parsed.purpose,
|
|
29
|
+
modelItems: parseModelItems(parsed.lines, parsed.bodyStartLine),
|
|
30
|
+
rules: parseRuleItems(parsed.lines, parsed.bodyStartLine),
|
|
31
|
+
source,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
export function parseStackSpec(source, options = {}) {
|
|
35
|
+
const filePath = options.filePath ?? "<inline>";
|
|
36
|
+
const parsed = parseMarkdownDocument(source);
|
|
37
|
+
return {
|
|
38
|
+
kind: "stack",
|
|
39
|
+
filePath,
|
|
40
|
+
frontmatter: parsed.frontmatter,
|
|
41
|
+
title: parsed.title,
|
|
42
|
+
purpose: parsed.purpose,
|
|
43
|
+
stack: sectionText(parsed.lines, "Stack").trim(),
|
|
44
|
+
context: sectionText(parsed.lines, "Context").trim(),
|
|
45
|
+
rationale: sectionText(parsed.lines, "Rationale").trim(),
|
|
46
|
+
consequences: sectionText(parsed.lines, "Consequences").trim(),
|
|
47
|
+
rules: parseRuleItems(parsed.lines, parsed.bodyStartLine),
|
|
48
|
+
source,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
export function parseDesignSpec(source, options = {}) {
|
|
52
|
+
const filePath = options.filePath ?? "<inline>";
|
|
53
|
+
const parsed = parseMarkdownDocument(source);
|
|
54
|
+
return {
|
|
55
|
+
kind: "design",
|
|
56
|
+
filePath,
|
|
57
|
+
frontmatter: parsed.frontmatter,
|
|
58
|
+
title: parsed.title,
|
|
59
|
+
purpose: parsed.purpose,
|
|
60
|
+
design: sectionText(parsed.lines, "Design").trim(),
|
|
61
|
+
principles: sectionText(parsed.lines, "Principles").trim(),
|
|
62
|
+
layout: sectionText(parsed.lines, "Layout").trim(),
|
|
63
|
+
interaction: sectionText(parsed.lines, "Interaction").trim(),
|
|
64
|
+
visualStyle: sectionText(parsed.lines, "Visual style").trim(),
|
|
65
|
+
rules: parseRuleItems(parsed.lines, parsed.bodyStartLine),
|
|
66
|
+
source,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
export async function loadSpecDocuments(patterns) {
|
|
70
|
+
const documents = [];
|
|
71
|
+
for (const file of await expandFilePatterns(patterns)) {
|
|
72
|
+
documents.push(parseSpecDocument(await readFile(file, "utf8"), { filePath: file }));
|
|
73
|
+
}
|
|
74
|
+
return documents;
|
|
75
|
+
}
|
|
76
|
+
export function parseSpecTestReferences(source, filePath = "<inline>") {
|
|
77
|
+
const lines = source.split(/\r?\n/);
|
|
78
|
+
const modelRefs = Array.from(source.matchAll(modelIdPattern)).map((match) => ({
|
|
79
|
+
id: match[0],
|
|
80
|
+
filePath,
|
|
81
|
+
line: lineForOffset(lines, match.index ?? 0),
|
|
82
|
+
kind: "model",
|
|
83
|
+
source: "free-text",
|
|
84
|
+
}));
|
|
85
|
+
return dedupeTestReferences([
|
|
86
|
+
...parseTestReferences(source, filePath),
|
|
87
|
+
...modelRefs,
|
|
88
|
+
]);
|
|
89
|
+
}
|
|
90
|
+
export async function collectSpecTestReferences(patterns) {
|
|
91
|
+
const refs = [];
|
|
92
|
+
for (const file of await expandFilePatterns(patterns)) {
|
|
93
|
+
refs.push(...parseSpecTestReferences(await readFile(file, "utf8"), file));
|
|
94
|
+
}
|
|
95
|
+
return refs;
|
|
96
|
+
}
|
|
97
|
+
export function validateModelSpec(spec) {
|
|
98
|
+
const issues = [];
|
|
99
|
+
validateCommonSpec(spec, issues);
|
|
100
|
+
if (!spec.modelItems.length) {
|
|
101
|
+
issues.push(issue(spec, "missing-model-items", "error", "Model spec must include at least one -M001 model item."));
|
|
102
|
+
}
|
|
103
|
+
for (const item of spec.modelItems) {
|
|
104
|
+
if (!item.id.startsWith(`${spec.frontmatter.id}-`)) {
|
|
105
|
+
issues.push(issue(spec, "wrong-model-prefix", "error", `Model item id "${item.id}" must start with ${spec.frontmatter.id}-.`, item.line));
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return issues;
|
|
109
|
+
}
|
|
110
|
+
export function validateStackSpec(spec) {
|
|
111
|
+
const issues = [];
|
|
112
|
+
validateCommonSpec(spec, issues);
|
|
113
|
+
if (!spec.stack) {
|
|
114
|
+
issues.push(issue(spec, "missing-stack", "error", "Stack spec must include a non-empty ## Stack section."));
|
|
115
|
+
}
|
|
116
|
+
return issues;
|
|
117
|
+
}
|
|
118
|
+
export function validateDesignSpec(spec) {
|
|
119
|
+
const issues = [];
|
|
120
|
+
validateCommonSpec(spec, issues);
|
|
121
|
+
if (!spec.design) {
|
|
122
|
+
issues.push(issue(spec, "missing-design", "error", "Design spec must include a non-empty ## Design section."));
|
|
123
|
+
}
|
|
124
|
+
return issues;
|
|
125
|
+
}
|
|
126
|
+
export function validateSpecDocument(spec) {
|
|
127
|
+
if (spec.kind === "model")
|
|
128
|
+
return validateModelSpec(spec);
|
|
129
|
+
if (spec.kind === "stack")
|
|
130
|
+
return validateStackSpec(spec);
|
|
131
|
+
if (spec.kind === "design")
|
|
132
|
+
return validateDesignSpec(spec);
|
|
133
|
+
return validateFeatureSpec(spec);
|
|
134
|
+
}
|
|
135
|
+
export function validateSpecGraph(documents) {
|
|
136
|
+
const issues = [];
|
|
137
|
+
const modelIds = new Set(documents.filter(isModelSpec).map((model) => model.frontmatter.id));
|
|
138
|
+
const seen = new Map();
|
|
139
|
+
for (const doc of documents) {
|
|
140
|
+
for (const entry of documentIds(doc)) {
|
|
141
|
+
const first = seen.get(entry.id);
|
|
142
|
+
if (first) {
|
|
143
|
+
issues.push({
|
|
144
|
+
code: "duplicate-id",
|
|
145
|
+
severity: "error",
|
|
146
|
+
message: `Duplicate id "${entry.id}".`,
|
|
147
|
+
filePath: entry.filePath,
|
|
148
|
+
line: entry.line,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
seen.set(entry.id, entry);
|
|
152
|
+
}
|
|
153
|
+
if (isModelReferencingSpec(doc)) {
|
|
154
|
+
for (const modelId of referencedModelIds(doc)) {
|
|
155
|
+
if (!modelIds.has(modelId)) {
|
|
156
|
+
issues.push({
|
|
157
|
+
code: "unknown-model-reference",
|
|
158
|
+
severity: "error",
|
|
159
|
+
message: `Spec references unknown model "${modelId}".`,
|
|
160
|
+
filePath: doc.filePath,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return issues;
|
|
167
|
+
}
|
|
168
|
+
export function buildSpecCoverageSummary(documents, references) {
|
|
169
|
+
const baseCoverage = buildCoverageSummary(documents.filter(isFeatureSpec), references);
|
|
170
|
+
const modelRefs = references.filter((ref) => ref.kind === "model");
|
|
171
|
+
const ruleRefs = references.filter((ref) => ref.kind === "rule");
|
|
172
|
+
const rules = documents.flatMap((doc) => doc.rules.map((rule) => ({ doc, rule })));
|
|
173
|
+
const modelItems = documents.flatMap((doc) => doc.kind === "model"
|
|
174
|
+
? doc.modelItems.map((modelItem) => ({ doc, modelItem }))
|
|
175
|
+
: []);
|
|
176
|
+
return {
|
|
177
|
+
...baseCoverage,
|
|
178
|
+
ruleCoverage: rules.map(({ doc, rule }) => coverageItem(rule.id, rule.text, doc.filePath, rule.line, ruleRefs)),
|
|
179
|
+
orphanRuleReferences: ruleRefs.filter((ref) => !rules.some(({ rule }) => rule.id === ref.id)),
|
|
180
|
+
modelCoverage: modelItems.map(({ doc, modelItem }) => ({
|
|
181
|
+
id: modelItem.id,
|
|
182
|
+
title: modelItem.title,
|
|
183
|
+
filePath: doc.filePath,
|
|
184
|
+
line: modelItem.line,
|
|
185
|
+
references: modelRefs.filter((ref) => ref.id === modelItem.id),
|
|
186
|
+
covered: modelRefs.some((ref) => ref.id === modelItem.id),
|
|
187
|
+
})),
|
|
188
|
+
orphanModelReferences: modelRefs.filter((ref) => !modelItems.some(({ modelItem }) => modelItem.id === ref.id)),
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
function coverageItem(id, title, filePath, line, references) {
|
|
192
|
+
const matchingReferences = references.filter((ref) => ref.id === id);
|
|
193
|
+
return {
|
|
194
|
+
id,
|
|
195
|
+
title,
|
|
196
|
+
filePath,
|
|
197
|
+
line,
|
|
198
|
+
references: matchingReferences,
|
|
199
|
+
covered: matchingReferences.length > 0,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
export async function checkSpecDocuments(options) {
|
|
203
|
+
const documents = await loadSpecDocuments(options.specs);
|
|
204
|
+
const references = options.tests?.length
|
|
205
|
+
? await collectSpecTestReferences(options.tests)
|
|
206
|
+
: [];
|
|
207
|
+
const coverage = options.tests?.length
|
|
208
|
+
? buildSpecCoverageSummary(documents, references)
|
|
209
|
+
: undefined;
|
|
210
|
+
const validationIssues = [
|
|
211
|
+
...documents.flatMap(validateSpecDocument),
|
|
212
|
+
...validateSpecGraph(documents),
|
|
213
|
+
];
|
|
214
|
+
const coverageIssues = coverage
|
|
215
|
+
? [
|
|
216
|
+
...validateCoverage(coverage, options),
|
|
217
|
+
...validateModelCoverage(coverage, options.requireModelCoverage),
|
|
218
|
+
]
|
|
219
|
+
: [];
|
|
220
|
+
const models = documents.filter(isModelSpec);
|
|
221
|
+
const features = documents.filter(isFeatureSpec);
|
|
222
|
+
const stacks = documents.filter(isStackSpec);
|
|
223
|
+
const designs = documents.filter(isDesignSpec);
|
|
224
|
+
return {
|
|
225
|
+
documents,
|
|
226
|
+
models,
|
|
227
|
+
features,
|
|
228
|
+
stacks,
|
|
229
|
+
designs,
|
|
230
|
+
specs: features,
|
|
231
|
+
validationIssues,
|
|
232
|
+
coverage,
|
|
233
|
+
coverageIssues,
|
|
234
|
+
ok: ![...validationIssues, ...coverageIssues].some((issue) => issue.severity === "error"),
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
function validateModelCoverage(coverage, required = false) {
|
|
238
|
+
const issues = [];
|
|
239
|
+
if (required) {
|
|
240
|
+
for (const item of coverage.modelCoverage?.filter((item) => !item.covered) ?? []) {
|
|
241
|
+
issues.push({
|
|
242
|
+
code: "missing-model-coverage",
|
|
243
|
+
severity: "error",
|
|
244
|
+
message: `Model item "${item.id}" has no matching test reference.`,
|
|
245
|
+
filePath: item.filePath,
|
|
246
|
+
line: item.line,
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
for (const ref of coverage.orphanModelReferences ?? []) {
|
|
251
|
+
issues.push({
|
|
252
|
+
code: "orphan-model-reference",
|
|
253
|
+
severity: "error",
|
|
254
|
+
message: `Test references unknown model item "${ref.id}".`,
|
|
255
|
+
filePath: ref.filePath,
|
|
256
|
+
line: ref.line,
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
return issues;
|
|
260
|
+
}
|
|
261
|
+
function parseModelItems(lines, bodyStartLine) {
|
|
262
|
+
const bounds = sectionBounds(lines, "Model");
|
|
263
|
+
if (!bounds)
|
|
264
|
+
return [];
|
|
265
|
+
const items = [];
|
|
266
|
+
for (let i = bounds.start; i < bounds.end; i += 1) {
|
|
267
|
+
const match = lines[i].match(/^###\s+([A-Z][A-Z0-9]*(?:-[A-Z0-9]+)*-M\d{3}):\s+(.+)$/);
|
|
268
|
+
if (match) {
|
|
269
|
+
const bodyStart = i + 1;
|
|
270
|
+
let bodyEnd = bounds.end;
|
|
271
|
+
for (let j = bodyStart; j < bounds.end; j += 1) {
|
|
272
|
+
if (/^###\s+([A-Z][A-Z0-9]*(?:-[A-Z0-9]+)*-M\d{3}):\s+(.+)$/.test(lines[j])) {
|
|
273
|
+
bodyEnd = j;
|
|
274
|
+
break;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
items.push({
|
|
278
|
+
id: match[1],
|
|
279
|
+
title: match[2].trim(),
|
|
280
|
+
body: trimBlankLines(lines.slice(bodyStart, bodyEnd)).join("\n"),
|
|
281
|
+
line: bodyStartLine + i,
|
|
282
|
+
});
|
|
283
|
+
i = bodyEnd - 1;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
return items;
|
|
287
|
+
}
|
|
288
|
+
function validateCommonSpec(spec, issues) {
|
|
289
|
+
if (!spec.purpose) {
|
|
290
|
+
issues.push(issue(spec, "missing-purpose", "error", "Spec document must include a non-empty ## Purpose section."));
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
function issue(spec, code, severity, message, line) {
|
|
294
|
+
return { code, severity, message, filePath: spec.filePath, line };
|
|
295
|
+
}
|
|
296
|
+
function referencedModelIds(spec) {
|
|
297
|
+
const models = typeof spec.frontmatter.models === "string"
|
|
298
|
+
? spec.frontmatter.models.split(",")
|
|
299
|
+
: (spec.frontmatter.models ?? []);
|
|
300
|
+
return [spec.frontmatter.model, ...models]
|
|
301
|
+
.map((model) => model?.trim())
|
|
302
|
+
.filter((model) => Boolean(model));
|
|
303
|
+
}
|
|
304
|
+
function kindFromPath(filePath) {
|
|
305
|
+
if (filePath.endsWith(".model.md"))
|
|
306
|
+
return "model";
|
|
307
|
+
if (filePath.endsWith(".stack.md"))
|
|
308
|
+
return "stack";
|
|
309
|
+
if (filePath.endsWith(".design.md"))
|
|
310
|
+
return "design";
|
|
311
|
+
return "feature";
|
|
312
|
+
}
|
|
313
|
+
function isModelSpec(doc) {
|
|
314
|
+
return doc.kind === "model";
|
|
315
|
+
}
|
|
316
|
+
function isFeatureSpec(doc) {
|
|
317
|
+
return doc.kind === "feature" || doc.kind === undefined;
|
|
318
|
+
}
|
|
319
|
+
function isStackSpec(doc) {
|
|
320
|
+
return doc.kind === "stack";
|
|
321
|
+
}
|
|
322
|
+
function isDesignSpec(doc) {
|
|
323
|
+
return doc.kind === "design";
|
|
324
|
+
}
|
|
325
|
+
function isModelReferencingSpec(doc) {
|
|
326
|
+
return isFeatureSpec(doc) || isDesignSpec(doc);
|
|
327
|
+
}
|
|
328
|
+
function documentIds(doc) {
|
|
329
|
+
return [
|
|
330
|
+
{ id: doc.frontmatter.id, filePath: doc.filePath },
|
|
331
|
+
...doc.rules.map((rule) => ({
|
|
332
|
+
id: rule.id,
|
|
333
|
+
filePath: doc.filePath,
|
|
334
|
+
line: rule.line,
|
|
335
|
+
})),
|
|
336
|
+
...(doc.kind === "model"
|
|
337
|
+
? doc.modelItems.map((item) => ({
|
|
338
|
+
id: item.id,
|
|
339
|
+
filePath: doc.filePath,
|
|
340
|
+
line: item.line,
|
|
341
|
+
}))
|
|
342
|
+
: isFeatureSpec(doc)
|
|
343
|
+
? doc.scenarios.map((scenario) => ({
|
|
344
|
+
id: scenario.id,
|
|
345
|
+
filePath: doc.filePath,
|
|
346
|
+
line: scenario.line,
|
|
347
|
+
}))
|
|
348
|
+
: []),
|
|
349
|
+
];
|
|
350
|
+
}
|
|
351
|
+
//# sourceMappingURL=specDocuments.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"specDocuments.js","sourceRoot":"","sources":["../src/specDocuments.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Markdown parsing primitives for frontmatter, sections, rules, stable
|
|
3
|
+
* IDs, line numbers, and test-reference deduplication.
|
|
4
|
+
*/
|
|
5
|
+
import type { FeatureRule, TestReference } from "./types.js";
|
|
6
|
+
export declare const modelIdPattern: RegExp;
|
|
7
|
+
export declare const ruleIdPattern: RegExp;
|
|
8
|
+
export declare const scenarioIdPattern: RegExp;
|
|
9
|
+
export type ParsedMarkdownDocument = {
|
|
10
|
+
frontmatter: Record<string, string>;
|
|
11
|
+
lines: string[];
|
|
12
|
+
bodyStartLine: number;
|
|
13
|
+
title: string;
|
|
14
|
+
purpose: string;
|
|
15
|
+
};
|
|
16
|
+
export declare function parseMarkdownDocument(source: string, documentName?: string): ParsedMarkdownDocument;
|
|
17
|
+
export declare function sectionBounds(lines: string[], heading: string): {
|
|
18
|
+
start: number;
|
|
19
|
+
end: number;
|
|
20
|
+
} | null;
|
|
21
|
+
export declare function sectionText(lines: string[], heading: string): string;
|
|
22
|
+
export declare function parseRuleItems(lines: string[], bodyStartLine: number): FeatureRule[];
|
|
23
|
+
export declare function trimBlankLines(lines: string[]): string[];
|
|
24
|
+
export declare function lineForOffset(lines: string[], offset: number): number;
|
|
25
|
+
export declare function dedupeTestReferences(refs: TestReference[]): TestReference[];
|
|
26
|
+
//# sourceMappingURL=specMarkdown.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"specMarkdown.d.ts","sourceRoot":"","sources":["../src/specMarkdown.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,WAAW,EAAe,aAAa,EAAE,MAAM,YAAY,CAAC;AAE1E,eAAO,MAAM,cAAc,QAA8C,CAAC;AAC1E,eAAO,MAAM,aAAa,QAA8C,CAAC;AACzE,eAAO,MAAM,iBAAiB,QAA8C,CAAC;AAW7E,MAAM,MAAM,sBAAsB,GAAG;IACnC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,EACd,YAAY,SAAkB,GAC7B,sBAAsB,CAmCxB;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM;;;SAW7D;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,UAG3D;AAED,wBAAgB,cAAc,CAC5B,KAAK,EAAE,MAAM,EAAE,EACf,aAAa,EAAE,MAAM,GACpB,WAAW,EAAE,CAwBf;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,YAM7C;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,UAO5D;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,aAAa,EAAE,mBAQzD"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
export const modelIdPattern = /\b[A-Z][A-Z0-9]*(?:-[A-Z0-9]+)*-M\d{3}\b/g;
|
|
2
|
+
export const ruleIdPattern = /\b[A-Z][A-Z0-9]*(?:-[A-Z0-9]+)*-R\d{3}\b/g;
|
|
3
|
+
export const scenarioIdPattern = /\b[A-Z][A-Z0-9]*(?:-[A-Z0-9]+)*-S\d{3}\b/g;
|
|
4
|
+
const ruleKeywords = [
|
|
5
|
+
"MUST NOT",
|
|
6
|
+
"SHOULD NOT",
|
|
7
|
+
"MUST",
|
|
8
|
+
"SHOULD",
|
|
9
|
+
"MAY",
|
|
10
|
+
"OPTIONAL",
|
|
11
|
+
];
|
|
12
|
+
export function parseMarkdownDocument(source, documentName = "Spec document") {
|
|
13
|
+
const normalized = source.replace(/\r\n/g, "\n");
|
|
14
|
+
if (!normalized.startsWith("---\n")) {
|
|
15
|
+
throw new Error(`${documentName} must start with frontmatter delimited by ---. `);
|
|
16
|
+
}
|
|
17
|
+
const endIndex = normalized.indexOf("\n---\n", 4);
|
|
18
|
+
if (endIndex === -1) {
|
|
19
|
+
throw new Error(`${documentName} frontmatter must end with a second --- delimiter.`);
|
|
20
|
+
}
|
|
21
|
+
const frontmatter = parseFrontmatter(normalized.slice(4, endIndex));
|
|
22
|
+
if (!frontmatter.id || !frontmatter.title) {
|
|
23
|
+
throw new Error(`${documentName} frontmatter must contain id and title.`);
|
|
24
|
+
}
|
|
25
|
+
const body = normalized.slice(endIndex + 5);
|
|
26
|
+
const lines = body.split("\n");
|
|
27
|
+
const bodyStartLine = normalized.slice(0, endIndex + 5).split("\n").length;
|
|
28
|
+
return {
|
|
29
|
+
frontmatter,
|
|
30
|
+
lines,
|
|
31
|
+
bodyStartLine,
|
|
32
|
+
title: lines
|
|
33
|
+
.find((line) => line.startsWith("# "))
|
|
34
|
+
?.replace(/^#\s+/, "")
|
|
35
|
+
.trim() ?? frontmatter.title,
|
|
36
|
+
purpose: sectionText(lines, "Purpose").trim(),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export function sectionBounds(lines, heading) {
|
|
40
|
+
const start = lines.findIndex((line) => line.trim() === `## ${heading}`);
|
|
41
|
+
if (start === -1)
|
|
42
|
+
return null;
|
|
43
|
+
let end = lines.length;
|
|
44
|
+
for (let i = start + 1; i < lines.length; i += 1) {
|
|
45
|
+
if (/^##\s+/.test(lines[i])) {
|
|
46
|
+
end = i;
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return { start: start + 1, end };
|
|
51
|
+
}
|
|
52
|
+
export function sectionText(lines, heading) {
|
|
53
|
+
const bounds = sectionBounds(lines, heading);
|
|
54
|
+
return bounds ? lines.slice(bounds.start, bounds.end).join("\n") : "";
|
|
55
|
+
}
|
|
56
|
+
export function parseRuleItems(lines, bodyStartLine) {
|
|
57
|
+
const bounds = sectionBounds(lines, "Rules");
|
|
58
|
+
if (!bounds)
|
|
59
|
+
return [];
|
|
60
|
+
const rules = [];
|
|
61
|
+
for (let i = bounds.start; i < bounds.end; i += 1) {
|
|
62
|
+
const match = lines[i].match(/^\s*-\s+([A-Z][A-Z0-9]*(?:-[A-Z0-9]+)*-R\d{3}):\s+(.+)$/);
|
|
63
|
+
if (!match)
|
|
64
|
+
continue;
|
|
65
|
+
const keyword = ruleKeywords.find((kw) => match[2].toUpperCase().includes(kw));
|
|
66
|
+
rules.push({
|
|
67
|
+
id: match[1],
|
|
68
|
+
text: match[2].trim(),
|
|
69
|
+
keyword,
|
|
70
|
+
strength: ruleStrength(keyword),
|
|
71
|
+
line: bodyStartLine + i,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
return rules;
|
|
75
|
+
}
|
|
76
|
+
export function trimBlankLines(lines) {
|
|
77
|
+
let start = 0;
|
|
78
|
+
let end = lines.length;
|
|
79
|
+
while (start < end && !lines[start].trim())
|
|
80
|
+
start += 1;
|
|
81
|
+
while (end > start && !lines[end - 1].trim())
|
|
82
|
+
end -= 1;
|
|
83
|
+
return lines.slice(start, end);
|
|
84
|
+
}
|
|
85
|
+
export function lineForOffset(lines, offset) {
|
|
86
|
+
let consumed = 0;
|
|
87
|
+
for (const [index, line] of lines.entries()) {
|
|
88
|
+
consumed += line.length + 1;
|
|
89
|
+
if (consumed > offset)
|
|
90
|
+
return index + 1;
|
|
91
|
+
}
|
|
92
|
+
return lines.length;
|
|
93
|
+
}
|
|
94
|
+
export function dedupeTestReferences(refs) {
|
|
95
|
+
const seen = new Set();
|
|
96
|
+
return refs.filter((ref) => {
|
|
97
|
+
const key = `${ref.kind}:${ref.id}:${ref.filePath}:${ref.line}:${ref.source}`;
|
|
98
|
+
if (seen.has(key))
|
|
99
|
+
return false;
|
|
100
|
+
seen.add(key);
|
|
101
|
+
return true;
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
function parseFrontmatter(source) {
|
|
105
|
+
const data = {};
|
|
106
|
+
for (const line of source.split("\n")) {
|
|
107
|
+
const match = line.match(/^([A-Za-z][A-Za-z0-9_-]*):\s*(.*)$/);
|
|
108
|
+
if (match) {
|
|
109
|
+
data[match[1]] = match[2]
|
|
110
|
+
.replace(/^[']|[']$/g, "")
|
|
111
|
+
.replace(/^["]|["]$/g, "")
|
|
112
|
+
.trim();
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return data;
|
|
116
|
+
}
|
|
117
|
+
function ruleStrength(keyword) {
|
|
118
|
+
if (keyword === "MUST" || keyword === "MUST NOT")
|
|
119
|
+
return "required";
|
|
120
|
+
if (keyword === "SHOULD" || keyword === "SHOULD NOT")
|
|
121
|
+
return "recommended";
|
|
122
|
+
if (keyword === "MAY" || keyword === "OPTIONAL")
|
|
123
|
+
return "optional";
|
|
124
|
+
return "unspecified";
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=specMarkdown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"specMarkdown.js","sourceRoot":"","sources":["../src/specMarkdown.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terminal report builder and formatter for summarizing which specs, model
|
|
3
|
+
* items, rules, and scenarios have executable test coverage.
|
|
4
|
+
*/
|
|
5
|
+
import type { CoverageItem, CoverageSummary, FeatureSpec, ModelSpec } from "./types.js";
|
|
6
|
+
export type SpecImplementationStatus = "implemented" | "partial" | "missing";
|
|
7
|
+
export type SpecImplementationItem = {
|
|
8
|
+
id: string;
|
|
9
|
+
title: string;
|
|
10
|
+
filePath: string;
|
|
11
|
+
totalScenarios: number;
|
|
12
|
+
coveredScenarios: number;
|
|
13
|
+
totalRules: number;
|
|
14
|
+
coveredRules: number;
|
|
15
|
+
missingScenarios: CoverageItem[];
|
|
16
|
+
coveredRuleItems: CoverageItem[];
|
|
17
|
+
missingRules: CoverageItem[];
|
|
18
|
+
status: SpecImplementationStatus;
|
|
19
|
+
};
|
|
20
|
+
export type ModelImplementationItem = {
|
|
21
|
+
id: string;
|
|
22
|
+
title: string;
|
|
23
|
+
filePath: string;
|
|
24
|
+
totalItems: number;
|
|
25
|
+
coveredItems: number;
|
|
26
|
+
totalRules: number;
|
|
27
|
+
coveredRules: number;
|
|
28
|
+
coveredModelItems: CoverageItem[];
|
|
29
|
+
missingModelItems: CoverageItem[];
|
|
30
|
+
coveredRuleItems: CoverageItem[];
|
|
31
|
+
missingRules: CoverageItem[];
|
|
32
|
+
};
|
|
33
|
+
export type SpecImplementationReport = {
|
|
34
|
+
models: ModelImplementationItem[];
|
|
35
|
+
specs: SpecImplementationItem[];
|
|
36
|
+
implemented: SpecImplementationItem[];
|
|
37
|
+
partial: SpecImplementationItem[];
|
|
38
|
+
missing: SpecImplementationItem[];
|
|
39
|
+
totalModels: number;
|
|
40
|
+
totalModelItems: number;
|
|
41
|
+
coveredModelItems: number;
|
|
42
|
+
missingModelItems: number;
|
|
43
|
+
totalSpecs: number;
|
|
44
|
+
totalScenarios: number;
|
|
45
|
+
coveredScenarios: number;
|
|
46
|
+
missingScenarios: number;
|
|
47
|
+
totalRules: number;
|
|
48
|
+
coveredRules: number;
|
|
49
|
+
missingRules: number;
|
|
50
|
+
};
|
|
51
|
+
export declare function buildSpecImplementationReport(specs: FeatureSpec[], coverage: CoverageSummary, models?: ModelSpec[]): SpecImplementationReport;
|
|
52
|
+
export declare function formatSpecImplementationReport(report: SpecImplementationReport): string;
|
|
53
|
+
//# sourceMappingURL=testImplementationReport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testImplementationReport.d.ts","sourceRoot":"","sources":["../src/testImplementationReport.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EACV,YAAY,EACZ,eAAe,EACf,WAAW,EACX,SAAS,EACV,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,wBAAwB,GAAG,aAAa,GAAG,SAAS,GAAG,SAAS,CAAC;AAE7E,MAAM,MAAM,sBAAsB,GAAG;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,YAAY,EAAE,CAAC;IACjC,gBAAgB,EAAE,YAAY,EAAE,CAAC;IACjC,YAAY,EAAE,YAAY,EAAE,CAAC;IAC7B,MAAM,EAAE,wBAAwB,CAAC;CAClC,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,iBAAiB,EAAE,YAAY,EAAE,CAAC;IAClC,iBAAiB,EAAE,YAAY,EAAE,CAAC;IAClC,gBAAgB,EAAE,YAAY,EAAE,CAAC;IACjC,YAAY,EAAE,YAAY,EAAE,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,MAAM,EAAE,uBAAuB,EAAE,CAAC;IAClC,KAAK,EAAE,sBAAsB,EAAE,CAAC;IAChC,WAAW,EAAE,sBAAsB,EAAE,CAAC;IACtC,OAAO,EAAE,sBAAsB,EAAE,CAAC;IAClC,OAAO,EAAE,sBAAsB,EAAE,CAAC;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,WAAW,EAAE,EACpB,QAAQ,EAAE,eAAe,EACzB,MAAM,GAAE,SAAS,EAAO,GACvB,wBAAwB,CA+H1B;AAED,wBAAgB,8BAA8B,CAC5C,MAAM,EAAE,wBAAwB,UAuBjC"}
|