@anselmdk/feature-spec-md 0.1.1 → 0.2.1-rc.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.
Files changed (50) hide show
  1. package/README.md +159 -49
  2. package/SPEC_FORMAT.md +200 -38
  3. package/dist/cli.js +198 -28
  4. package/dist/cli.js.map +1 -1
  5. package/dist/featureSpecs.d.ts +34 -0
  6. package/dist/featureSpecs.d.ts.map +1 -0
  7. package/dist/featureSpecs.js +240 -0
  8. package/dist/featureSpecs.js.map +1 -0
  9. package/dist/filePatterns.d.ts.map +1 -1
  10. package/dist/filePatterns.js +4 -0
  11. package/dist/filePatterns.js.map +1 -1
  12. package/dist/githubActionReport.d.ts +3 -0
  13. package/dist/githubActionReport.d.ts.map +1 -0
  14. package/dist/githubActionReport.js +247 -0
  15. package/dist/githubActionReport.js.map +1 -0
  16. package/dist/html.d.ts +3 -0
  17. package/dist/html.d.ts.map +1 -1
  18. package/dist/html.js +3 -0
  19. package/dist/html.js.map +1 -1
  20. package/dist/index.d.ts +3 -34
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +7 -338
  23. package/dist/index.js.map +1 -1
  24. package/dist/playwright.d.ts.map +1 -1
  25. package/dist/playwright.js +13 -21
  26. package/dist/playwright.js.map +1 -1
  27. package/dist/reportTemplate.d.ts +4 -1
  28. package/dist/reportTemplate.d.ts.map +1 -1
  29. package/dist/reportTemplate.js +251 -21
  30. package/dist/reportTemplate.js.map +1 -1
  31. package/dist/screenshots.d.ts.map +1 -1
  32. package/dist/screenshots.js +4 -0
  33. package/dist/screenshots.js.map +1 -1
  34. package/dist/specDocuments.d.ts +86 -0
  35. package/dist/specDocuments.d.ts.map +1 -0
  36. package/dist/specDocuments.js +351 -0
  37. package/dist/specDocuments.js.map +1 -0
  38. package/dist/specMarkdown.d.ts +26 -0
  39. package/dist/specMarkdown.d.ts.map +1 -0
  40. package/dist/specMarkdown.js +126 -0
  41. package/dist/specMarkdown.js.map +1 -0
  42. package/dist/testImplementationReport.d.ts +53 -0
  43. package/dist/testImplementationReport.d.ts.map +1 -0
  44. package/dist/testImplementationReport.js +160 -0
  45. package/dist/testImplementationReport.js.map +1 -0
  46. package/dist/types.d.ts +76 -11
  47. package/dist/types.d.ts.map +1 -1
  48. package/docs/releasing.md +108 -0
  49. package/docs/spec-driven-flow.md +175 -0
  50. package/package.json +13 -3
package/dist/cli.js CHANGED
@@ -1,8 +1,15 @@
1
1
  #!/usr/bin/env node
2
- import { mkdir, writeFile } from "node:fs/promises";
2
+ /**
3
+ * Command-line interface for initializing, validating, reporting on, and
4
+ * measuring test coverage for Feature Spec Markdown documents.
5
+ */
6
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
3
7
  import path from "node:path";
4
- import { checkFeatureSpecs, collectSpecScreenshots, renderHtmlReport, writeTextFile, } from "./index.js";
5
- const defaultSpecPattern = "specs/**/*.feature.md";
8
+ import { collectSpecScreenshots, renderHtmlReport, writeTextFile, } from "./index.js";
9
+ import { publishGithubActionReport } from "./githubActionReport.js";
10
+ import { checkSpecDocuments } from "./specDocuments.js";
11
+ import { buildSpecImplementationReport, formatSpecImplementationReport, } from "./testImplementationReport.js";
12
+ const defaultSpecPattern = "specs/**/*.model.md,specs/**/*.feature.md,specs/**/*.stack.md,specs/**/*.design.md";
6
13
  const defaultTestPattern = "tests/**/*.spec.ts";
7
14
  main().catch((error) => {
8
15
  console.error(error instanceof Error ? error.message : error);
@@ -15,27 +22,54 @@ async function main() {
15
22
  return runCheck(options);
16
23
  if (command === "report")
17
24
  return runReport(options);
25
+ if (command === "coverage")
26
+ return runCoverage(options);
27
+ if (command === "github-report")
28
+ return publishGithubActionReport(options);
18
29
  if (command === "init")
19
30
  return runInit(options);
20
31
  printHelp();
21
32
  process.exit(command === "help" || command === "--help" || command === "-h" ? 0 : 1);
22
33
  }
23
34
  async function runCheck(options) {
24
- const result = await checkFeatureSpecs({
35
+ const result = await checkSpecDocuments({
25
36
  specs: optionList(options.specs, defaultSpecPattern),
26
37
  tests: options.tests === "" ? [] : optionList(options.tests, defaultTestPattern),
38
+ requireModelCoverage: options["require-model-coverage"] === "true",
27
39
  requireRuleCoverage: options["require-rule-coverage"] === "true",
28
40
  requireScenarioCoverage: options["require-scenario-coverage"] !== "false",
29
41
  });
30
42
  printIssues([...result.validationIssues, ...result.coverageIssues]);
31
43
  if (!result.ok)
32
44
  process.exit(1);
33
- const scenarioCount = result.specs.reduce((sum, spec) => sum + spec.scenarios.length, 0);
34
- const ruleCount = result.specs.reduce((sum, spec) => sum + spec.rules.length, 0);
35
- console.log(`Feature spec check passed: ${result.specs.length} spec(s), ${ruleCount} rule(s), ${scenarioCount} scenario(s).`);
45
+ const modelItemCount = result.models.reduce((sum, spec) => sum + spec.modelItems.length, 0);
46
+ const ruleCount = result.documents.reduce((sum, spec) => sum + spec.rules.length, 0);
47
+ const scenarioCount = result.features.reduce((sum, spec) => sum + spec.scenarios.length, 0);
48
+ console.log(`Spec check passed: ${result.models.length} model(s), ${result.features.length} feature(s), ${result.stacks.length} stack(s), ${result.designs.length} design(s), ${modelItemCount} model item(s), ${ruleCount} rule(s), ${scenarioCount} scenario(s).`);
49
+ }
50
+ async function runCoverage(options) {
51
+ const result = await checkSpecDocuments({
52
+ specs: optionList(options.specs, defaultSpecPattern),
53
+ tests: options.tests === "" ? [] : optionList(options.tests, defaultTestPattern),
54
+ requireModelCoverage: false,
55
+ requireRuleCoverage: false,
56
+ requireScenarioCoverage: false,
57
+ });
58
+ printIssues(result.coverageIssues);
59
+ if (!result.coverage) {
60
+ console.log("Spec test implementation report");
61
+ console.log("");
62
+ console.log("No tests were scanned. Pass --tests or omit --tests to use the default tests/**/*.spec.ts pattern.");
63
+ return;
64
+ }
65
+ const report = buildSpecImplementationReport(result.features, result.coverage, result.models);
66
+ console.log(formatSpecImplementationReport(report));
67
+ if (options["fail-on-missing"] === "true" && hasMissingCoverage(report)) {
68
+ process.exit(1);
69
+ }
36
70
  }
37
71
  async function runReport(options) {
38
- const result = await checkFeatureSpecs({
72
+ const result = await checkSpecDocuments({
39
73
  specs: optionList(options.specs, defaultSpecPattern),
40
74
  tests: options.tests === "" ? [] : optionList(options.tests, defaultTestPattern),
41
75
  requireRuleCoverage: options["require-rule-coverage"] === "true",
@@ -45,7 +79,11 @@ async function runReport(options) {
45
79
  const screenshots = options.screenshots
46
80
  ? await collectSpecScreenshots(optionList(options.screenshots, ""))
47
81
  : [];
48
- await writeTextFile(out, renderHtmlReport(result.specs, {
82
+ await writeTextFile(out, renderHtmlReport(result.features, {
83
+ title: await reportTitle(),
84
+ models: result.models,
85
+ stacks: result.stacks,
86
+ designs: result.designs,
49
87
  coverage: result.coverage,
50
88
  screenshots,
51
89
  validationIssues: [...result.validationIssues, ...result.coverageIssues],
@@ -54,9 +92,10 @@ async function runReport(options) {
54
92
  }
55
93
  async function runInit(options) {
56
94
  const dir = options.dir ?? "specs";
57
- const target = path.join(dir, "account-access.feature.md");
95
+ const kind = options.kind ?? "feature";
96
+ const target = path.join(dir, fileNameForKind(kind));
58
97
  await mkdir(dir, { recursive: true });
59
- await writeFile(target, exampleSpec, "utf8");
98
+ await writeFile(target, exampleForKind(kind), "utf8");
60
99
  console.log(`Created ${target}`);
61
100
  }
62
101
  function parseArgs(args) {
@@ -94,25 +133,98 @@ function printIssues(issues) {
94
133
  console.error(`${issue.severity.toUpperCase()} ${issue.code}${location ? ` ${location}` : ""}: ${issue.message}`);
95
134
  }
96
135
  }
136
+ function hasMissingCoverage(report) {
137
+ return (report.missingScenarios > 0 ||
138
+ report.missingRules > 0 ||
139
+ report.missingModelItems > 0);
140
+ }
141
+ async function reportTitle() {
142
+ const packageName = await readPackageName();
143
+ return packageName
144
+ ? `Feature Spec Report for ${packageName}`
145
+ : "Feature Spec Report";
146
+ }
147
+ async function readPackageName() {
148
+ try {
149
+ const raw = await readFile("package.json", "utf8");
150
+ const parsed = JSON.parse(raw);
151
+ return typeof parsed.name === "string" && parsed.name.trim()
152
+ ? parsed.name.trim()
153
+ : undefined;
154
+ }
155
+ catch {
156
+ return undefined;
157
+ }
158
+ }
97
159
  function printHelp() {
98
160
  console.log(`feature-spec-md
99
161
 
100
162
  Usage:
101
- feature-spec-md init [--dir specs]
102
- feature-spec-md check [--specs "specs/**/*.feature.md"] [--tests "tests/**/*.spec.ts"]
103
- feature-spec-md report [--specs "specs/**/*.feature.md"] [--tests "tests/**/*.spec.ts"] [--screenshots "test-results/spec-report/screenshots.json"] [--out test-results/feature-spec-report/index.html]
163
+ feature-spec-md init [--kind feature|model|stack|design] [--dir specs]
164
+ feature-spec-md check [--specs "specs/**/*.model.md,specs/**/*.feature.md,specs/**/*.stack.md,specs/**/*.design.md"] [--tests "tests/**/*.spec.ts"]
165
+ feature-spec-md coverage [--specs "specs/**/*.model.md,specs/**/*.feature.md,specs/**/*.stack.md,specs/**/*.design.md"] [--tests "tests/**/*.spec.ts"] [--fail-on-missing]
166
+ feature-spec-md report [--specs "specs/**/*.model.md,specs/**/*.feature.md,specs/**/*.stack.md,specs/**/*.design.md"] [--tests "tests/**/*.spec.ts"] [--screenshots "test-results/spec-report/screenshots.json"] [--out test-results/feature-spec-report/index.html]
167
+ feature-spec-md github-report [--report-dir test-results/spec-report] [--publish artifact|ftp]
104
168
 
105
169
  Options:
170
+ --require-model-coverage Fail when model items have no matching test references.
106
171
  --require-rule-coverage Fail when rules have no matching test references.
107
172
  --require-scenario-coverage Defaults to true for check. Use --require-scenario-coverage=false to disable.
173
+ --fail-on-missing Exit with status 1 when coverage finds missing model items, rules, or scenarios.
108
174
  --screenshots Screenshot manifest JSON glob for report evidence.
109
175
  --tests "" Disable test coverage lookup.
176
+
177
+ GitHub report publishing:
178
+ --publish artifact Write summary and outputs for GitHub artifact upload.
179
+ --publish ftp Upload report files and an index.html to FTP; no GitHub artifact is needed.
180
+ --ftp-host FTP host, or FEATURE_SPEC_FTP_HOST.
181
+ --ftp-user FTP username, or FEATURE_SPEC_FTP_USER.
182
+ --ftp-password FTP password, or FEATURE_SPEC_FTP_PASSWORD.
183
+ --ftp-remote-dir FTP root directory for reports, or FEATURE_SPEC_FTP_REMOTE_DIR.
184
+ --base-url Public base URL, or FEATURE_SPEC_REPORT_BASE_URL.
110
185
  `);
111
186
  }
112
- const exampleSpec = `---
187
+ function fileNameForKind(kind) {
188
+ if (kind === "model")
189
+ return "example.model.md";
190
+ if (kind === "stack")
191
+ return "example.stack.md";
192
+ if (kind === "design")
193
+ return "example.design.md";
194
+ return "account-access.feature.md";
195
+ }
196
+ function exampleForKind(kind) {
197
+ if (kind === "model")
198
+ return exampleModel;
199
+ if (kind === "stack")
200
+ return exampleStack;
201
+ if (kind === "design")
202
+ return exampleDesign;
203
+ return exampleFeature;
204
+ }
205
+ const exampleModel = `---
113
206
  id: ACCOUNT
207
+ title: Account model
208
+ status: draft
209
+ ---
210
+
211
+ # Account model
212
+
213
+ ## Purpose
214
+
215
+ Define the shared account concepts used by account access features.
216
+
217
+ ## Model
218
+
219
+ ### ACCOUNT-M001: Account
220
+
221
+ An account represents one registered person.
222
+ `;
223
+ const exampleFeature = `---
224
+ id: ACCOUNT-ACCESS
114
225
  title: Account access
115
226
  status: draft
227
+ model: ACCOUNT
116
228
  ---
117
229
 
118
230
  # Account access
@@ -123,24 +235,82 @@ People can access their own account after proving their identity.
123
235
 
124
236
  ## Rules
125
237
 
126
- - ACCOUNT-R001: A person MUST prove control of a registered email address before accessing an account.
127
- - ACCOUNT-R002: The system MUST NOT reveal whether an unknown email address belongs to an account.
128
- - ACCOUNT-R003: A signed-in person SHOULD be returned to the page they originally requested.
238
+ - ACCOUNT-ACCESS-R001: A person MUST prove control of a registered email address before accessing an account.
239
+ - ACCOUNT-ACCESS-R002: The system MUST NOT reveal whether an unknown email address belongs to an account.
129
240
 
130
241
  ## Scenarios
131
242
 
132
- ### ACCOUNT-S001: Registered person signs in
243
+ ### ACCOUNT-ACCESS-S001: Registered person signs in
244
+
245
+ Given a registered person is on the sign-in page
246
+ When they request and open a valid sign-in link
247
+ Then they are signed in
248
+ `;
249
+ const exampleStack = `---
250
+ id: ACCOUNT-STACK
251
+ title: Account stack
252
+ status: draft
253
+ ---
254
+
255
+ # Account stack
256
+
257
+ ## Purpose
258
+
259
+ Define the initial technical stack for the account access demo.
260
+
261
+ ## Context
262
+
263
+ The demo is a small browser-based application with automated tests.
264
+
265
+ ## Stack
266
+
267
+ | Area | Choice |
268
+ |---|---|
269
+ | Frontend | React |
270
+ | Language | TypeScript |
271
+ | Testing | Playwright |
272
+
273
+ ## Rationale
274
+
275
+ React, TypeScript, and Playwright fit the interaction-heavy UI and scenario-based testing style.
276
+
277
+ ## Consequences
278
+
279
+ The stack is optimized for a browser UI and static deployment.
280
+ `;
281
+ const exampleDesign = `---
282
+ id: ACCOUNT-DESIGN
283
+ title: Account design
284
+ status: draft
285
+ model: ACCOUNT
286
+ ---
287
+
288
+ # Account design
289
+
290
+ ## Purpose
291
+
292
+ Define the initial interaction and visual design direction for account access.
293
+
294
+ ## Design
295
+
296
+ The account access flow should feel simple, calm, and direct.
297
+
298
+ ## Principles
299
+
300
+ - Keep the sign-in flow short.
301
+ - Avoid revealing whether an email address exists.
302
+ - Make recovery states easy to understand.
303
+
304
+ ## Layout
305
+
306
+ The sign-in page uses one primary form and one primary action.
307
+
308
+ ## Interaction
133
309
 
134
- Given a registered person is on the sign-in page
135
- When they request and open a valid sign-in link
136
- Then they are signed in
137
- And they are returned to the page they originally requested
310
+ Validation messages appear near the field they describe.
138
311
 
139
- ### ACCOUNT-S002: Unknown email receives a neutral response
312
+ ## Visual style
140
313
 
141
- Given a person enters an email address that is not registered
142
- When they request a sign-in link
143
- Then the response says to check their email
144
- And the response does not reveal whether the email address is registered
314
+ Use a clean, low-distraction visual style.
145
315
  `;
146
316
  //# sourceMappingURL=cli.js.map
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ import type { CoverageSummary, FeatureSpec, TestReference, ValidationIssue } from "./types.js";
2
+ /** Parse one feature spec Markdown document into structured metadata, rules, and scenarios. */
3
+ export declare function parseFeatureSpec(source: string, options?: {
4
+ filePath?: string;
5
+ }): FeatureSpec;
6
+ /** Validate spec structure, ID prefixes, duplicate IDs, and required sections. */
7
+ export declare function validateFeatureSpec(spec: FeatureSpec): ValidationIssue[];
8
+ /** Find rule and scenario IDs referenced by one test source file. */
9
+ export declare function parseTestReferences(source: string, filePath?: string): TestReference[];
10
+ /** Expand test file globs and collect all rule and scenario references from them. */
11
+ export declare function collectTestReferences(patterns: string[]): Promise<TestReference[]>;
12
+ /** Build rule and scenario coverage from parsed specs and collected test references. */
13
+ export declare function buildCoverageSummary(specs: FeatureSpec[], references: TestReference[]): CoverageSummary;
14
+ /** Validate coverage expectations and orphaned references. */
15
+ export declare function validateCoverage(coverage: CoverageSummary, options?: {
16
+ requireRuleCoverage?: boolean;
17
+ requireScenarioCoverage?: boolean;
18
+ }): ValidationIssue[];
19
+ /** Load and parse all feature specs matching the provided globs. */
20
+ export declare function loadFeatureSpecs(patterns: string[]): Promise<FeatureSpec[]>;
21
+ /** Run spec validation and optional test coverage validation in one call. */
22
+ export declare function checkFeatureSpecs(options: {
23
+ specs: string[];
24
+ tests?: string[];
25
+ requireRuleCoverage?: boolean;
26
+ requireScenarioCoverage?: boolean;
27
+ }): Promise<{
28
+ specs: FeatureSpec[];
29
+ validationIssues: ValidationIssue[];
30
+ coverage: CoverageSummary | undefined;
31
+ coverageIssues: ValidationIssue[];
32
+ ok: boolean;
33
+ }>;
34
+ //# sourceMappingURL=featureSpecs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"featureSpecs.d.ts","sourceRoot":"","sources":["../src/featureSpecs.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAEV,eAAe,EAGf,WAAW,EAEX,aAAa,EACb,eAAe,EAChB,MAAM,YAAY,CAAC;AAEpB,+FAA+F;AAC/F,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,MAAM,EACd,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,GAClC,WAAW,CAab;AAED,kFAAkF;AAClF,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,WAAW,GAAG,eAAe,EAAE,CA2GxE;AAED,qEAAqE;AACrE,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,EACd,QAAQ,SAAa,GACpB,aAAa,EAAE,CAyBjB;AAED,qFAAqF;AACrF,wBAAsB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,4BAM7D;AAED,wFAAwF;AACxF,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,WAAW,EAAE,EACpB,UAAU,EAAE,aAAa,EAAE,GAC1B,eAAe,CAkCjB;AAED,8DAA8D;AAC9D,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,eAAe,EACzB,OAAO,GAAE;IACP,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,uBAAuB,CAAC,EAAE,OAAO,CAAC;CAC9B,qBAmDP;AAED,oEAAoE;AACpE,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,0BAQxD;AAED,6EAA6E;AAC7E,wBAAsB,iBAAiB,CAAC,OAAO,EAAE;IAC/C,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,uBAAuB,CAAC,EAAE,OAAO,CAAC;CACnC;;;;;;GAsBA"}
@@ -0,0 +1,240 @@
1
+ /**
2
+ * Feature-spec parsing, validation, test-reference extraction, and coverage
3
+ * checks for `*.feature.md` documents.
4
+ */
5
+ import { readFile } from "node:fs/promises";
6
+ import { expandFilePatterns } from "./filePatterns.js";
7
+ import { dedupeTestReferences, lineForOffset, parseMarkdownDocument, parseRuleItems, ruleIdPattern, scenarioIdPattern, } from "./specMarkdown.js";
8
+ /** Parse one feature spec Markdown document into structured metadata, rules, and scenarios. */
9
+ export function parseFeatureSpec(source, options = {}) {
10
+ const filePath = options.filePath ?? "<inline>";
11
+ const parsed = parseMarkdownDocument(source, "Feature spec");
12
+ return {
13
+ filePath,
14
+ frontmatter: parsed.frontmatter,
15
+ title: parsed.title,
16
+ purpose: parsed.purpose,
17
+ rules: parseRuleItems(parsed.lines, parsed.bodyStartLine),
18
+ scenarios: parseScenarios(parsed.lines, parsed.bodyStartLine),
19
+ source,
20
+ };
21
+ }
22
+ /** Validate spec structure, ID prefixes, duplicate IDs, and required sections. */
23
+ export function validateFeatureSpec(spec) {
24
+ const issues = [];
25
+ const seen = new Map();
26
+ if (!/^[A-Z][A-Z0-9]*(?:-[A-Z0-9]+)*$/.test(spec.frontmatter.id)) {
27
+ issues.push(issue(spec, "invalid-feature-id", "error", `Feature id "${spec.frontmatter.id}" must use uppercase words separated by hyphens.`));
28
+ }
29
+ if (spec.title !== spec.frontmatter.title) {
30
+ issues.push(issue(spec, "title-mismatch", "warning", "The H1 title should match frontmatter.title."));
31
+ }
32
+ if (!spec.purpose) {
33
+ issues.push(issue(spec, "missing-purpose", "error", "Feature spec must include a non-empty ## Purpose section."));
34
+ }
35
+ if (spec.scenarios.length === 0) {
36
+ issues.push(issue(spec, "missing-scenarios", "error", "Feature spec must include at least one scenario."));
37
+ }
38
+ for (const rule of spec.rules) {
39
+ if (!rule.id.startsWith(`${spec.frontmatter.id}-`)) {
40
+ issues.push(issue(spec, "wrong-rule-prefix", "error", `Rule id "${rule.id}" must start with ${spec.frontmatter.id}-.`, rule.line));
41
+ }
42
+ if (!rule.keyword) {
43
+ issues.push(issue(spec, "missing-rule-keyword", "warning", `Rule "${rule.id}" should use MUST, MUST NOT, SHOULD, SHOULD NOT, MAY, or OPTIONAL.`, rule.line));
44
+ }
45
+ registerId(spec, issues, seen, rule.id, rule.line);
46
+ }
47
+ for (const scenario of spec.scenarios) {
48
+ if (!scenario.id.startsWith(`${spec.frontmatter.id}-`)) {
49
+ issues.push(issue(spec, "wrong-scenario-prefix", "error", `Scenario id "${scenario.id}" must start with ${spec.frontmatter.id}-.`, scenario.line));
50
+ }
51
+ for (const keyword of ["Given", "When", "Then"]) {
52
+ if (!scenario.steps.some((step) => step.keyword === keyword)) {
53
+ issues.push(issue(spec, `missing-${keyword.toLowerCase()}`, "warning", `Scenario "${scenario.id}" should include a ${keyword} step.`, scenario.line));
54
+ }
55
+ }
56
+ registerId(spec, issues, seen, scenario.id, scenario.line);
57
+ }
58
+ return issues;
59
+ }
60
+ /** Find rule and scenario IDs referenced by one test source file. */
61
+ export function parseTestReferences(source, filePath = "<inline>") {
62
+ const lines = source.split(/\r?\n/);
63
+ const refs = [];
64
+ for (const match of source.matchAll(scenarioIdPattern)) {
65
+ refs.push({
66
+ id: match[0],
67
+ filePath,
68
+ line: lineForOffset(lines, match.index ?? 0),
69
+ kind: "scenario",
70
+ source: sourceForMatch(source, match.index ?? 0),
71
+ });
72
+ }
73
+ for (const match of source.matchAll(ruleIdPattern)) {
74
+ refs.push({
75
+ id: match[0],
76
+ filePath,
77
+ line: lineForOffset(lines, match.index ?? 0),
78
+ kind: "rule",
79
+ source: sourceForMatch(source, match.index ?? 0),
80
+ });
81
+ }
82
+ return dedupeTestReferences(refs);
83
+ }
84
+ /** Expand test file globs and collect all rule and scenario references from them. */
85
+ export async function collectTestReferences(patterns) {
86
+ const refs = [];
87
+ for (const file of await expandFilePatterns(patterns)) {
88
+ refs.push(...parseTestReferences(await readFile(file, "utf8"), file));
89
+ }
90
+ return refs;
91
+ }
92
+ /** Build rule and scenario coverage from parsed specs and collected test references. */
93
+ export function buildCoverageSummary(specs, references) {
94
+ const scenarios = new Map(specs.flatMap((spec) => spec.scenarios.map((scenario) => [scenario.id, { spec, scenario }])));
95
+ const rules = new Map(specs.flatMap((spec) => spec.rules.map((rule) => [rule.id, { spec, rule }])));
96
+ const scenarioRefs = references.filter((ref) => ref.kind === "scenario");
97
+ const ruleRefs = references.filter((ref) => ref.kind === "rule");
98
+ return {
99
+ scenarioCoverage: Array.from(scenarios.entries()).map(([id, value]) => item(id, value.scenario.title, value.spec.filePath, value.scenario.line, scenarioRefs)),
100
+ ruleCoverage: Array.from(rules.entries()).map(([id, value]) => item(id, value.rule.text, value.spec.filePath, value.rule.line, ruleRefs)),
101
+ orphanScenarioReferences: scenarioRefs.filter((ref) => !scenarios.has(ref.id)),
102
+ orphanRuleReferences: ruleRefs.filter((ref) => !rules.has(ref.id)),
103
+ };
104
+ }
105
+ /** Validate coverage expectations and orphaned references. */
106
+ export function validateCoverage(coverage, options = {}) {
107
+ const issues = [];
108
+ if (options.requireScenarioCoverage ?? true) {
109
+ for (const item of coverage.scenarioCoverage.filter((item) => !item.covered)) {
110
+ issues.push({
111
+ code: "missing-scenario-coverage",
112
+ severity: "error",
113
+ message: `Scenario "${item.id}" has no matching test reference.`,
114
+ filePath: item.filePath,
115
+ line: item.line,
116
+ });
117
+ }
118
+ }
119
+ if (options.requireRuleCoverage ?? false) {
120
+ for (const item of coverage.ruleCoverage.filter((item) => !item.covered)) {
121
+ issues.push({
122
+ code: "missing-rule-coverage",
123
+ severity: "error",
124
+ message: `Rule "${item.id}" has no matching test reference.`,
125
+ filePath: item.filePath,
126
+ line: item.line,
127
+ });
128
+ }
129
+ }
130
+ for (const ref of coverage.orphanScenarioReferences) {
131
+ issues.push({
132
+ code: "orphan-scenario-reference",
133
+ severity: "error",
134
+ message: `Test references unknown scenario "${ref.id}".`,
135
+ filePath: ref.filePath,
136
+ line: ref.line,
137
+ });
138
+ }
139
+ for (const ref of coverage.orphanRuleReferences) {
140
+ issues.push({
141
+ code: "orphan-rule-reference",
142
+ severity: "error",
143
+ message: `Test references unknown rule "${ref.id}".`,
144
+ filePath: ref.filePath,
145
+ line: ref.line,
146
+ });
147
+ }
148
+ return issues;
149
+ }
150
+ /** Load and parse all feature specs matching the provided globs. */
151
+ export async function loadFeatureSpecs(patterns) {
152
+ const specs = [];
153
+ for (const file of await expandFilePatterns(patterns)) {
154
+ specs.push(parseFeatureSpec(await readFile(file, "utf8"), { filePath: file }));
155
+ }
156
+ return specs;
157
+ }
158
+ /** Run spec validation and optional test coverage validation in one call. */
159
+ export async function checkFeatureSpecs(options) {
160
+ const specs = await loadFeatureSpecs(options.specs);
161
+ const validationIssues = specs.flatMap(validateFeatureSpec);
162
+ const coverage = options.tests?.length
163
+ ? buildCoverageSummary(specs, await collectTestReferences(options.tests))
164
+ : undefined;
165
+ const coverageIssues = coverage
166
+ ? validateCoverage(coverage, {
167
+ requireRuleCoverage: options.requireRuleCoverage,
168
+ requireScenarioCoverage: options.requireScenarioCoverage,
169
+ })
170
+ : [];
171
+ return {
172
+ specs,
173
+ validationIssues,
174
+ coverage,
175
+ coverageIssues,
176
+ ok: ![...validationIssues, ...coverageIssues].some((i) => i.severity === "error"),
177
+ };
178
+ }
179
+ function parseScenarios(lines, bodyStartLine) {
180
+ const scenarios = [];
181
+ for (let i = 0; i < lines.length; i += 1) {
182
+ const match = lines[i].match(/^###\s+([A-Z][A-Z0-9]*(?:-[A-Z0-9]+)*-S\d{3}):\s+(.+)$/);
183
+ if (!match)
184
+ continue;
185
+ const steps = [];
186
+ for (let j = i + 1; j < lines.length; j += 1) {
187
+ if (/^##?#\s+/.test(lines[j]))
188
+ break;
189
+ const step = lines[j].trim().match(/^(Given|When|Then|And|But)\s+(.+)$/);
190
+ if (step)
191
+ steps.push({
192
+ keyword: step[1],
193
+ text: step[2].trim(),
194
+ line: bodyStartLine + j,
195
+ });
196
+ }
197
+ scenarios.push({
198
+ id: match[1],
199
+ title: match[2].trim(),
200
+ line: bodyStartLine + i,
201
+ steps,
202
+ });
203
+ }
204
+ return scenarios;
205
+ }
206
+ function issue(spec, code, severity, message, line) {
207
+ return { code, severity, message, filePath: spec.filePath, line };
208
+ }
209
+ function registerId(spec, issues, seen, id, line) {
210
+ const previous = seen.get(id);
211
+ if (previous)
212
+ issues.push(issue(spec, "duplicate-id", "error", `Duplicate id "${id}". First occurrence is on line ${previous}.`, line));
213
+ seen.set(id, line);
214
+ }
215
+ function item(id, title, filePath, line, refs) {
216
+ const references = refs.filter((ref) => ref.id === id);
217
+ return {
218
+ id,
219
+ title,
220
+ filePath,
221
+ line,
222
+ references,
223
+ covered: references.length > 0,
224
+ };
225
+ }
226
+ function sourceForMatch(source, offset) {
227
+ const before = source.slice(Math.max(0, offset - 80), offset);
228
+ const context = source.slice(Math.max(0, offset - 80), offset + 80);
229
+ if (/covers\s*:\s*\[[^\]]*$/.test(before))
230
+ return "covers";
231
+ if (/tag\s*:\s*\[[^\]]*$/.test(before) ||
232
+ /@/.test(source.slice(Math.max(0, offset - 2), offset + 2)))
233
+ return "tag";
234
+ if (/annotation/.test(context))
235
+ return "annotation";
236
+ if (/test|scenario/.test(before.slice(-40)))
237
+ return "title";
238
+ return "free-text";
239
+ }
240
+ //# sourceMappingURL=featureSpecs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"featureSpecs.js","sourceRoot":"","sources":["../src/featureSpecs.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"filePatterns.d.ts","sourceRoot":"","sources":["../src/filePatterns.ts"],"names":[],"mappings":"AAEA,8EAA8E;AAC9E,wBAAsB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,qBAO1D;AAED,0EAA0E;AAC1E,wBAAsB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,qBAE9D"}
1
+ {"version":3,"file":"filePatterns.d.ts","sourceRoot":"","sources":["../src/filePatterns.ts"],"names":[],"mappings":"AAMA,8EAA8E;AAC9E,wBAAsB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,qBAO1D;AAED,0EAA0E;AAC1E,wBAAsB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,qBAE9D"}
@@ -1,3 +1,7 @@
1
+ /**
2
+ * Glob expansion helpers for source specs, tests, and generated artifact
3
+ * patterns while filtering directories that should never be scanned.
4
+ */
1
5
  import { glob } from "node:fs/promises";
2
6
  /** Expand user-provided source globs while ignoring generated directories. */
3
7
  export async function expandFilePatterns(patterns) {
@@ -1 +1 @@
1
- {"version":3,"file":"filePatterns.js","sourceRoot":"","sources":["../src/filePatterns.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAExC,8EAA8E;AAC9E,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,QAAkB;IACzD,OAAO,cAAc,CAAC,QAAQ,EAAE;QAC9B,iBAAiB;QACjB,SAAS;QACT,SAAS;QACT,iBAAiB;KAClB,CAAC,CAAC;AACL,CAAC;AAED,0EAA0E;AAC1E,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,QAAkB;IAC7D,OAAO,cAAc,CAAC,QAAQ,EAAE,CAAC,iBAAiB,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC;AAC7E,CAAC;AAED,KAAK,UAAU,cAAc,CAAC,QAAkB,EAAE,OAAiB;IACjE,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,KAAK,EAAE,MAAM,IAAI,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;YACpD,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;AAClC,CAAC"}
1
+ {"version":3,"file":"filePatterns.js","sourceRoot":"","sources":["../src/filePatterns.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAExC,8EAA8E;AAC9E,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,QAAkB;IACzD,OAAO,cAAc,CAAC,QAAQ,EAAE;QAC9B,iBAAiB;QACjB,SAAS;QACT,SAAS;QACT,iBAAiB;KAClB,CAAC,CAAC;AACL,CAAC;AAED,0EAA0E;AAC1E,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,QAAkB;IAC7D,OAAO,cAAc,CAAC,QAAQ,EAAE,CAAC,iBAAiB,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC;AAC7E,CAAC;AAED,KAAK,UAAU,cAAc,CAAC,QAAkB,EAAE,OAAiB;IACjE,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,KAAK,EAAE,MAAM,IAAI,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;YACpD,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;AAClC,CAAC"}