@eddacraft/anvil-adapters 0.1.0
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/AGENTS.md +180 -0
- package/BMAD_ADAPTER_SPEC.md +489 -0
- package/LICENSE +14 -0
- package/README.md +500 -0
- package/dist/aps-markdown/adapter.d.ts +102 -0
- package/dist/aps-markdown/adapter.d.ts.map +1 -0
- package/dist/aps-markdown/adapter.js +351 -0
- package/dist/aps-markdown/index.d.ts +8 -0
- package/dist/aps-markdown/index.d.ts.map +1 -0
- package/dist/aps-markdown/index.js +7 -0
- package/dist/base/file-discovery.d.ts +63 -0
- package/dist/base/file-discovery.d.ts.map +1 -0
- package/dist/base/file-discovery.js +246 -0
- package/dist/base/index.d.ts +10 -0
- package/dist/base/index.d.ts.map +1 -0
- package/dist/base/index.js +9 -0
- package/dist/base/registry.d.ts +155 -0
- package/dist/base/registry.d.ts.map +1 -0
- package/dist/base/registry.js +227 -0
- package/dist/base/testing.d.ts +102 -0
- package/dist/base/testing.d.ts.map +1 -0
- package/dist/base/testing.js +221 -0
- package/dist/base/types.d.ts +255 -0
- package/dist/base/types.d.ts.map +1 -0
- package/dist/base/types.js +78 -0
- package/dist/base/utils.d.ts +127 -0
- package/dist/base/utils.d.ts.map +1 -0
- package/dist/base/utils.js +254 -0
- package/dist/bmad/format-adapter.d.ts +76 -0
- package/dist/bmad/format-adapter.d.ts.map +1 -0
- package/dist/bmad/format-adapter.js +186 -0
- package/dist/bmad/index.d.ts +12 -0
- package/dist/bmad/index.d.ts.map +1 -0
- package/dist/bmad/index.js +10 -0
- package/dist/bmad/parser.d.ts +12 -0
- package/dist/bmad/parser.d.ts.map +1 -0
- package/dist/bmad/parser.js +181 -0
- package/dist/bmad/serializer.d.ts +16 -0
- package/dist/bmad/serializer.d.ts.map +1 -0
- package/dist/bmad/serializer.js +170 -0
- package/dist/bmad/types.d.ts +127 -0
- package/dist/bmad/types.d.ts.map +1 -0
- package/dist/bmad/types.js +47 -0
- package/dist/bmad/utils.d.ts +120 -0
- package/dist/bmad/utils.d.ts.map +1 -0
- package/dist/bmad/utils.js +480 -0
- package/dist/common/index.d.ts +3 -0
- package/dist/common/index.d.ts.map +1 -0
- package/dist/common/index.js +2 -0
- package/dist/common/registry.d.ts +18 -0
- package/dist/common/registry.d.ts.map +1 -0
- package/dist/common/registry.js +58 -0
- package/dist/common/types.d.ts +68 -0
- package/dist/common/types.d.ts.map +1 -0
- package/dist/common/types.js +12 -0
- package/dist/generic/format-adapter.d.ts +64 -0
- package/dist/generic/format-adapter.d.ts.map +1 -0
- package/dist/generic/format-adapter.js +159 -0
- package/dist/generic/index.d.ts +10 -0
- package/dist/generic/index.d.ts.map +1 -0
- package/dist/generic/index.js +9 -0
- package/dist/generic/parser.d.ts +11 -0
- package/dist/generic/parser.d.ts.map +1 -0
- package/dist/generic/parser.js +106 -0
- package/dist/generic/serializer.d.ts +11 -0
- package/dist/generic/serializer.d.ts.map +1 -0
- package/dist/generic/serializer.js +118 -0
- package/dist/generic/types.d.ts +52 -0
- package/dist/generic/types.d.ts.map +1 -0
- package/dist/generic/types.js +6 -0
- package/dist/generic/utils.d.ts +51 -0
- package/dist/generic/utils.d.ts.map +1 -0
- package/dist/generic/utils.js +232 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -0
- package/dist/speckit/export.d.ts +22 -0
- package/dist/speckit/export.d.ts.map +1 -0
- package/dist/speckit/export.js +384 -0
- package/dist/speckit/format-adapter.d.ts +104 -0
- package/dist/speckit/format-adapter.d.ts.map +1 -0
- package/dist/speckit/format-adapter.js +488 -0
- package/dist/speckit/import-v2.d.ts +33 -0
- package/dist/speckit/import-v2.d.ts.map +1 -0
- package/dist/speckit/import-v2.js +361 -0
- package/dist/speckit/import.d.ts +16 -0
- package/dist/speckit/import.d.ts.map +1 -0
- package/dist/speckit/import.js +247 -0
- package/dist/speckit/index.d.ts +5 -0
- package/dist/speckit/index.d.ts.map +1 -0
- package/dist/speckit/index.js +4 -0
- package/dist/speckit/parser.d.ts +28 -0
- package/dist/speckit/parser.d.ts.map +1 -0
- package/dist/speckit/parser.js +283 -0
- package/dist/speckit/parsers/plan-parser.d.ts +71 -0
- package/dist/speckit/parsers/plan-parser.d.ts.map +1 -0
- package/dist/speckit/parsers/plan-parser.js +216 -0
- package/dist/speckit/parsers/spec-parser.d.ts +67 -0
- package/dist/speckit/parsers/spec-parser.d.ts.map +1 -0
- package/dist/speckit/parsers/spec-parser.js +255 -0
- package/dist/speckit/parsers/tasks-parser.d.ts +57 -0
- package/dist/speckit/parsers/tasks-parser.d.ts.map +1 -0
- package/dist/speckit/parsers/tasks-parser.js +157 -0
- package/package.json +23 -0
- package/project.json +29 -0
- package/src/__tests__/adapter-edge-cases.test.ts +937 -0
- package/src/__tests__/bmad-format-adapter.test.ts +1470 -0
- package/src/__tests__/fixtures/aps/expected-output.json +83 -0
- package/src/__tests__/fixtures/bmad/invalid-malformed-yaml.md +16 -0
- package/src/__tests__/fixtures/bmad/invalid-no-requirements.md +23 -0
- package/src/__tests__/fixtures/bmad/invalid-only-yaml.md +16 -0
- package/src/__tests__/fixtures/bmad/invalid-too-short.md +3 -0
- package/src/__tests__/fixtures/bmad/invalid-wrong-format.md +40 -0
- package/src/__tests__/fixtures/bmad/valid-agent.md +27 -0
- package/src/__tests__/fixtures/bmad/valid-architecture.md +116 -0
- package/src/__tests__/fixtures/bmad/valid-complex-prd.md +161 -0
- package/src/__tests__/fixtures/bmad/valid-epic.md +73 -0
- package/src/__tests__/fixtures/bmad/valid-minimal-prd.md +19 -0
- package/src/__tests__/fixtures/bmad/valid-prd.md +107 -0
- package/src/__tests__/fixtures/bmad/valid-story.md +107 -0
- package/src/__tests__/fixtures/bmad/valid-task.md +79 -0
- package/src/__tests__/fixtures/bmad/valid-v6-prd.md +35 -0
- package/src/__tests__/fixtures/generic/plan-detailed.md +39 -0
- package/src/__tests__/fixtures/generic/prd-simple.md +27 -0
- package/src/__tests__/fixtures/generic/rfc-example.md +26 -0
- package/src/__tests__/fixtures/generic/todo-list.md +23 -0
- package/src/__tests__/fixtures/speckit/sample-plan.md +63 -0
- package/src/__tests__/fixtures/speckit/sample-spec-namespaced.md +50 -0
- package/src/__tests__/fixtures/speckit/sample-spec.md +105 -0
- package/src/__tests__/fixtures/speckit/sample-tasks.md +87 -0
- package/src/__tests__/fixtures/speckit-official/auth-feature/plan.md +272 -0
- package/src/__tests__/fixtures/speckit-official/auth-feature/spec.md +149 -0
- package/src/__tests__/fixtures/speckit-official/auth-feature/tasks.md +169 -0
- package/src/__tests__/generic-format-adapter.test.ts +398 -0
- package/src/__tests__/speckit-export.test.ts +233 -0
- package/src/__tests__/speckit-format-adapter.test.ts +832 -0
- package/src/__tests__/speckit-import-v2.test.ts +253 -0
- package/src/__tests__/speckit-import.test.ts +209 -0
- package/src/__tests__/speckit-parser.test.ts +219 -0
- package/src/__tests__/speckit-spec-parser.test.ts +120 -0
- package/src/aps-markdown/__tests__/__fixtures__/simple-leaf.aps.md +17 -0
- package/src/aps-markdown/__tests__/adapter.test.ts +393 -0
- package/src/aps-markdown/adapter.ts +455 -0
- package/src/aps-markdown/index.ts +8 -0
- package/src/base/__tests__/registry.test.ts +515 -0
- package/src/base/file-discovery.ts +305 -0
- package/src/base/index.ts +10 -0
- package/src/base/registry.ts +263 -0
- package/src/base/testing.ts +334 -0
- package/src/base/types.ts +342 -0
- package/src/base/utils.ts +306 -0
- package/src/bmad/format-adapter.ts +227 -0
- package/src/bmad/index.ts +21 -0
- package/src/bmad/parser.ts +224 -0
- package/src/bmad/serializer.ts +206 -0
- package/src/bmad/types.ts +135 -0
- package/src/bmad/utils.ts +575 -0
- package/src/common/index.ts +2 -0
- package/src/common/registry.ts +72 -0
- package/src/common/types.ts +84 -0
- package/src/generic/__tests__/serializer.test.ts +167 -0
- package/src/generic/format-adapter.ts +200 -0
- package/src/generic/index.ts +11 -0
- package/src/generic/parser.ts +129 -0
- package/src/generic/serializer.ts +134 -0
- package/src/generic/types.ts +53 -0
- package/src/generic/utils.ts +270 -0
- package/src/index.ts +48 -0
- package/src/speckit/export.ts +489 -0
- package/src/speckit/format-adapter.ts +595 -0
- package/src/speckit/import-v2.ts +445 -0
- package/src/speckit/import.ts +305 -0
- package/src/speckit/index.ts +4 -0
- package/src/speckit/parser.ts +351 -0
- package/src/speckit/parsers/plan-parser.ts +342 -0
- package/src/speckit/parsers/spec-parser.ts +379 -0
- package/src/speckit/parsers/tasks-parser.ts +246 -0
- package/tsconfig.json +26 -0
- package/tsconfig.lib.json +21 -0
- package/tsconfig.lib.tsbuildinfo +1 -0
- package/tsconfig.spec.json +9 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/vitest.config.ts +14 -0
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import { validateRelativePath } from '@eddacraft/anvil-core';
|
|
2
|
+
/**
|
|
3
|
+
* Validate and sanitize a file path to prevent path traversal attacks.
|
|
4
|
+
* Returns undefined if the path is invalid (absolute, contains null bytes, or escapes parent directory).
|
|
5
|
+
*/
|
|
6
|
+
function safePath(raw) {
|
|
7
|
+
if (!raw)
|
|
8
|
+
return undefined;
|
|
9
|
+
try {
|
|
10
|
+
return validateRelativePath(raw);
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export class SpecKitParser {
|
|
17
|
+
static SPEC_SECTIONS = {
|
|
18
|
+
intent: ['intent', 'purpose', 'objective'],
|
|
19
|
+
overview: ['overview', 'summary', 'description'],
|
|
20
|
+
goals: ['goals', 'objectives', 'outcomes'],
|
|
21
|
+
requirements: ['requirements', 'prerequisites', 'dependencies'],
|
|
22
|
+
changes: ['changes', 'modifications', 'alterations', 'tasks'],
|
|
23
|
+
};
|
|
24
|
+
/** Maximum input size for SpecKit parsing (2MB) */
|
|
25
|
+
static MAX_INPUT_SIZE = 2 * 1024 * 1024;
|
|
26
|
+
parseSpecMarkdown(content) {
|
|
27
|
+
if (content.length > SpecKitParser.MAX_INPUT_SIZE) {
|
|
28
|
+
throw new Error(`Input exceeds maximum size of ${SpecKitParser.MAX_INPUT_SIZE} bytes`);
|
|
29
|
+
}
|
|
30
|
+
const sections = this.parseMarkdownSections(content);
|
|
31
|
+
const result = {
|
|
32
|
+
metadata: {},
|
|
33
|
+
};
|
|
34
|
+
for (const section of sections) {
|
|
35
|
+
this.extractSectionData(section, result);
|
|
36
|
+
}
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
parseMarkdownSections(content) {
|
|
40
|
+
const lines = content.split('\n');
|
|
41
|
+
const sections = [];
|
|
42
|
+
const stack = [];
|
|
43
|
+
let currentContent = [];
|
|
44
|
+
for (const line of lines) {
|
|
45
|
+
const headerMatch = line.match(/^(#{1,6})\s+(.+)$/);
|
|
46
|
+
if (headerMatch) {
|
|
47
|
+
if (currentContent.length > 0 && stack.length > 0) {
|
|
48
|
+
stack[stack.length - 1].content = currentContent.join('\n').trim();
|
|
49
|
+
}
|
|
50
|
+
const level = headerMatch[1].length;
|
|
51
|
+
const title = headerMatch[2].trim();
|
|
52
|
+
const newSection = {
|
|
53
|
+
title,
|
|
54
|
+
level,
|
|
55
|
+
content: '',
|
|
56
|
+
subsections: [],
|
|
57
|
+
};
|
|
58
|
+
while (stack.length > 0 && stack[stack.length - 1].level >= level) {
|
|
59
|
+
stack.pop();
|
|
60
|
+
}
|
|
61
|
+
if (stack.length === 0) {
|
|
62
|
+
sections.push(newSection);
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
stack[stack.length - 1].subsections.push(newSection);
|
|
66
|
+
}
|
|
67
|
+
stack.push(newSection);
|
|
68
|
+
currentContent = [];
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
currentContent.push(line);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (currentContent.length > 0 && stack.length > 0) {
|
|
75
|
+
stack[stack.length - 1].content = currentContent.join('\n').trim();
|
|
76
|
+
}
|
|
77
|
+
return sections;
|
|
78
|
+
}
|
|
79
|
+
extractSectionData(section, result) {
|
|
80
|
+
const sectionTitleLower = section.title.toLowerCase();
|
|
81
|
+
let sectionWasProcessed = false;
|
|
82
|
+
for (const [key, aliases] of Object.entries(SpecKitParser.SPEC_SECTIONS)) {
|
|
83
|
+
// Use word boundary matching to avoid partial matches (e.g., "objective" shouldn't match "objectives")
|
|
84
|
+
if (aliases.some((alias) => {
|
|
85
|
+
const regex = new RegExp(`\\b${alias}\\b`, 'i');
|
|
86
|
+
return regex.test(sectionTitleLower);
|
|
87
|
+
})) {
|
|
88
|
+
sectionWasProcessed = true;
|
|
89
|
+
switch (key) {
|
|
90
|
+
case 'intent':
|
|
91
|
+
// For intent, get only the paragraph text, not list items
|
|
92
|
+
result.intent = this.extractParagraphText(section.content);
|
|
93
|
+
break;
|
|
94
|
+
case 'overview':
|
|
95
|
+
// For overview, get only the paragraph text, not list items
|
|
96
|
+
result.overview = this.extractParagraphText(section.content);
|
|
97
|
+
break;
|
|
98
|
+
case 'goals':
|
|
99
|
+
result.goals = this.parseListItems(section.content);
|
|
100
|
+
break;
|
|
101
|
+
case 'requirements':
|
|
102
|
+
result.requirements = this.parseListItems(section.content);
|
|
103
|
+
break;
|
|
104
|
+
case 'changes':
|
|
105
|
+
// parseChanges handles all nested subsections, so don't recurse into them
|
|
106
|
+
result.changes = this.parseChanges(section);
|
|
107
|
+
return; // Exit early - changes section is fully processed
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
// Only recurse into subsections if this section wasn't fully processed by a specialized method
|
|
112
|
+
// or if the section didn't match any known section types
|
|
113
|
+
if (!sectionWasProcessed) {
|
|
114
|
+
for (const subsection of section.subsections) {
|
|
115
|
+
this.extractSectionData(subsection, result);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
extractParagraphText(content) {
|
|
120
|
+
const lines = content.split('\n');
|
|
121
|
+
const paragraphLines = [];
|
|
122
|
+
let hasContent = false;
|
|
123
|
+
for (const line of lines) {
|
|
124
|
+
const trimmedLine = line.trim();
|
|
125
|
+
// Stop at list items
|
|
126
|
+
if (trimmedLine.match(/^[-*+]\s+/) || trimmedLine.match(/^\d+\.\s+/)) {
|
|
127
|
+
break;
|
|
128
|
+
}
|
|
129
|
+
// Add non-empty lines
|
|
130
|
+
if (trimmedLine) {
|
|
131
|
+
paragraphLines.push(trimmedLine);
|
|
132
|
+
hasContent = true;
|
|
133
|
+
}
|
|
134
|
+
else if (hasContent && paragraphLines.length > 0) {
|
|
135
|
+
// Stop at empty line after we've collected some content
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return paragraphLines.join(' ').trim();
|
|
140
|
+
}
|
|
141
|
+
parseListItems(content) {
|
|
142
|
+
const lines = content.split('\n');
|
|
143
|
+
const items = [];
|
|
144
|
+
let currentItem = '';
|
|
145
|
+
for (const line of lines) {
|
|
146
|
+
const listMatch = line.match(/^[\s]*[-*+]\s+(.+)$/);
|
|
147
|
+
const numberedMatch = line.match(/^[\s]*\d+\.\s+(.+)$/);
|
|
148
|
+
if (listMatch || numberedMatch) {
|
|
149
|
+
if (currentItem) {
|
|
150
|
+
items.push(currentItem.trim());
|
|
151
|
+
}
|
|
152
|
+
currentItem = (listMatch?.[1] || numberedMatch?.[1] || '').trim();
|
|
153
|
+
}
|
|
154
|
+
else if (currentItem && line.trim()) {
|
|
155
|
+
currentItem += ' ' + line.trim();
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
if (currentItem) {
|
|
159
|
+
items.push(currentItem.trim());
|
|
160
|
+
}
|
|
161
|
+
return items;
|
|
162
|
+
}
|
|
163
|
+
parseChanges(section) {
|
|
164
|
+
const changes = [];
|
|
165
|
+
// Process direct subsections
|
|
166
|
+
for (const subsection of section.subsections) {
|
|
167
|
+
// Check if this subsection is a grouping section (like "Files to Create")
|
|
168
|
+
const subsectionTitleLower = subsection.title.toLowerCase();
|
|
169
|
+
const isGroupingSection = subsectionTitleLower.includes('files to') ||
|
|
170
|
+
subsectionTitleLower.includes('configuration') ||
|
|
171
|
+
subsectionTitleLower.includes('dependencies') ||
|
|
172
|
+
subsectionTitleLower.includes('scripts');
|
|
173
|
+
if (isGroupingSection && subsection.subsections.length > 0) {
|
|
174
|
+
// Process nested subsections within grouping sections
|
|
175
|
+
for (const nestedSection of subsection.subsections) {
|
|
176
|
+
const change = this.parseChangeSection(nestedSection);
|
|
177
|
+
if (change) {
|
|
178
|
+
changes.push(change);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
// Process as a direct change section
|
|
184
|
+
const change = this.parseChangeSection(subsection);
|
|
185
|
+
if (change) {
|
|
186
|
+
changes.push(change);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
// Fallback to parsing list items if no subsections found
|
|
191
|
+
if (changes.length === 0) {
|
|
192
|
+
const listItems = this.parseListItems(section.content);
|
|
193
|
+
for (const item of listItems) {
|
|
194
|
+
const change = this.parseChangeFromListItem(item);
|
|
195
|
+
if (change) {
|
|
196
|
+
changes.push(change);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return changes;
|
|
201
|
+
}
|
|
202
|
+
parseChangeSection(section) {
|
|
203
|
+
const titleLower = section.title.toLowerCase();
|
|
204
|
+
let type = 'script_execute';
|
|
205
|
+
if (titleLower.includes('create') || titleLower.includes('new')) {
|
|
206
|
+
type = 'file_create';
|
|
207
|
+
}
|
|
208
|
+
else if (titleLower.includes('update') || titleLower.includes('modify')) {
|
|
209
|
+
type = 'file_update';
|
|
210
|
+
}
|
|
211
|
+
else if (titleLower.includes('delete') || titleLower.includes('remove')) {
|
|
212
|
+
type = 'file_delete';
|
|
213
|
+
}
|
|
214
|
+
else if (titleLower.includes('config')) {
|
|
215
|
+
type = 'config_update';
|
|
216
|
+
}
|
|
217
|
+
else if (titleLower.includes('dependency') || titleLower.includes('package')) {
|
|
218
|
+
if (titleLower.includes('add') || titleLower.includes('install')) {
|
|
219
|
+
type = 'dependency_add';
|
|
220
|
+
}
|
|
221
|
+
else if (titleLower.includes('remove') || titleLower.includes('uninstall')) {
|
|
222
|
+
type = 'dependency_remove';
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
type = 'dependency_update';
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
// Look for path in title first, then in content
|
|
229
|
+
let pathMatch = section.title.match(/`([^`]+)`/);
|
|
230
|
+
if (!pathMatch && section.content) {
|
|
231
|
+
// Look for path in the first line of content
|
|
232
|
+
const firstLine = section.content.split('\n')[0];
|
|
233
|
+
pathMatch = firstLine.match(/`([^`]+)`/);
|
|
234
|
+
}
|
|
235
|
+
const path = safePath(pathMatch?.[1]);
|
|
236
|
+
const codeBlockMatch = section.content.match(/```[\w]*\n([\s\S]*?)```/);
|
|
237
|
+
const content = codeBlockMatch ? codeBlockMatch[1].trim() : undefined;
|
|
238
|
+
return {
|
|
239
|
+
type,
|
|
240
|
+
description: section.title,
|
|
241
|
+
path,
|
|
242
|
+
content,
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
parseChangeFromListItem(item) {
|
|
246
|
+
const itemLower = item.toLowerCase();
|
|
247
|
+
let type = 'script_execute';
|
|
248
|
+
// Check for script execution patterns first
|
|
249
|
+
if (itemLower.includes('run') ||
|
|
250
|
+
itemLower.includes('execute') ||
|
|
251
|
+
itemLower.includes('script')) {
|
|
252
|
+
type = 'script_execute';
|
|
253
|
+
}
|
|
254
|
+
else if (itemLower.includes('create') || itemLower.includes('new file')) {
|
|
255
|
+
type = 'file_create';
|
|
256
|
+
}
|
|
257
|
+
else if (itemLower.includes('delete') || itemLower.includes('remove file')) {
|
|
258
|
+
type = 'file_delete';
|
|
259
|
+
}
|
|
260
|
+
else if (itemLower.includes('update dependency')) {
|
|
261
|
+
type = 'dependency_update';
|
|
262
|
+
}
|
|
263
|
+
else if (itemLower.includes('install') || itemLower.includes('add dependency')) {
|
|
264
|
+
type = 'dependency_add';
|
|
265
|
+
}
|
|
266
|
+
else if (itemLower.includes('uninstall') || itemLower.includes('remove dependency')) {
|
|
267
|
+
type = 'dependency_remove';
|
|
268
|
+
}
|
|
269
|
+
else if (itemLower.includes('update') || itemLower.includes('modify')) {
|
|
270
|
+
type = 'file_update';
|
|
271
|
+
}
|
|
272
|
+
else if (itemLower.includes('config')) {
|
|
273
|
+
type = 'config_update';
|
|
274
|
+
}
|
|
275
|
+
const pathMatch = item.match(/`([^`]+)`/);
|
|
276
|
+
const path = safePath(pathMatch?.[1]);
|
|
277
|
+
return {
|
|
278
|
+
type,
|
|
279
|
+
description: item,
|
|
280
|
+
path,
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parser for official GitHub Spec-Kit plan.md format
|
|
3
|
+
*
|
|
4
|
+
* Plan.md focuses on HOW (technical implementation):
|
|
5
|
+
* - Summary
|
|
6
|
+
* - Technical Context (stack, dependencies, constraints)
|
|
7
|
+
* - Constitution Check (compliance with project principles)
|
|
8
|
+
* - Project Structure (directories, files)
|
|
9
|
+
* - Implementation Details (API endpoints, database schema, etc.)
|
|
10
|
+
* - Complexity Tracking (design decisions)
|
|
11
|
+
*/
|
|
12
|
+
interface PlanMetadata {
|
|
13
|
+
feature?: string;
|
|
14
|
+
branch?: string;
|
|
15
|
+
date?: string;
|
|
16
|
+
spec?: string;
|
|
17
|
+
[key: string]: unknown;
|
|
18
|
+
}
|
|
19
|
+
interface TechnicalContext {
|
|
20
|
+
language?: string;
|
|
21
|
+
dependencies?: string[];
|
|
22
|
+
storage?: string;
|
|
23
|
+
testing?: string;
|
|
24
|
+
target?: string;
|
|
25
|
+
type?: string;
|
|
26
|
+
performanceGoals?: string[];
|
|
27
|
+
constraints?: string[];
|
|
28
|
+
scale?: string;
|
|
29
|
+
}
|
|
30
|
+
interface ConstitutionCheck {
|
|
31
|
+
modularity?: boolean | string;
|
|
32
|
+
testability?: boolean | string;
|
|
33
|
+
security?: boolean | string;
|
|
34
|
+
performance?: boolean | string;
|
|
35
|
+
maintainability?: boolean | string;
|
|
36
|
+
documentation?: boolean | string;
|
|
37
|
+
[key: string]: boolean | string | undefined;
|
|
38
|
+
}
|
|
39
|
+
interface ProjectStructure {
|
|
40
|
+
documentation?: string;
|
|
41
|
+
sourceCode?: string;
|
|
42
|
+
selectedOption?: string;
|
|
43
|
+
}
|
|
44
|
+
interface ComplexityDecision {
|
|
45
|
+
title: string;
|
|
46
|
+
problem: string;
|
|
47
|
+
solution: string;
|
|
48
|
+
justification: string;
|
|
49
|
+
}
|
|
50
|
+
export interface ParsedPlan {
|
|
51
|
+
metadata: PlanMetadata;
|
|
52
|
+
summary: string;
|
|
53
|
+
technicalContext: TechnicalContext;
|
|
54
|
+
constitutionCheck: ConstitutionCheck;
|
|
55
|
+
projectStructure: ProjectStructure;
|
|
56
|
+
implementationDetails: Map<string, string>;
|
|
57
|
+
complexityDecisions: ComplexityDecision[];
|
|
58
|
+
}
|
|
59
|
+
export declare class PlanParser {
|
|
60
|
+
parsePlan(content: string): ParsedPlan;
|
|
61
|
+
private extractMetadata;
|
|
62
|
+
private extractSummary;
|
|
63
|
+
private parseTechnicalContext;
|
|
64
|
+
private parseConstitutionCheck;
|
|
65
|
+
private parseProjectStructure;
|
|
66
|
+
private parseImplementationDetails;
|
|
67
|
+
private parseComplexityDecisions;
|
|
68
|
+
private parseComplexityDecision;
|
|
69
|
+
}
|
|
70
|
+
export {};
|
|
71
|
+
//# sourceMappingURL=plan-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan-parser.d.ts","sourceRoot":"","sources":["../../../src/speckit/parsers/plan-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,UAAU,YAAY;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,UAAU,gBAAgB;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,iBAAiB;IACzB,UAAU,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC9B,WAAW,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC/B,QAAQ,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC5B,WAAW,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC/B,eAAe,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACnC,aAAa,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IACjC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;CAC7C;AAED,UAAU,gBAAgB;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,UAAU,kBAAkB;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,YAAY,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,iBAAiB,EAAE,iBAAiB,CAAC;IACrC,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,qBAAqB,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3C,mBAAmB,EAAE,kBAAkB,EAAE,CAAC;CAC3C;AAED,qBAAa,UAAU;IACrB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU;IAmCtC,OAAO,CAAC,eAAe;IAqBvB,OAAO,CAAC,cAAc;IAKtB,OAAO,CAAC,qBAAqB;IAiF7B,OAAO,CAAC,sBAAsB;IA4B9B,OAAO,CAAC,qBAAqB;IAoC7B,OAAO,CAAC,0BAA0B;IA2BlC,OAAO,CAAC,wBAAwB;IAyBhC,OAAO,CAAC,uBAAuB;CAiBhC"}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parser for official GitHub Spec-Kit plan.md format
|
|
3
|
+
*
|
|
4
|
+
* Plan.md focuses on HOW (technical implementation):
|
|
5
|
+
* - Summary
|
|
6
|
+
* - Technical Context (stack, dependencies, constraints)
|
|
7
|
+
* - Constitution Check (compliance with project principles)
|
|
8
|
+
* - Project Structure (directories, files)
|
|
9
|
+
* - Implementation Details (API endpoints, database schema, etc.)
|
|
10
|
+
* - Complexity Tracking (design decisions)
|
|
11
|
+
*/
|
|
12
|
+
export class PlanParser {
|
|
13
|
+
parsePlan(content) {
|
|
14
|
+
const result = {
|
|
15
|
+
metadata: {},
|
|
16
|
+
summary: '',
|
|
17
|
+
technicalContext: {},
|
|
18
|
+
constitutionCheck: {},
|
|
19
|
+
projectStructure: {},
|
|
20
|
+
implementationDetails: new Map(),
|
|
21
|
+
complexityDecisions: [],
|
|
22
|
+
};
|
|
23
|
+
// Extract metadata from first section
|
|
24
|
+
result.metadata = this.extractMetadata(content);
|
|
25
|
+
// Parse summary section
|
|
26
|
+
result.summary = this.extractSummary(content);
|
|
27
|
+
// Parse technical context
|
|
28
|
+
result.technicalContext = this.parseTechnicalContext(content);
|
|
29
|
+
// Parse constitution check
|
|
30
|
+
result.constitutionCheck = this.parseConstitutionCheck(content);
|
|
31
|
+
// Parse project structure
|
|
32
|
+
result.projectStructure = this.parseProjectStructure(content);
|
|
33
|
+
// Parse implementation details (flexible sections)
|
|
34
|
+
result.implementationDetails = this.parseImplementationDetails(content);
|
|
35
|
+
// Parse complexity tracking
|
|
36
|
+
result.complexityDecisions = this.parseComplexityDecisions(content);
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
extractMetadata(content) {
|
|
40
|
+
const metadata = {};
|
|
41
|
+
// Extract title (# Implementation Plan: ...)
|
|
42
|
+
const titleMatch = content.match(/^#\s+Implementation Plan:\s+(.+)$/m);
|
|
43
|
+
if (titleMatch) {
|
|
44
|
+
metadata.feature = titleMatch[1].trim();
|
|
45
|
+
}
|
|
46
|
+
// Extract bold key-value pairs
|
|
47
|
+
const metadataRegex = /\*\*([^*]+)\*\*:\s*(?:`([^`\n]+)`|\[([^\]]+)\]\(([^)]+)\)|([^\n]+))/g;
|
|
48
|
+
let match;
|
|
49
|
+
while ((match = metadataRegex.exec(content)) !== null) {
|
|
50
|
+
const key = match[1].trim().toLowerCase().replace(/\s+/g, '_');
|
|
51
|
+
const value = match[2] || match[3] || match[5] || '';
|
|
52
|
+
metadata[key] = value.trim();
|
|
53
|
+
}
|
|
54
|
+
return metadata;
|
|
55
|
+
}
|
|
56
|
+
extractSummary(content) {
|
|
57
|
+
const summaryMatch = content.match(/##\s+Summary\s+([\s\S]*?)(?=\n##\s|$)/i);
|
|
58
|
+
return summaryMatch?.[1]?.trim() || '';
|
|
59
|
+
}
|
|
60
|
+
parseTechnicalContext(content) {
|
|
61
|
+
const context = {};
|
|
62
|
+
const contextMatch = content.match(/##\s+Technical Context([\s\S]*?)(?=\n##\s|$)/i);
|
|
63
|
+
if (!contextMatch) {
|
|
64
|
+
return context;
|
|
65
|
+
}
|
|
66
|
+
const contextSection = contextMatch[1];
|
|
67
|
+
// Parse bullet points with key-value pairs
|
|
68
|
+
const languageMatch = contextSection.match(/[-*]\s+\*\*Language\/Version\*\*:\s+(.+)/i);
|
|
69
|
+
if (languageMatch) {
|
|
70
|
+
context.language = languageMatch[1].trim();
|
|
71
|
+
}
|
|
72
|
+
const storageMatch = contextSection.match(/[-*]\s+\*\*Storage\*\*:\s+(.+)/i);
|
|
73
|
+
if (storageMatch) {
|
|
74
|
+
context.storage = storageMatch[1].trim();
|
|
75
|
+
}
|
|
76
|
+
const testingMatch = contextSection.match(/[-*]\s+\*\*Testing\*\*:\s+(.+)/i);
|
|
77
|
+
if (testingMatch) {
|
|
78
|
+
context.testing = testingMatch[1].trim();
|
|
79
|
+
}
|
|
80
|
+
const targetMatch = contextSection.match(/[-*]\s+\*\*Target\*\*:\s+(.+)/i);
|
|
81
|
+
if (targetMatch) {
|
|
82
|
+
context.target = targetMatch[1].trim();
|
|
83
|
+
}
|
|
84
|
+
const typeMatch = contextSection.match(/[-*]\s+\*\*Type\*\*:\s+(.+)/i);
|
|
85
|
+
if (typeMatch) {
|
|
86
|
+
context.type = typeMatch[1].trim();
|
|
87
|
+
}
|
|
88
|
+
const scaleMatch = contextSection.match(/[-*]\s+\*\*Scale\*\*:\s+(.+)/i);
|
|
89
|
+
if (scaleMatch) {
|
|
90
|
+
context.scale = scaleMatch[1].trim();
|
|
91
|
+
}
|
|
92
|
+
// Parse dependencies (multi-line list)
|
|
93
|
+
const depsMatch = contextSection.match(/[-*]\s+\*\*Dependencies\*\*:\s+([\s\S]*?)(?=\n[-*]\s+\*\*|$)/i);
|
|
94
|
+
if (depsMatch) {
|
|
95
|
+
const deps = depsMatch[1]
|
|
96
|
+
.split(/\n\s*[-*]\s+/)
|
|
97
|
+
.map((d) => d.trim())
|
|
98
|
+
.filter((d) => d.length > 0);
|
|
99
|
+
context.dependencies = deps;
|
|
100
|
+
}
|
|
101
|
+
// Parse performance goals
|
|
102
|
+
const perfMatch = contextSection.match(/[-*]\s+\*\*Performance Goals\*\*:\s+([\s\S]*?)(?=\n[-*]\s+\*\*|$)/i);
|
|
103
|
+
if (perfMatch) {
|
|
104
|
+
const goals = perfMatch[1]
|
|
105
|
+
.split(/\n\s*[-*]\s+/)
|
|
106
|
+
.map((g) => g.trim())
|
|
107
|
+
.filter((g) => g.length > 0);
|
|
108
|
+
context.performanceGoals = goals;
|
|
109
|
+
}
|
|
110
|
+
// Parse constraints
|
|
111
|
+
const constraintsMatch = contextSection.match(/[-*]\s+\*\*Constraints\*\*:\s+([\s\S]*?)(?=\n[-*]\s+\*\*|$)/i);
|
|
112
|
+
if (constraintsMatch) {
|
|
113
|
+
const constraints = constraintsMatch[1]
|
|
114
|
+
.split(/\n\s*[-*]\s+/)
|
|
115
|
+
.map((c) => c.trim())
|
|
116
|
+
.filter((c) => c.length > 0);
|
|
117
|
+
context.constraints = constraints;
|
|
118
|
+
}
|
|
119
|
+
return context;
|
|
120
|
+
}
|
|
121
|
+
parseConstitutionCheck(content) {
|
|
122
|
+
const check = {};
|
|
123
|
+
const checkMatch = content.match(/##\s+Constitution Check([\s\S]*?)(?=\n##\s|$)/i);
|
|
124
|
+
if (!checkMatch) {
|
|
125
|
+
return check;
|
|
126
|
+
}
|
|
127
|
+
const checkSection = checkMatch[1];
|
|
128
|
+
// Parse ✅ or ❌ followed by **Key**: Description
|
|
129
|
+
const checkRegex = /([✅❌✓✗×])\s+\*\*([^*]+)\*\*:\s+(.+)/g;
|
|
130
|
+
let match;
|
|
131
|
+
while ((match = checkRegex.exec(checkSection)) !== null) {
|
|
132
|
+
const status = match[1];
|
|
133
|
+
const key = match[2].trim().toLowerCase().replace(/\s+/g, '_');
|
|
134
|
+
const description = match[3].trim();
|
|
135
|
+
// Check if it passes or fails
|
|
136
|
+
const passes = status === '✅' || status === '✓';
|
|
137
|
+
check[key] = passes ? description : `FAIL: ${description}`;
|
|
138
|
+
}
|
|
139
|
+
return check;
|
|
140
|
+
}
|
|
141
|
+
parseProjectStructure(content) {
|
|
142
|
+
const structure = {};
|
|
143
|
+
const structureMatch = content.match(/##\s+Project Structure([\s\S]*?)(?=\n##\s|$)/i);
|
|
144
|
+
if (!structureMatch) {
|
|
145
|
+
return structure;
|
|
146
|
+
}
|
|
147
|
+
const structureSection = structureMatch[1];
|
|
148
|
+
// Extract documentation structure (code block)
|
|
149
|
+
const docsMatch = structureSection.match(/###\s+Documentation[\s\S]*?```[\s\S]*?\n([\s\S]*?)```/i);
|
|
150
|
+
if (docsMatch) {
|
|
151
|
+
structure.documentation = docsMatch[1].trim();
|
|
152
|
+
}
|
|
153
|
+
// Extract source code structure
|
|
154
|
+
const sourceMatch = structureSection.match(/###\s+Source Code Structure[\s\S]*?```[\s\S]*?\n([\s\S]*?)```/i);
|
|
155
|
+
if (sourceMatch) {
|
|
156
|
+
structure.sourceCode = sourceMatch[1].trim();
|
|
157
|
+
}
|
|
158
|
+
// Check for "Selected" or "(Selected)" marker
|
|
159
|
+
const selectedMatch = structureSection.match(/####\s+Option \d+:([^(]+)\(Selected\)/i);
|
|
160
|
+
if (selectedMatch) {
|
|
161
|
+
structure.selectedOption = selectedMatch[1].trim();
|
|
162
|
+
}
|
|
163
|
+
return structure;
|
|
164
|
+
}
|
|
165
|
+
parseImplementationDetails(content) {
|
|
166
|
+
const details = new Map();
|
|
167
|
+
// Find "Implementation Details" section
|
|
168
|
+
const detailsMatch = content.match(/##\s+Implementation Details([\s\S]*?)(?=\n##\s+Complexity|$)/i);
|
|
169
|
+
if (!detailsMatch) {
|
|
170
|
+
return details;
|
|
171
|
+
}
|
|
172
|
+
const detailsSection = detailsMatch[1];
|
|
173
|
+
// Split by ### headers
|
|
174
|
+
const subsectionRegex = /###\s+([^\n]+)\n([\s\S]*?)(?=\n###|$)/g;
|
|
175
|
+
let match;
|
|
176
|
+
while ((match = subsectionRegex.exec(detailsSection)) !== null) {
|
|
177
|
+
const title = match[1].trim();
|
|
178
|
+
const content = match[2].trim();
|
|
179
|
+
details.set(title, content);
|
|
180
|
+
}
|
|
181
|
+
return details;
|
|
182
|
+
}
|
|
183
|
+
parseComplexityDecisions(content) {
|
|
184
|
+
const decisions = [];
|
|
185
|
+
// Find "Complexity Tracking" section
|
|
186
|
+
const complexityMatch = content.match(/##\s+Complexity Tracking([\s\S]*?)$/i);
|
|
187
|
+
if (!complexityMatch) {
|
|
188
|
+
return decisions;
|
|
189
|
+
}
|
|
190
|
+
const complexitySection = complexityMatch[1];
|
|
191
|
+
// Split by ### headers (each decision)
|
|
192
|
+
const decisionBlocks = complexitySection.split(/###\s+/).slice(1);
|
|
193
|
+
for (const block of decisionBlocks) {
|
|
194
|
+
const decision = this.parseComplexityDecision(block);
|
|
195
|
+
if (decision) {
|
|
196
|
+
decisions.push(decision);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return decisions;
|
|
200
|
+
}
|
|
201
|
+
parseComplexityDecision(block) {
|
|
202
|
+
const titleMatch = block.match(/^([^\n]+)/);
|
|
203
|
+
const problemMatch = block.match(/\*\*Problem\*\*:\s+(.+?)(?=\n\*\*|$)/s);
|
|
204
|
+
const solutionMatch = block.match(/\*\*Solution\*\*:\s+([\s\S]+?)(?=\n\*\*|$)/);
|
|
205
|
+
const justificationMatch = block.match(/\*\*Justification\*\*:\s+([\s\S]+?)(?=\n###|$)/);
|
|
206
|
+
if (!titleMatch) {
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
209
|
+
return {
|
|
210
|
+
title: titleMatch[1].trim(),
|
|
211
|
+
problem: problemMatch?.[1]?.trim() || '',
|
|
212
|
+
solution: solutionMatch?.[1]?.trim() || '',
|
|
213
|
+
justification: justificationMatch?.[1]?.trim() || '',
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parser for official GitHub Spec-Kit spec.md format
|
|
3
|
+
*
|
|
4
|
+
* Spec.md focuses on WHAT and WHY (not HOW):
|
|
5
|
+
* - Feature metadata
|
|
6
|
+
* - User Scenarios & Testing (prioritized user stories)
|
|
7
|
+
* - Requirements (functional requirements, key entities)
|
|
8
|
+
* - Success Criteria (measurable outcomes)
|
|
9
|
+
*/
|
|
10
|
+
interface SpecMetadata {
|
|
11
|
+
feature?: string;
|
|
12
|
+
branch?: string;
|
|
13
|
+
date?: string;
|
|
14
|
+
status?: string;
|
|
15
|
+
[key: string]: unknown;
|
|
16
|
+
}
|
|
17
|
+
interface UserScenario {
|
|
18
|
+
priority: 'P1' | 'P2' | 'P3' | string;
|
|
19
|
+
title: string;
|
|
20
|
+
asA: string;
|
|
21
|
+
iWantTo: string;
|
|
22
|
+
soThat: string;
|
|
23
|
+
acceptanceScenarios: string[];
|
|
24
|
+
edgeCases: string[];
|
|
25
|
+
}
|
|
26
|
+
interface FunctionalRequirement {
|
|
27
|
+
code: string;
|
|
28
|
+
description: string;
|
|
29
|
+
needsClarification: boolean;
|
|
30
|
+
clarificationQuestion?: string;
|
|
31
|
+
}
|
|
32
|
+
interface EntityDefinition {
|
|
33
|
+
name: string;
|
|
34
|
+
represents: string;
|
|
35
|
+
keyAttributes: string[];
|
|
36
|
+
relationships: string[];
|
|
37
|
+
}
|
|
38
|
+
interface SuccessCriteria {
|
|
39
|
+
quantitative: string[];
|
|
40
|
+
qualitative: string[];
|
|
41
|
+
security?: string[];
|
|
42
|
+
performance?: string[];
|
|
43
|
+
}
|
|
44
|
+
export interface ParsedSpec {
|
|
45
|
+
metadata: SpecMetadata;
|
|
46
|
+
userScenarios: UserScenario[];
|
|
47
|
+
requirements: {
|
|
48
|
+
functional: FunctionalRequirement[];
|
|
49
|
+
entities: EntityDefinition[];
|
|
50
|
+
};
|
|
51
|
+
successCriteria: SuccessCriteria;
|
|
52
|
+
clarifications: string[];
|
|
53
|
+
}
|
|
54
|
+
export declare class SpecParser {
|
|
55
|
+
parseSpec(content: string): ParsedSpec;
|
|
56
|
+
private extractMetadata;
|
|
57
|
+
private parseUserScenarios;
|
|
58
|
+
private parseUserScenario;
|
|
59
|
+
private parseRequirements;
|
|
60
|
+
private parseFunctionalRequirements;
|
|
61
|
+
private parseEntities;
|
|
62
|
+
private parseEntity;
|
|
63
|
+
private parseSuccessCriteria;
|
|
64
|
+
private extractClarifications;
|
|
65
|
+
}
|
|
66
|
+
export {};
|
|
67
|
+
//# sourceMappingURL=spec-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spec-parser.d.ts","sourceRoot":"","sources":["../../../src/speckit/parsers/spec-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,UAAU,YAAY;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,UAAU,YAAY;IACpB,QAAQ,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,MAAM,CAAC;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,UAAU,qBAAqB;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC;AAED,UAAU,gBAAgB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,UAAU,eAAe;IACvB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,YAAY,CAAC;IACvB,aAAa,EAAE,YAAY,EAAE,CAAC;IAC9B,YAAY,EAAE;QACZ,UAAU,EAAE,qBAAqB,EAAE,CAAC;QACpC,QAAQ,EAAE,gBAAgB,EAAE,CAAC;KAC9B,CAAC;IACF,eAAe,EAAE,eAAe,CAAC;IACjC,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED,qBAAa,UAAU;IACrB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU;IAiCtC,OAAO,CAAC,eAAe;IAsBvB,OAAO,CAAC,kBAAkB;IA2B1B,OAAO,CAAC,iBAAiB;IAkDzB,OAAO,CAAC,iBAAiB;IA2BzB,OAAO,CAAC,2BAA2B;IAkCnC,OAAO,CAAC,aAAa;IAgCrB,OAAO,CAAC,WAAW;IAqBnB,OAAO,CAAC,oBAAoB;IA4D5B,OAAO,CAAC,qBAAqB;CAW9B"}
|