@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,160 @@
|
|
|
1
|
+
export function buildSpecImplementationReport(specs, coverage, models = []) {
|
|
2
|
+
const modelCoverage = new Map(coverage.modelCoverage?.map((item) => [item.id, item]) ?? []);
|
|
3
|
+
const scenarioCoverage = new Map(coverage.scenarioCoverage.map((item) => [item.id, item]));
|
|
4
|
+
const ruleCoverage = new Map(coverage.ruleCoverage.map((item) => [item.id, item]));
|
|
5
|
+
const modelItems = models.map((model) => {
|
|
6
|
+
const coverageItems = model.modelItems.map((modelItem) => modelCoverage.get(modelItem.id) ?? {
|
|
7
|
+
id: modelItem.id,
|
|
8
|
+
title: modelItem.title,
|
|
9
|
+
filePath: model.filePath,
|
|
10
|
+
line: modelItem.line,
|
|
11
|
+
covered: false,
|
|
12
|
+
references: [],
|
|
13
|
+
});
|
|
14
|
+
const coveredModelItems = coverageItems.filter((item) => item.covered);
|
|
15
|
+
const missingModelItems = coverageItems.filter((item) => !item.covered);
|
|
16
|
+
const rules = model.rules.map((rule) => ruleCoverage.get(rule.id) ?? {
|
|
17
|
+
id: rule.id,
|
|
18
|
+
title: rule.text,
|
|
19
|
+
filePath: model.filePath,
|
|
20
|
+
line: rule.line,
|
|
21
|
+
covered: false,
|
|
22
|
+
references: [],
|
|
23
|
+
});
|
|
24
|
+
const coveredRuleItems = rules.filter((rule) => rule.covered);
|
|
25
|
+
const missingRules = rules.filter((rule) => !rule.covered);
|
|
26
|
+
return {
|
|
27
|
+
id: model.frontmatter.id,
|
|
28
|
+
title: model.title,
|
|
29
|
+
filePath: model.filePath,
|
|
30
|
+
totalItems: coverageItems.length,
|
|
31
|
+
coveredItems: coveredModelItems.length,
|
|
32
|
+
totalRules: rules.length,
|
|
33
|
+
coveredRules: coveredRuleItems.length,
|
|
34
|
+
coveredModelItems,
|
|
35
|
+
missingModelItems,
|
|
36
|
+
coveredRuleItems,
|
|
37
|
+
missingRules,
|
|
38
|
+
};
|
|
39
|
+
});
|
|
40
|
+
const items = specs.map((spec) => {
|
|
41
|
+
const scenarios = spec.scenarios.map((scenario) => scenarioCoverage.get(scenario.id) ?? {
|
|
42
|
+
id: scenario.id,
|
|
43
|
+
title: scenario.title,
|
|
44
|
+
filePath: spec.filePath,
|
|
45
|
+
line: scenario.line,
|
|
46
|
+
covered: false,
|
|
47
|
+
references: [],
|
|
48
|
+
});
|
|
49
|
+
const rules = spec.rules.map((rule) => ruleCoverage.get(rule.id) ?? {
|
|
50
|
+
id: rule.id,
|
|
51
|
+
title: rule.text,
|
|
52
|
+
filePath: spec.filePath,
|
|
53
|
+
line: rule.line,
|
|
54
|
+
covered: false,
|
|
55
|
+
references: [],
|
|
56
|
+
});
|
|
57
|
+
const missingScenarios = scenarios.filter((scenario) => !scenario.covered);
|
|
58
|
+
const coveredScenarios = scenarios.length - missingScenarios.length;
|
|
59
|
+
const coveredRuleItems = rules.filter((rule) => rule.covered);
|
|
60
|
+
const missingRules = rules.filter((rule) => !rule.covered);
|
|
61
|
+
const status = statusForCoverage(coveredScenarios, scenarios.length);
|
|
62
|
+
return {
|
|
63
|
+
id: spec.frontmatter.id,
|
|
64
|
+
title: spec.title,
|
|
65
|
+
filePath: spec.filePath,
|
|
66
|
+
totalScenarios: scenarios.length,
|
|
67
|
+
coveredScenarios,
|
|
68
|
+
totalRules: rules.length,
|
|
69
|
+
coveredRules: coveredRuleItems.length,
|
|
70
|
+
missingScenarios,
|
|
71
|
+
coveredRuleItems,
|
|
72
|
+
missingRules,
|
|
73
|
+
status,
|
|
74
|
+
};
|
|
75
|
+
});
|
|
76
|
+
return {
|
|
77
|
+
models: modelItems,
|
|
78
|
+
specs: items,
|
|
79
|
+
implemented: items.filter((item) => item.status === "implemented"),
|
|
80
|
+
partial: items.filter((item) => item.status === "partial"),
|
|
81
|
+
missing: items.filter((item) => item.status === "missing"),
|
|
82
|
+
totalModels: modelItems.length,
|
|
83
|
+
totalModelItems: modelItems.reduce((sum, item) => sum + item.totalItems, 0),
|
|
84
|
+
coveredModelItems: modelItems.reduce((sum, item) => sum + item.coveredItems, 0),
|
|
85
|
+
missingModelItems: modelItems.reduce((sum, item) => sum + item.missingModelItems.length, 0),
|
|
86
|
+
totalSpecs: items.length,
|
|
87
|
+
totalScenarios: items.reduce((sum, item) => sum + item.totalScenarios, 0),
|
|
88
|
+
coveredScenarios: items.reduce((sum, item) => sum + item.coveredScenarios, 0),
|
|
89
|
+
missingScenarios: items.reduce((sum, item) => sum + item.missingScenarios.length, 0),
|
|
90
|
+
totalRules: coverage.ruleCoverage.length,
|
|
91
|
+
coveredRules: coverage.ruleCoverage.filter((item) => item.covered).length,
|
|
92
|
+
missingRules: coverage.ruleCoverage.filter((item) => !item.covered).length,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
export function formatSpecImplementationReport(report) {
|
|
96
|
+
const modelSummary = report.totalModelItems > 0
|
|
97
|
+
? `, ${report.coveredModelItems}/${report.totalModelItems} model item(s) covered`
|
|
98
|
+
: "";
|
|
99
|
+
const missingModelSummary = report.totalModelItems > 0
|
|
100
|
+
? `. Missing model items: ${report.missingModelItems}`
|
|
101
|
+
: "";
|
|
102
|
+
return [
|
|
103
|
+
"Spec test implementation report",
|
|
104
|
+
"",
|
|
105
|
+
`Summary: ${report.implemented.length}/${report.totalSpecs} spec(s) implemented, ${report.coveredScenarios}/${report.totalScenarios} scenario(s) covered, ${report.coveredRules}/${report.totalRules} rule(s) covered${modelSummary}.`,
|
|
106
|
+
`Partial: ${report.partial.length}. Not implemented: ${report.missing.length}. Missing scenarios: ${report.missingScenarios}. Missing rules: ${report.missingRules}${missingModelSummary}.`,
|
|
107
|
+
...(report.totalModels > 0 ? ["", formatModelSection(report.models)] : []),
|
|
108
|
+
"",
|
|
109
|
+
formatSection("Implemented", report.implemented),
|
|
110
|
+
"",
|
|
111
|
+
formatSection("Partial", report.partial),
|
|
112
|
+
"",
|
|
113
|
+
formatSection("Not implemented", report.missing),
|
|
114
|
+
].join("\n");
|
|
115
|
+
}
|
|
116
|
+
function statusForCoverage(coveredScenarios, totalScenarios) {
|
|
117
|
+
if (totalScenarios > 0 && coveredScenarios === totalScenarios)
|
|
118
|
+
return "implemented";
|
|
119
|
+
if (coveredScenarios > 0)
|
|
120
|
+
return "partial";
|
|
121
|
+
return "missing";
|
|
122
|
+
}
|
|
123
|
+
function formatSection(title, specs) {
|
|
124
|
+
if (!specs.length)
|
|
125
|
+
return `${title}:\n (none)`;
|
|
126
|
+
return [
|
|
127
|
+
`${title}:`,
|
|
128
|
+
...specs.flatMap((spec) => [
|
|
129
|
+
` - ${spec.id}: ${spec.title} (${spec.coveredScenarios}/${spec.totalScenarios} scenarios, ${spec.coveredRules}/${spec.totalRules} rules) ${spec.filePath}`,
|
|
130
|
+
...spec.missingScenarios.map((scenario) => ` missing ${scenario.id}: ${scenario.title ?? "Untitled scenario"}`),
|
|
131
|
+
...spec.coveredRuleItems.map((rule) => ` covered rule ${rule.id}: ${rule.title ?? "Untitled rule"}${formatCoverageReferenceSuffix(rule)}`),
|
|
132
|
+
...spec.missingRules.map((rule) => ` missing rule ${rule.id}: ${rule.title ?? "Untitled rule"}`),
|
|
133
|
+
]),
|
|
134
|
+
].join("\n");
|
|
135
|
+
}
|
|
136
|
+
function formatModelSection(models) {
|
|
137
|
+
if (!models.length)
|
|
138
|
+
return "Models:\n (none)";
|
|
139
|
+
return [
|
|
140
|
+
"Models:",
|
|
141
|
+
...models.flatMap((model) => [
|
|
142
|
+
` - ${model.id}: ${model.title} (${model.coveredItems}/${model.totalItems} model items, ${model.coveredRules}/${model.totalRules} rules) ${model.filePath}`,
|
|
143
|
+
...model.coveredModelItems.map((item) => ` covered model ${item.id}: ${item.title ?? "Untitled model item"}${formatCoverageReferenceSuffix(item)}`),
|
|
144
|
+
...model.missingModelItems.map((item) => ` missing model ${item.id}: ${item.title ?? "Untitled model item"}`),
|
|
145
|
+
...model.coveredRuleItems.map((rule) => ` covered rule ${rule.id}: ${rule.title ?? "Untitled rule"}${formatCoverageReferenceSuffix(rule)}`),
|
|
146
|
+
...model.missingRules.map((rule) => ` missing rule ${rule.id}: ${rule.title ?? "Untitled rule"}`),
|
|
147
|
+
]),
|
|
148
|
+
].join("\n");
|
|
149
|
+
}
|
|
150
|
+
function formatCoverageReferenceSuffix(item) {
|
|
151
|
+
const references = coverageReferenceLabels(item);
|
|
152
|
+
return references.length ? ` (${references.join(", ")})` : "";
|
|
153
|
+
}
|
|
154
|
+
function coverageReferenceLabels(item) {
|
|
155
|
+
return Array.from(new Set(item.references.map((reference) => {
|
|
156
|
+
const line = reference.line ? `:${reference.line}` : "";
|
|
157
|
+
return `${reference.filePath}${line}`;
|
|
158
|
+
})));
|
|
159
|
+
}
|
|
160
|
+
//# sourceMappingURL=testImplementationReport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testImplementationReport.js","sourceRoot":"","sources":["../src/testImplementationReport.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,5 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared TypeScript types for parsed spec documents, validation issues,
|
|
3
|
+
* coverage summaries, test references, and screenshot evidence.
|
|
4
|
+
*/
|
|
5
|
+
/** Shared frontmatter fields supported by all spec documents. */
|
|
6
|
+
export type SpecFrontmatter = {
|
|
7
|
+
id: string;
|
|
8
|
+
title: string;
|
|
9
|
+
status?: "draft" | "active" | "deprecated";
|
|
10
|
+
owner?: string;
|
|
11
|
+
};
|
|
12
|
+
/** Frontmatter fields supported by documents that may reference models. */
|
|
13
|
+
export type ModelReferenceFrontmatter = SpecFrontmatter & {
|
|
14
|
+
model?: string;
|
|
15
|
+
models?: string[] | string;
|
|
16
|
+
};
|
|
17
|
+
/** Frontmatter fields supported by `*.feature.md` files. */
|
|
18
|
+
export type FeatureFrontmatter = ModelReferenceFrontmatter;
|
|
19
|
+
/** Frontmatter fields supported by `*.design.md` files. */
|
|
20
|
+
export type DesignFrontmatter = ModelReferenceFrontmatter;
|
|
21
|
+
/** Parsed contents of one `*.model.md` file. */
|
|
22
|
+
export type ModelSpec = {
|
|
23
|
+
kind: "model";
|
|
24
|
+
filePath: string;
|
|
25
|
+
frontmatter: SpecFrontmatter;
|
|
26
|
+
title: string;
|
|
27
|
+
purpose: string;
|
|
28
|
+
modelItems: ModelItem[];
|
|
29
|
+
rules: FeatureRule[];
|
|
30
|
+
source: string;
|
|
31
|
+
};
|
|
1
32
|
/** Parsed contents of one `*.feature.md` file. */
|
|
2
33
|
export type FeatureSpec = {
|
|
34
|
+
kind?: "feature";
|
|
3
35
|
filePath: string;
|
|
4
36
|
frontmatter: FeatureFrontmatter;
|
|
5
37
|
title: string;
|
|
@@ -8,14 +40,45 @@ export type FeatureSpec = {
|
|
|
8
40
|
scenarios: FeatureScenario[];
|
|
9
41
|
source: string;
|
|
10
42
|
};
|
|
11
|
-
/**
|
|
12
|
-
export type
|
|
43
|
+
/** Parsed contents of one `*.stack.md` file. */
|
|
44
|
+
export type StackSpec = {
|
|
45
|
+
kind: "stack";
|
|
46
|
+
filePath: string;
|
|
47
|
+
frontmatter: SpecFrontmatter;
|
|
48
|
+
title: string;
|
|
49
|
+
purpose: string;
|
|
50
|
+
stack: string;
|
|
51
|
+
context: string;
|
|
52
|
+
rationale: string;
|
|
53
|
+
consequences: string;
|
|
54
|
+
rules: FeatureRule[];
|
|
55
|
+
source: string;
|
|
56
|
+
};
|
|
57
|
+
/** Parsed contents of one `*.design.md` file. */
|
|
58
|
+
export type DesignSpec = {
|
|
59
|
+
kind: "design";
|
|
60
|
+
filePath: string;
|
|
61
|
+
frontmatter: DesignFrontmatter;
|
|
62
|
+
title: string;
|
|
63
|
+
purpose: string;
|
|
64
|
+
design: string;
|
|
65
|
+
principles: string;
|
|
66
|
+
layout: string;
|
|
67
|
+
interaction: string;
|
|
68
|
+
visualStyle: string;
|
|
69
|
+
rules: FeatureRule[];
|
|
70
|
+
source: string;
|
|
71
|
+
};
|
|
72
|
+
/** Any parsed spec document. */
|
|
73
|
+
export type SpecDocument = ModelSpec | FeatureSpec | StackSpec | DesignSpec;
|
|
74
|
+
/** A model concept declared in the `## Model` section. */
|
|
75
|
+
export type ModelItem = {
|
|
13
76
|
id: string;
|
|
14
77
|
title: string;
|
|
15
|
-
|
|
16
|
-
|
|
78
|
+
body: string;
|
|
79
|
+
line: number;
|
|
17
80
|
};
|
|
18
|
-
/** A
|
|
81
|
+
/** A rule declared in the `## Rules` section. */
|
|
19
82
|
export type FeatureRule = {
|
|
20
83
|
id: string;
|
|
21
84
|
text: string;
|
|
@@ -46,15 +109,15 @@ export type ValidationIssue = {
|
|
|
46
109
|
filePath?: string;
|
|
47
110
|
line?: number;
|
|
48
111
|
};
|
|
49
|
-
/** A rule or scenario ID found in executable tests. */
|
|
112
|
+
/** A model item, rule, or scenario ID found in executable tests. */
|
|
50
113
|
export type TestReference = {
|
|
51
114
|
id: string;
|
|
52
115
|
filePath: string;
|
|
53
116
|
line: number;
|
|
54
|
-
kind: "
|
|
117
|
+
kind: "model" | "rule" | "scenario";
|
|
55
118
|
source: "title" | "tag" | "covers" | "annotation" | "free-text";
|
|
56
119
|
};
|
|
57
|
-
/** Coverage state for one expected rule or scenario. */
|
|
120
|
+
/** Coverage state for one expected model item, rule, or scenario. */
|
|
58
121
|
export type CoverageItem = {
|
|
59
122
|
id: string;
|
|
60
123
|
title?: string;
|
|
@@ -63,12 +126,14 @@ export type CoverageItem = {
|
|
|
63
126
|
covered: boolean;
|
|
64
127
|
references: TestReference[];
|
|
65
128
|
};
|
|
66
|
-
/** Complete test coverage mapping for a set of
|
|
129
|
+
/** Complete test coverage mapping for a set of spec documents. */
|
|
67
130
|
export type CoverageSummary = {
|
|
68
|
-
|
|
131
|
+
modelCoverage?: CoverageItem[];
|
|
69
132
|
ruleCoverage: CoverageItem[];
|
|
70
|
-
|
|
133
|
+
scenarioCoverage: CoverageItem[];
|
|
134
|
+
orphanModelReferences?: TestReference[];
|
|
71
135
|
orphanRuleReferences: TestReference[];
|
|
136
|
+
orphanScenarioReferences: TestReference[];
|
|
72
137
|
};
|
|
73
138
|
/** Screenshot evidence associated with an exact spec line. */
|
|
74
139
|
export type SpecScreenshot = {
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,kDAAkD;AAClD,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,kBAAkB,CAAC;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,SAAS,EAAE,eAAe,EAAE,CAAC;IAC7B,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,iEAAiE;AACjE,MAAM,MAAM,eAAe,GAAG;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,YAAY,CAAC;IAC3C,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,2EAA2E;AAC3E,MAAM,MAAM,yBAAyB,GAAG,eAAe,GAAG;IACxD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC;CAC5B,CAAC;AAEF,4DAA4D;AAC5D,MAAM,MAAM,kBAAkB,GAAG,yBAAyB,CAAC;AAE3D,2DAA2D;AAC3D,MAAM,MAAM,iBAAiB,GAAG,yBAAyB,CAAC;AAE1D,gDAAgD;AAChD,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,eAAe,CAAC;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,SAAS,EAAE,CAAC;IACxB,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,kDAAkD;AAClD,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,kBAAkB,CAAC;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,SAAS,EAAE,eAAe,EAAE,CAAC;IAC7B,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,gDAAgD;AAChD,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,eAAe,CAAC;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,iDAAiD;AACjD,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,QAAQ,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,iBAAiB,CAAC;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,gCAAgC;AAChC,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,UAAU,CAAC;AAE5E,0DAA0D;AAC1D,MAAM,MAAM,SAAS,GAAG;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,iDAAiD;AACjD,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,QAAQ,EAAE,UAAU,GAAG,aAAa,GAAG,UAAU,GAAG,aAAa,CAAC;IAClE,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,iEAAiE;AACjE,MAAM,MAAM,eAAe,GAAG;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,WAAW,EAAE,CAAC;CACtB,CAAC;AAEF,iEAAiE;AACjE,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE,WAAW,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,WAAW,GACnB,MAAM,GACN,UAAU,GACV,QAAQ,GACR,YAAY,GACZ,KAAK,GACL,UAAU,CAAC;AAEf,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK,CAAC;AAEpE,2EAA2E;AAC3E,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,oEAAoE;AACpE,MAAM,MAAM,aAAa,GAAG;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,UAAU,CAAC;IACpC,MAAM,EAAE,OAAO,GAAG,KAAK,GAAG,QAAQ,GAAG,YAAY,GAAG,WAAW,CAAC;CACjE,CAAC;AAEF,qEAAqE;AACrE,MAAM,MAAM,YAAY,GAAG;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,aAAa,EAAE,CAAC;CAC7B,CAAC;AAEF,kEAAkE;AAClE,MAAM,MAAM,eAAe,GAAG;IAC5B,aAAa,CAAC,EAAE,YAAY,EAAE,CAAC;IAC/B,YAAY,EAAE,YAAY,EAAE,CAAC;IAC7B,gBAAgB,EAAE,YAAY,EAAE,CAAC;IACjC,qBAAqB,CAAC,EAAE,aAAa,EAAE,CAAC;IACxC,oBAAoB,EAAE,aAAa,EAAE,CAAC;IACtC,wBAAwB,EAAE,aAAa,EAAE,CAAC;CAC3C,CAAC;AAEF,8DAA8D;AAC9D,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# Releasing
|
|
2
|
+
|
|
3
|
+
This package uses npm semver versions and bare git tags. Use `0.2.0`, not `v0.2.0`.
|
|
4
|
+
|
|
5
|
+
Bare semver tags are valid git tags and match the package version exactly. The `v` prefix is common in many projects because it makes tag names visually distinct from branch names, but npm does not require it. For this repository, exact package-version tags are simpler because the tag, `package.json`, `package-lock.json`, and npm version all use the same string.
|
|
6
|
+
|
|
7
|
+
## Release Candidate
|
|
8
|
+
|
|
9
|
+
Use an RC when you want a testable npm package for the next release without updating the `latest` npm dist-tag.
|
|
10
|
+
|
|
11
|
+
1. Make sure `main` contains the intended final version in `package.json` and `package-lock.json`.
|
|
12
|
+
- For the next minor release from `0.1.1`, the base version should be `0.2.0`.
|
|
13
|
+
- For the next major release from `0.2.0`, the base version should be `1.0.0`.
|
|
14
|
+
2. Open GitHub Actions.
|
|
15
|
+
3. Run the `Publish to npm` workflow from `main`.
|
|
16
|
+
4. Choose `rc` for the release type.
|
|
17
|
+
5. The workflow runs verification, changes the package version only inside the workflow to `<base>-rc.<run>.<attempt>`, and publishes it with the npm `rc` dist-tag.
|
|
18
|
+
|
|
19
|
+
Install the latest RC with:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install @anselmdk/feature-spec-md@rc
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Install a specific RC with:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm install @anselmdk/feature-spec-md@0.2.0-rc.123.1
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Repeat the workflow as needed. Each run publishes a new RC and moves the `rc` dist-tag to that version.
|
|
32
|
+
|
|
33
|
+
## Stable Minor Release
|
|
34
|
+
|
|
35
|
+
Use this for backward-compatible features.
|
|
36
|
+
|
|
37
|
+
1. Start from a clean branch based on `main`.
|
|
38
|
+
2. Bump the package version:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npm version minor --no-git-tag-version
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
3. Run verification locally:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
npm run verify
|
|
48
|
+
npm run format
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
4. Open and merge a pull request containing the version bump and any release notes.
|
|
52
|
+
5. After the PR is merged, update local `main` and create a bare semver tag that exactly matches `package.json`:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
git checkout main
|
|
56
|
+
git pull --ff-only
|
|
57
|
+
git tag 0.2.0
|
|
58
|
+
git push origin 0.2.0
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
6. Confirm the `Publish to npm` workflow succeeds.
|
|
62
|
+
|
|
63
|
+
The workflow validates that the tag is a stable semver version and exactly matches `package.json` before publishing to npm with the `latest` dist-tag.
|
|
64
|
+
|
|
65
|
+
## Stable Major Release
|
|
66
|
+
|
|
67
|
+
Use this for breaking changes.
|
|
68
|
+
|
|
69
|
+
1. Document the breaking changes in the release PR.
|
|
70
|
+
2. Bump the package version:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
npm version major --no-git-tag-version
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
3. Run verification locally:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
npm run verify
|
|
80
|
+
npm run format
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
4. Open and merge the release PR.
|
|
84
|
+
5. Tag the merged commit with the exact version, for example:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
git checkout main
|
|
88
|
+
git pull --ff-only
|
|
89
|
+
git tag 1.0.0
|
|
90
|
+
git push origin 1.0.0
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
6. Confirm the `Publish to npm` workflow succeeds.
|
|
94
|
+
|
|
95
|
+
## npm Publishing Setup
|
|
96
|
+
|
|
97
|
+
The publish workflows are ready for npm provenance. The best setup is npm trusted publishing with GitHub Actions OIDC, which avoids long-lived npm publish tokens.
|
|
98
|
+
|
|
99
|
+
On npmjs.com, configure this package with trusted publishing:
|
|
100
|
+
|
|
101
|
+
- Publisher: GitHub Actions
|
|
102
|
+
- Repository owner: `anselmdk`
|
|
103
|
+
- Repository name: `feature-spec-md`
|
|
104
|
+
- Workflow filename: `publish.yml`
|
|
105
|
+
- Allowed action: `npm publish`
|
|
106
|
+
|
|
107
|
+
If trusted publishing is not configured yet, the workflow can still use the `NPM_TOKEN` repository secret. Keep RC and stable publishing in the same workflow because npm trusted publishing allows only one trusted publisher workflow per package.
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# AI Spec Driven Development Flow
|
|
2
|
+
|
|
3
|
+
`feature-spec-md` is built for a loop where specs and tests are both AI-assisted, but the contract between them is explicit and testable.
|
|
4
|
+
|
|
5
|
+
```txt
|
|
6
|
+
AI drafts specs
|
|
7
|
+
-> humans review intent
|
|
8
|
+
-> AI writes tests from stable IDs
|
|
9
|
+
-> tooling checks coverage
|
|
10
|
+
-> implementation follows failing tests
|
|
11
|
+
-> reports show what is implemented
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Install
|
|
15
|
+
|
|
16
|
+
Install the package in the project that owns the specs and tests:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install -D @anselmdk/feature-spec-md
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Add scripts if you want short project commands:
|
|
23
|
+
|
|
24
|
+
```json
|
|
25
|
+
{
|
|
26
|
+
"scripts": {
|
|
27
|
+
"spec": "feature-spec-md check",
|
|
28
|
+
"spec:coverage": "feature-spec-md coverage --fail-on-missing",
|
|
29
|
+
"spec:report": "feature-spec-md report"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Create starter documents:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npx feature-spec-md init --kind model --dir specs
|
|
38
|
+
npx feature-spec-md init --kind feature --dir specs
|
|
39
|
+
npx feature-spec-md init --kind stack --dir specs
|
|
40
|
+
npx feature-spec-md init --kind design --dir specs
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## 1. Ask AI To Draft The Spec Set
|
|
44
|
+
|
|
45
|
+
Give the AI product intent and ask it to create or update:
|
|
46
|
+
|
|
47
|
+
- `*.model.md` for domain vocabulary and global invariants
|
|
48
|
+
- `*.feature.md` for capabilities, rules, and scenarios
|
|
49
|
+
- `*.stack.md` for implementation platform choices
|
|
50
|
+
- `*.design.md` for product, UI, and interaction direction
|
|
51
|
+
|
|
52
|
+
Useful instruction:
|
|
53
|
+
|
|
54
|
+
```txt
|
|
55
|
+
Create feature-spec-md documents for this change. Keep the documents small.
|
|
56
|
+
Use stable uppercase IDs. Put durable behavior in rules. Put testable examples
|
|
57
|
+
in scenarios. Do not include test mappings inside the specs.
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Run:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
npx feature-spec-md check --tests ""
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Use `--tests ""` while the spec set is still being drafted so validation focuses on document structure and graph references.
|
|
67
|
+
|
|
68
|
+
## 2. Review The Specs Before Implementation
|
|
69
|
+
|
|
70
|
+
Review the Markdown as product intent, not as generated test code.
|
|
71
|
+
|
|
72
|
+
Check that:
|
|
73
|
+
|
|
74
|
+
- model terms are clear enough for test authors
|
|
75
|
+
- feature rules are durable product truths
|
|
76
|
+
- scenarios are concrete enough to become executable tests
|
|
77
|
+
- stack choices are specific enough to guide implementation
|
|
78
|
+
- design direction covers the visible behavior users will judge
|
|
79
|
+
|
|
80
|
+
Then run:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
npx feature-spec-md check --require-scenario-coverage=false
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
This keeps the spec set valid while allowing missing tests.
|
|
87
|
+
|
|
88
|
+
## 3. Ask AI To Write Tests From The Specs
|
|
89
|
+
|
|
90
|
+
Give the AI the relevant spec files and tell it to write executable tests that preserve spec IDs in the test source.
|
|
91
|
+
|
|
92
|
+
Useful instruction:
|
|
93
|
+
|
|
94
|
+
```txt
|
|
95
|
+
Write tests from these feature-spec-md specs. Each scenario test must include
|
|
96
|
+
the scenario ID in the test title. Add comments or annotations for covered
|
|
97
|
+
rule IDs and model item IDs. Do not invent IDs that are not in the specs.
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Example:
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
test("ACCOUNT-ACCESS-S001 registered person signs in", async ({ page }) => {
|
|
104
|
+
// Covers ACCOUNT-ACCESS-R001 and ACCOUNT-M001.
|
|
105
|
+
});
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
The test can reference IDs in titles, tags, annotations, comments, or metadata. The important part is that the ID text is present in the test source.
|
|
109
|
+
|
|
110
|
+
## 4. Check Coverage
|
|
111
|
+
|
|
112
|
+
Run:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
npx feature-spec-md coverage
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
The coverage command groups specs by implementation state and shows missing scenario, rule, and model item references.
|
|
119
|
+
|
|
120
|
+
Use this in CI when missing scenario tests should block a change:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
npx feature-spec-md coverage --fail-on-missing
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Use stricter checks when you also want rule coverage to fail CI:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
npx feature-spec-md check --require-rule-coverage=true
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## 5. Generate A Report
|
|
133
|
+
|
|
134
|
+
Run:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
npx feature-spec-md report --out test-results/feature-spec-report/index.html
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
The report is useful as a PR artifact because it shows specs, coverage state, validation issues, and optional screenshot evidence.
|
|
141
|
+
|
|
142
|
+
If your tests produce screenshot manifests, include them:
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
npx feature-spec-md report \
|
|
146
|
+
--screenshots "test-results/spec-report/screenshots-*.json" \
|
|
147
|
+
--out test-results/feature-spec-report/index.html
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Screenshot manifest shape:
|
|
151
|
+
|
|
152
|
+
```json
|
|
153
|
+
{
|
|
154
|
+
"screenshots": [
|
|
155
|
+
{
|
|
156
|
+
"specPath": "specs/account-access.feature.md",
|
|
157
|
+
"line": 24,
|
|
158
|
+
"path": "screenshots/account-access-s001-line-24.png",
|
|
159
|
+
"title": "ACCOUNT-ACCESS-S001:24 Given a registered person is on the sign-in page"
|
|
160
|
+
}
|
|
161
|
+
]
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## 6. Keep The Loop Honest
|
|
166
|
+
|
|
167
|
+
When behavior changes, update specs first, then regenerate or update tests from the changed specs.
|
|
168
|
+
|
|
169
|
+
The expected loop is:
|
|
170
|
+
|
|
171
|
+
```txt
|
|
172
|
+
spec change -> validation -> AI test update -> coverage -> implementation -> report
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
That keeps the AI-generated work anchored to a small, reviewable contract instead of a loose conversation history.
|
package/package.json
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@anselmdk/feature-spec-md",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Markdown
|
|
3
|
+
"version": "0.2.1",
|
|
4
|
+
"description": "Markdown specs for AI-assisted, testable spec driven development across model, feature, stack, and design documents.",
|
|
5
5
|
"type": "module",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/anselmdk/feature-spec-md.git"
|
|
9
|
+
},
|
|
6
10
|
"bin": {
|
|
7
11
|
"feature-spec-md": "./dist/cli.js"
|
|
8
12
|
},
|
|
@@ -11,6 +15,10 @@
|
|
|
11
15
|
"types": "./dist/index.d.ts",
|
|
12
16
|
"import": "./dist/index.js"
|
|
13
17
|
},
|
|
18
|
+
"./specDocuments": {
|
|
19
|
+
"types": "./dist/specDocuments.d.ts",
|
|
20
|
+
"import": "./dist/specDocuments.js"
|
|
21
|
+
},
|
|
14
22
|
"./playwright": {
|
|
15
23
|
"types": "./dist/playwright.d.ts",
|
|
16
24
|
"import": "./dist/playwright.js"
|
|
@@ -20,6 +28,7 @@
|
|
|
20
28
|
"dist",
|
|
21
29
|
"README.md",
|
|
22
30
|
"SPEC_FORMAT.md",
|
|
31
|
+
"docs",
|
|
23
32
|
"templates",
|
|
24
33
|
"examples",
|
|
25
34
|
"LICENSE"
|
|
@@ -49,6 +58,7 @@
|
|
|
49
58
|
"gherkin",
|
|
50
59
|
"playwright",
|
|
51
60
|
"specification",
|
|
61
|
+
"spec-driven-development",
|
|
52
62
|
"testing"
|
|
53
63
|
],
|
|
54
64
|
"license": "MIT",
|