pmp-gywd 3.3.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/LICENSE +27 -0
- package/README.md +567 -0
- package/bin/install.js +348 -0
- package/commands/gywd/add-phase.md +207 -0
- package/commands/gywd/anticipate.md +271 -0
- package/commands/gywd/bootstrap.md +336 -0
- package/commands/gywd/challenge.md +344 -0
- package/commands/gywd/check-drift.md +144 -0
- package/commands/gywd/complete-milestone.md +106 -0
- package/commands/gywd/consider-issues.md +202 -0
- package/commands/gywd/context.md +93 -0
- package/commands/gywd/create-roadmap.md +115 -0
- package/commands/gywd/deps.md +169 -0
- package/commands/gywd/digest.md +138 -0
- package/commands/gywd/discuss-milestone.md +47 -0
- package/commands/gywd/discuss-phase.md +60 -0
- package/commands/gywd/execute-plan.md +161 -0
- package/commands/gywd/extract-decisions.md +325 -0
- package/commands/gywd/health.md +150 -0
- package/commands/gywd/help.md +556 -0
- package/commands/gywd/history.md +278 -0
- package/commands/gywd/impact.md +317 -0
- package/commands/gywd/init.md +95 -0
- package/commands/gywd/insert-phase.md +227 -0
- package/commands/gywd/list-phase-assumptions.md +50 -0
- package/commands/gywd/map-codebase.md +84 -0
- package/commands/gywd/memory.md +159 -0
- package/commands/gywd/new-milestone.md +59 -0
- package/commands/gywd/new-project.md +315 -0
- package/commands/gywd/pause-work.md +123 -0
- package/commands/gywd/plan-fix.md +205 -0
- package/commands/gywd/plan-phase.md +93 -0
- package/commands/gywd/preview-plan.md +139 -0
- package/commands/gywd/profile.md +363 -0
- package/commands/gywd/progress.md +317 -0
- package/commands/gywd/remove-phase.md +338 -0
- package/commands/gywd/research-phase.md +91 -0
- package/commands/gywd/resume-work.md +40 -0
- package/commands/gywd/rollback.md +179 -0
- package/commands/gywd/status.md +42 -0
- package/commands/gywd/sync-github.md +234 -0
- package/commands/gywd/verify-work.md +71 -0
- package/commands/gywd/why.md +251 -0
- package/docs/COMMANDS.md +722 -0
- package/docs/CONTRIBUTING.md +342 -0
- package/docs/EXAMPLES.md +535 -0
- package/docs/GETTING-STARTED.md +262 -0
- package/docs/README.md +55 -0
- package/docs/RELEASING.md +159 -0
- package/get-your-work-done/core/agent-patterns.md +331 -0
- package/get-your-work-done/core/architecture.md +334 -0
- package/get-your-work-done/core/context-model-schema.json +154 -0
- package/get-your-work-done/core/decisions-schema.json +193 -0
- package/get-your-work-done/core/learning-state-schema.json +133 -0
- package/get-your-work-done/core/profile-schema.json +257 -0
- package/get-your-work-done/references/adaptive-decomposition.md +175 -0
- package/get-your-work-done/references/checkpoints.md +287 -0
- package/get-your-work-done/references/confidence-scoring.md +169 -0
- package/get-your-work-done/references/continuation-format.md +255 -0
- package/get-your-work-done/references/git-integration.md +254 -0
- package/get-your-work-done/references/plan-format.md +428 -0
- package/get-your-work-done/references/principles.md +157 -0
- package/get-your-work-done/references/questioning.md +162 -0
- package/get-your-work-done/references/research-pitfalls.md +215 -0
- package/get-your-work-done/references/scope-estimation.md +172 -0
- package/get-your-work-done/references/tdd.md +263 -0
- package/get-your-work-done/templates/codebase/architecture.md +255 -0
- package/get-your-work-done/templates/codebase/concerns.md +310 -0
- package/get-your-work-done/templates/codebase/conventions.md +307 -0
- package/get-your-work-done/templates/codebase/integrations.md +280 -0
- package/get-your-work-done/templates/codebase/stack.md +186 -0
- package/get-your-work-done/templates/codebase/structure.md +285 -0
- package/get-your-work-done/templates/codebase/testing.md +480 -0
- package/get-your-work-done/templates/config.json +18 -0
- package/get-your-work-done/templates/context.md +161 -0
- package/get-your-work-done/templates/continue-here.md +78 -0
- package/get-your-work-done/templates/discovery.md +146 -0
- package/get-your-work-done/templates/issues.md +32 -0
- package/get-your-work-done/templates/milestone-archive.md +123 -0
- package/get-your-work-done/templates/milestone-context.md +93 -0
- package/get-your-work-done/templates/milestone.md +115 -0
- package/get-your-work-done/templates/phase-prompt.md +303 -0
- package/get-your-work-done/templates/project.md +184 -0
- package/get-your-work-done/templates/research.md +529 -0
- package/get-your-work-done/templates/roadmap.md +196 -0
- package/get-your-work-done/templates/state.md +210 -0
- package/get-your-work-done/templates/summary.md +273 -0
- package/get-your-work-done/templates/uat-issues.md +143 -0
- package/get-your-work-done/workflows/complete-milestone.md +643 -0
- package/get-your-work-done/workflows/create-milestone.md +416 -0
- package/get-your-work-done/workflows/create-roadmap.md +481 -0
- package/get-your-work-done/workflows/discovery-phase.md +293 -0
- package/get-your-work-done/workflows/discuss-milestone.md +236 -0
- package/get-your-work-done/workflows/discuss-phase.md +247 -0
- package/get-your-work-done/workflows/execute-phase.md +1625 -0
- package/get-your-work-done/workflows/list-phase-assumptions.md +178 -0
- package/get-your-work-done/workflows/map-codebase.md +434 -0
- package/get-your-work-done/workflows/plan-phase.md +488 -0
- package/get-your-work-done/workflows/research-phase.md +436 -0
- package/get-your-work-done/workflows/resume-project.md +287 -0
- package/get-your-work-done/workflows/transition.md +580 -0
- package/get-your-work-done/workflows/verify-work.md +202 -0
- package/lib/automation/dependency-analyzer.js +635 -0
- package/lib/automation/doc-generator.js +643 -0
- package/lib/automation/index.js +42 -0
- package/lib/automation/test-generator.js +628 -0
- package/lib/context/context-analyzer.js +554 -0
- package/lib/context/context-cache.js +426 -0
- package/lib/context/context-predictor.js +622 -0
- package/lib/context/index.js +44 -0
- package/lib/memory/confidence-calibrator.js +484 -0
- package/lib/memory/feedback-collector.js +551 -0
- package/lib/memory/global-memory.js +465 -0
- package/lib/memory/index.js +75 -0
- package/lib/memory/pattern-aggregator.js +487 -0
- package/lib/memory/team-sync.js +501 -0
- package/lib/profile/index.js +24 -0
- package/lib/profile/pattern-learner.js +303 -0
- package/lib/profile/profile-manager.js +445 -0
- package/lib/questioning/index.js +49 -0
- package/lib/questioning/question-engine.js +311 -0
- package/lib/questioning/question-templates.js +315 -0
- package/lib/validators/command-validator.js +188 -0
- package/lib/validators/index.js +29 -0
- package/lib/validators/schema-validator.js +183 -0
- package/package.json +61 -0
|
@@ -0,0 +1,643 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Documentation Generator
|
|
3
|
+
*
|
|
4
|
+
* Automatically generates documentation from source code:
|
|
5
|
+
* - JSDoc comments extraction
|
|
6
|
+
* - API documentation
|
|
7
|
+
* - Module documentation
|
|
8
|
+
* - README generation
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const fs = require('fs');
|
|
12
|
+
const path = require('path');
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* JSDoc tag patterns (reserved for future use)
|
|
16
|
+
*/
|
|
17
|
+
const _JSDOC_PATTERNS = {
|
|
18
|
+
block: /\/\*\*\s*([\s\S]*?)\s*\*\//g,
|
|
19
|
+
param: /@param\s+\{([^}]+)\}\s+(\w+)(?:\s*-\s*(.+))?/g,
|
|
20
|
+
returns: /@returns?\s+\{([^}]+)\}(?:\s*-?\s*(.+))?/,
|
|
21
|
+
description: /^([^@]+)/,
|
|
22
|
+
example: /@example\s*([\s\S]*?)(?=@|$)/g,
|
|
23
|
+
throws: /@throws?\s+\{([^}]+)\}(?:\s*-?\s*(.+))?/g,
|
|
24
|
+
deprecated: /@deprecated(?:\s+(.+))?/,
|
|
25
|
+
since: /@since\s+(.+)/,
|
|
26
|
+
see: /@see\s+(.+)/g,
|
|
27
|
+
type: /@type\s+\{([^}]+)\}/,
|
|
28
|
+
typedef: /@typedef\s+\{([^}]+)\}\s+(\w+)/,
|
|
29
|
+
property: /@property\s+\{([^}]+)\}\s+(\w+)(?:\s*-\s*(.+))?/g,
|
|
30
|
+
private: /@private/,
|
|
31
|
+
public: /@public/,
|
|
32
|
+
static: /@static/,
|
|
33
|
+
async: /@async/,
|
|
34
|
+
class: /@class(?:\s+(\w+))?/,
|
|
35
|
+
constructor: /@constructor/,
|
|
36
|
+
module: /@module\s+(\w+)/,
|
|
37
|
+
memberof: /@memberof\s+(\w+)/,
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Documentation types
|
|
42
|
+
*/
|
|
43
|
+
const DOC_TYPES = {
|
|
44
|
+
MODULE: 'module',
|
|
45
|
+
CLASS: 'class',
|
|
46
|
+
FUNCTION: 'function',
|
|
47
|
+
METHOD: 'method',
|
|
48
|
+
PROPERTY: 'property',
|
|
49
|
+
CONSTANT: 'constant',
|
|
50
|
+
TYPEDEF: 'typedef',
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Documentation Generator class
|
|
55
|
+
*/
|
|
56
|
+
class DocGenerator {
|
|
57
|
+
constructor(options = {}) {
|
|
58
|
+
this.outputDir = options.outputDir || 'docs';
|
|
59
|
+
this.sourceDir = options.sourceDir || 'lib';
|
|
60
|
+
this.includePrivate = options.includePrivate || false;
|
|
61
|
+
this.format = options.format || 'markdown';
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Parse JSDoc comments from file content
|
|
66
|
+
* @param {string} content - File content
|
|
67
|
+
* @returns {Array<object>}
|
|
68
|
+
*/
|
|
69
|
+
parseJSDoc(content) {
|
|
70
|
+
const docs = [];
|
|
71
|
+
// Match JSDoc blocks followed by declarations
|
|
72
|
+
const blockPattern = '\\/\\*\\*\\s*([\\s\\S]*?)\\s*\\*\\/\\s*\\n?\\s*' +
|
|
73
|
+
'(?:export\\s+)?(?:async\\s+)?(?:(const|let|var|function|class)\\s+)?(\\w+)?';
|
|
74
|
+
const blockRegex = new RegExp(blockPattern, 'g');
|
|
75
|
+
|
|
76
|
+
let match;
|
|
77
|
+
while ((match = blockRegex.exec(content)) !== null) {
|
|
78
|
+
const commentBody = match[1];
|
|
79
|
+
const declType = match[2];
|
|
80
|
+
const name = match[3];
|
|
81
|
+
|
|
82
|
+
const doc = this.parseCommentBlock(commentBody);
|
|
83
|
+
doc.name = name || doc.name;
|
|
84
|
+
doc.declarationType = declType;
|
|
85
|
+
|
|
86
|
+
// Determine doc type
|
|
87
|
+
if (doc.class || declType === 'class') {
|
|
88
|
+
doc.type = DOC_TYPES.CLASS;
|
|
89
|
+
} else if (doc.typedef) {
|
|
90
|
+
doc.type = DOC_TYPES.TYPEDEF;
|
|
91
|
+
} else if (declType === 'function' || doc.params.length > 0 || doc.returns) {
|
|
92
|
+
doc.type = DOC_TYPES.FUNCTION;
|
|
93
|
+
} else if (doc.module) {
|
|
94
|
+
doc.type = DOC_TYPES.MODULE;
|
|
95
|
+
} else {
|
|
96
|
+
doc.type = DOC_TYPES.CONSTANT;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Skip private unless configured
|
|
100
|
+
if (doc.private && !this.includePrivate) {
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
docs.push(doc);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return docs;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Parse a single JSDoc comment block
|
|
112
|
+
* @param {string} body - Comment body
|
|
113
|
+
* @returns {object}
|
|
114
|
+
*/
|
|
115
|
+
parseCommentBlock(body) {
|
|
116
|
+
const lines = body
|
|
117
|
+
.split('\n')
|
|
118
|
+
.map(line => line.replace(/^\s*\*\s?/, '').trim())
|
|
119
|
+
.join('\n');
|
|
120
|
+
|
|
121
|
+
const doc = {
|
|
122
|
+
description: '',
|
|
123
|
+
params: [],
|
|
124
|
+
returns: null,
|
|
125
|
+
examples: [],
|
|
126
|
+
throws: [],
|
|
127
|
+
deprecated: null,
|
|
128
|
+
since: null,
|
|
129
|
+
see: [],
|
|
130
|
+
private: false,
|
|
131
|
+
static: false,
|
|
132
|
+
async: false,
|
|
133
|
+
properties: [],
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
// Extract description (text before first @tag)
|
|
137
|
+
const descMatch = lines.match(/^([^@]+)/);
|
|
138
|
+
if (descMatch) {
|
|
139
|
+
doc.description = descMatch[1].trim();
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Extract @param tags
|
|
143
|
+
const paramRegex = /@param\s+\{([^}]+)\}\s+(\[?\w+\]?)(?:\s*-?\s*(.+))?/g;
|
|
144
|
+
let paramMatch;
|
|
145
|
+
while ((paramMatch = paramRegex.exec(lines)) !== null) {
|
|
146
|
+
const paramName = paramMatch[2];
|
|
147
|
+
const optional = paramName.startsWith('[') && paramName.endsWith(']');
|
|
148
|
+
doc.params.push({
|
|
149
|
+
type: paramMatch[1],
|
|
150
|
+
name: paramName.replace(/[\[\]]/g, ''),
|
|
151
|
+
description: paramMatch[3] || '',
|
|
152
|
+
optional,
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Extract @returns
|
|
157
|
+
const returnsMatch = lines.match(/@returns?\s+\{([^}]+)\}(?:\s*-?\s*(.+))?/);
|
|
158
|
+
if (returnsMatch) {
|
|
159
|
+
doc.returns = {
|
|
160
|
+
type: returnsMatch[1],
|
|
161
|
+
description: returnsMatch[2] || '',
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Extract @example
|
|
166
|
+
const exampleRegex = /@example\s*([\s\S]*?)(?=@\w|$)/g;
|
|
167
|
+
let exampleMatch;
|
|
168
|
+
while ((exampleMatch = exampleRegex.exec(lines)) !== null) {
|
|
169
|
+
const example = exampleMatch[1].trim();
|
|
170
|
+
if (example) {
|
|
171
|
+
doc.examples.push(example);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Extract @throws
|
|
176
|
+
const throwsRegex = /@throws?\s+\{([^}]+)\}(?:\s*-?\s*(.+))?/g;
|
|
177
|
+
let throwsMatch;
|
|
178
|
+
while ((throwsMatch = throwsRegex.exec(lines)) !== null) {
|
|
179
|
+
doc.throws.push({
|
|
180
|
+
type: throwsMatch[1],
|
|
181
|
+
description: throwsMatch[2] || '',
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Extract @property
|
|
186
|
+
const propRegex = /@property\s+\{([^}]+)\}\s+(\w+)(?:\s*-?\s*(.+))?/g;
|
|
187
|
+
let propMatch;
|
|
188
|
+
while ((propMatch = propRegex.exec(lines)) !== null) {
|
|
189
|
+
doc.properties.push({
|
|
190
|
+
type: propMatch[1],
|
|
191
|
+
name: propMatch[2],
|
|
192
|
+
description: propMatch[3] || '',
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Extract simple tags
|
|
197
|
+
const deprecatedMatch = lines.match(/@deprecated(?:\s+(.+))?/);
|
|
198
|
+
if (deprecatedMatch) {
|
|
199
|
+
doc.deprecated = deprecatedMatch[1] || true;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const sinceMatch = lines.match(/@since\s+(.+)/);
|
|
203
|
+
if (sinceMatch) {
|
|
204
|
+
doc.since = sinceMatch[1].trim();
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const seeRegex = /@see\s+(.+)/g;
|
|
208
|
+
let seeMatch;
|
|
209
|
+
while ((seeMatch = seeRegex.exec(lines)) !== null) {
|
|
210
|
+
doc.see.push(seeMatch[1].trim());
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const moduleMatch = lines.match(/@module\s+(\w+)/);
|
|
214
|
+
if (moduleMatch) {
|
|
215
|
+
doc.module = moduleMatch[1];
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const classMatch = lines.match(/@class(?:\s+(\w+))?/);
|
|
219
|
+
if (classMatch) {
|
|
220
|
+
doc.class = classMatch[1] || true;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const typedefMatch = lines.match(/@typedef\s+\{([^}]+)\}\s+(\w+)/);
|
|
224
|
+
if (typedefMatch) {
|
|
225
|
+
doc.typedef = {
|
|
226
|
+
type: typedefMatch[1],
|
|
227
|
+
name: typedefMatch[2],
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Boolean flags
|
|
232
|
+
doc.private = /@private/.test(lines);
|
|
233
|
+
doc.static = /@static/.test(lines);
|
|
234
|
+
doc.async = /@async/.test(lines);
|
|
235
|
+
|
|
236
|
+
return doc;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Generate markdown documentation for a file
|
|
241
|
+
* @param {string} filePath - Source file path
|
|
242
|
+
* @returns {string}
|
|
243
|
+
*/
|
|
244
|
+
generateMarkdown(filePath) {
|
|
245
|
+
let content;
|
|
246
|
+
try {
|
|
247
|
+
content = fs.readFileSync(filePath, 'utf-8');
|
|
248
|
+
} catch {
|
|
249
|
+
return `# Error\n\nCould not read file: ${filePath}`;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const docs = this.parseJSDoc(content);
|
|
253
|
+
const fileName = path.basename(filePath);
|
|
254
|
+
const moduleName = path.basename(filePath, path.extname(filePath));
|
|
255
|
+
|
|
256
|
+
const lines = [
|
|
257
|
+
`# ${moduleName}`,
|
|
258
|
+
'',
|
|
259
|
+
`Source: \`${fileName}\``,
|
|
260
|
+
'',
|
|
261
|
+
];
|
|
262
|
+
|
|
263
|
+
// Find module-level description
|
|
264
|
+
const moduleDoc = docs.find(d => d.type === DOC_TYPES.MODULE);
|
|
265
|
+
if (moduleDoc) {
|
|
266
|
+
lines.push(moduleDoc.description, '');
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Group by type
|
|
270
|
+
const classes = docs.filter(d => d.type === DOC_TYPES.CLASS);
|
|
271
|
+
const functions = docs.filter(d => d.type === DOC_TYPES.FUNCTION);
|
|
272
|
+
const constants = docs.filter(d => d.type === DOC_TYPES.CONSTANT);
|
|
273
|
+
const typedefs = docs.filter(d => d.type === DOC_TYPES.TYPEDEF);
|
|
274
|
+
|
|
275
|
+
// Document typedefs
|
|
276
|
+
if (typedefs.length > 0) {
|
|
277
|
+
lines.push('## Type Definitions', '');
|
|
278
|
+
for (const typedef of typedefs) {
|
|
279
|
+
lines.push(...this.formatTypedef(typedef));
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Document classes
|
|
284
|
+
if (classes.length > 0) {
|
|
285
|
+
lines.push('## Classes', '');
|
|
286
|
+
for (const cls of classes) {
|
|
287
|
+
lines.push(...this.formatClass(cls, docs));
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// Document functions
|
|
292
|
+
if (functions.length > 0) {
|
|
293
|
+
lines.push('## Functions', '');
|
|
294
|
+
for (const func of functions) {
|
|
295
|
+
lines.push(...this.formatFunction(func));
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// Document constants
|
|
300
|
+
if (constants.length > 0) {
|
|
301
|
+
lines.push('## Constants', '');
|
|
302
|
+
for (const constant of constants) {
|
|
303
|
+
lines.push(...this.formatConstant(constant));
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
return lines.join('\n');
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Format a function for markdown
|
|
312
|
+
* @param {object} doc - Function documentation
|
|
313
|
+
* @returns {string[]}
|
|
314
|
+
*/
|
|
315
|
+
formatFunction(doc) {
|
|
316
|
+
const lines = [];
|
|
317
|
+
const asyncPrefix = doc.async ? 'async ' : '';
|
|
318
|
+
const params = doc.params.map(p => p.name).join(', ');
|
|
319
|
+
|
|
320
|
+
lines.push(`### ${asyncPrefix}${doc.name}(${params})`, '');
|
|
321
|
+
|
|
322
|
+
if (doc.deprecated) {
|
|
323
|
+
lines.push(`> **Deprecated**: ${doc.deprecated === true ? 'This function is deprecated.' : doc.deprecated}`, '');
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
if (doc.description) {
|
|
327
|
+
lines.push(doc.description, '');
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
if (doc.params.length > 0) {
|
|
331
|
+
lines.push('**Parameters:**', '');
|
|
332
|
+
lines.push('| Name | Type | Description |');
|
|
333
|
+
lines.push('|------|------|-------------|');
|
|
334
|
+
for (const param of doc.params) {
|
|
335
|
+
const optional = param.optional ? ' *(optional)*' : '';
|
|
336
|
+
lines.push(`| ${param.name}${optional} | \`${param.type}\` | ${param.description} |`);
|
|
337
|
+
}
|
|
338
|
+
lines.push('');
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
if (doc.returns) {
|
|
342
|
+
lines.push(`**Returns:** \`${doc.returns.type}\`${doc.returns.description ? ` - ${doc.returns.description}` : ''}`, '');
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
if (doc.throws.length > 0) {
|
|
346
|
+
lines.push('**Throws:**', '');
|
|
347
|
+
for (const t of doc.throws) {
|
|
348
|
+
lines.push(`- \`${t.type}\` - ${t.description}`);
|
|
349
|
+
}
|
|
350
|
+
lines.push('');
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
if (doc.examples.length > 0) {
|
|
354
|
+
lines.push('**Example:**', '');
|
|
355
|
+
for (const example of doc.examples) {
|
|
356
|
+
lines.push('```javascript', example, '```', '');
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
if (doc.since) {
|
|
361
|
+
lines.push(`*Since: ${doc.since}*`, '');
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
if (doc.see.length > 0) {
|
|
365
|
+
lines.push('**See also:**', '');
|
|
366
|
+
for (const see of doc.see) {
|
|
367
|
+
lines.push(`- ${see}`);
|
|
368
|
+
}
|
|
369
|
+
lines.push('');
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
lines.push('---', '');
|
|
373
|
+
|
|
374
|
+
return lines;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Format a class for markdown
|
|
379
|
+
* @param {object} doc - Class documentation
|
|
380
|
+
* @param {Array} allDocs - All documentation items
|
|
381
|
+
* @returns {string[]}
|
|
382
|
+
*/
|
|
383
|
+
formatClass(doc, allDocs) {
|
|
384
|
+
const lines = [];
|
|
385
|
+
|
|
386
|
+
lines.push(`### class ${doc.name}`, '');
|
|
387
|
+
|
|
388
|
+
if (doc.deprecated) {
|
|
389
|
+
lines.push(`> **Deprecated**: ${doc.deprecated === true ? 'This class is deprecated.' : doc.deprecated}`, '');
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
if (doc.description) {
|
|
393
|
+
lines.push(doc.description, '');
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// Find methods belonging to this class (reserved for future method documentation)
|
|
397
|
+
const _methods = allDocs.filter(d =>
|
|
398
|
+
d.memberof === doc.name ||
|
|
399
|
+
(d.type === DOC_TYPES.FUNCTION && d.name && d.name !== doc.name),
|
|
400
|
+
);
|
|
401
|
+
|
|
402
|
+
if (doc.properties.length > 0) {
|
|
403
|
+
lines.push('**Properties:**', '');
|
|
404
|
+
lines.push('| Name | Type | Description |');
|
|
405
|
+
lines.push('|------|------|-------------|');
|
|
406
|
+
for (const prop of doc.properties) {
|
|
407
|
+
lines.push(`| ${prop.name} | \`${prop.type}\` | ${prop.description} |`);
|
|
408
|
+
}
|
|
409
|
+
lines.push('');
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
if (doc.examples.length > 0) {
|
|
413
|
+
lines.push('**Example:**', '');
|
|
414
|
+
for (const example of doc.examples) {
|
|
415
|
+
lines.push('```javascript', example, '```', '');
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
lines.push('---', '');
|
|
420
|
+
|
|
421
|
+
return lines;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* Format a constant for markdown
|
|
426
|
+
* @param {object} doc - Constant documentation
|
|
427
|
+
* @returns {string[]}
|
|
428
|
+
*/
|
|
429
|
+
formatConstant(doc) {
|
|
430
|
+
const lines = [];
|
|
431
|
+
|
|
432
|
+
lines.push(`### ${doc.name}`, '');
|
|
433
|
+
|
|
434
|
+
if (doc.description) {
|
|
435
|
+
lines.push(doc.description, '');
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
if (doc.properties.length > 0) {
|
|
439
|
+
lines.push('**Properties:**', '');
|
|
440
|
+
lines.push('| Name | Type | Description |');
|
|
441
|
+
lines.push('|------|------|-------------|');
|
|
442
|
+
for (const prop of doc.properties) {
|
|
443
|
+
lines.push(`| ${prop.name} | \`${prop.type}\` | ${prop.description} |`);
|
|
444
|
+
}
|
|
445
|
+
lines.push('');
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
lines.push('---', '');
|
|
449
|
+
|
|
450
|
+
return lines;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* Format a typedef for markdown
|
|
455
|
+
* @param {object} doc - Typedef documentation
|
|
456
|
+
* @returns {string[]}
|
|
457
|
+
*/
|
|
458
|
+
formatTypedef(doc) {
|
|
459
|
+
const lines = [];
|
|
460
|
+
const name = doc.typedef?.name || doc.name;
|
|
461
|
+
const type = doc.typedef?.type || 'object';
|
|
462
|
+
|
|
463
|
+
lines.push(`### ${name}`, '');
|
|
464
|
+
lines.push(`Type: \`${type}\``, '');
|
|
465
|
+
|
|
466
|
+
if (doc.description) {
|
|
467
|
+
lines.push(doc.description, '');
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
if (doc.properties.length > 0) {
|
|
471
|
+
lines.push('**Properties:**', '');
|
|
472
|
+
lines.push('| Name | Type | Description |');
|
|
473
|
+
lines.push('|------|------|-------------|');
|
|
474
|
+
for (const prop of doc.properties) {
|
|
475
|
+
lines.push(`| ${prop.name} | \`${prop.type}\` | ${prop.description} |`);
|
|
476
|
+
}
|
|
477
|
+
lines.push('');
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
lines.push('---', '');
|
|
481
|
+
|
|
482
|
+
return lines;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* Generate documentation for a directory
|
|
487
|
+
* @param {string} dir - Directory to document
|
|
488
|
+
* @param {boolean} dryRun - If true, don't write files
|
|
489
|
+
* @returns {Array}
|
|
490
|
+
*/
|
|
491
|
+
generateForDirectory(dir, dryRun = false) {
|
|
492
|
+
const results = [];
|
|
493
|
+
const extensions = ['.js', '.ts', '.jsx', '.tsx', '.mjs'];
|
|
494
|
+
|
|
495
|
+
const scan = (scanDir) => {
|
|
496
|
+
let entries;
|
|
497
|
+
try {
|
|
498
|
+
entries = fs.readdirSync(scanDir, { withFileTypes: true });
|
|
499
|
+
} catch {
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
for (const entry of entries) {
|
|
504
|
+
const fullPath = path.join(scanDir, entry.name);
|
|
505
|
+
|
|
506
|
+
if (entry.isDirectory()) {
|
|
507
|
+
if (!['node_modules', '.git', 'test', 'tests', '__tests__', 'docs'].includes(entry.name)) {
|
|
508
|
+
scan(fullPath);
|
|
509
|
+
}
|
|
510
|
+
} else if (entry.isFile()) {
|
|
511
|
+
const ext = path.extname(entry.name);
|
|
512
|
+
if (extensions.includes(ext)) {
|
|
513
|
+
const result = this.generateDocFile(fullPath, dryRun);
|
|
514
|
+
results.push(result);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
};
|
|
519
|
+
|
|
520
|
+
scan(dir);
|
|
521
|
+
return results;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* Generate documentation file for a source file
|
|
526
|
+
* @param {string} sourcePath - Source file path
|
|
527
|
+
* @param {boolean} dryRun - If true, don't write file
|
|
528
|
+
* @returns {object}
|
|
529
|
+
*/
|
|
530
|
+
generateDocFile(sourcePath, dryRun = false) {
|
|
531
|
+
const content = this.generateMarkdown(sourcePath);
|
|
532
|
+
const docPath = this.getDocFilePath(sourcePath);
|
|
533
|
+
|
|
534
|
+
const result = {
|
|
535
|
+
source: sourcePath,
|
|
536
|
+
path: docPath,
|
|
537
|
+
content,
|
|
538
|
+
written: false,
|
|
539
|
+
};
|
|
540
|
+
|
|
541
|
+
if (!dryRun) {
|
|
542
|
+
const docDir = path.dirname(docPath);
|
|
543
|
+
if (!fs.existsSync(docDir)) {
|
|
544
|
+
fs.mkdirSync(docDir, { recursive: true });
|
|
545
|
+
}
|
|
546
|
+
fs.writeFileSync(docPath, content);
|
|
547
|
+
result.written = true;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
return result;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
/**
|
|
554
|
+
* Get documentation file path for a source file
|
|
555
|
+
* @param {string} sourcePath - Source file path
|
|
556
|
+
* @returns {string}
|
|
557
|
+
*/
|
|
558
|
+
getDocFilePath(sourcePath) {
|
|
559
|
+
const baseName = path.basename(sourcePath, path.extname(sourcePath));
|
|
560
|
+
const sourceDir = path.dirname(sourcePath);
|
|
561
|
+
const relativeSrc = sourceDir.replace(this.sourceDir, '').replace(/^[/\\]/, '');
|
|
562
|
+
|
|
563
|
+
return path.join(this.outputDir, relativeSrc, `${baseName}.md`);
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
/**
|
|
567
|
+
* Generate API index file
|
|
568
|
+
* @param {string} dir - Directory to index
|
|
569
|
+
* @returns {string}
|
|
570
|
+
*/
|
|
571
|
+
generateApiIndex(dir) {
|
|
572
|
+
const results = this.generateForDirectory(dir, true);
|
|
573
|
+
const lines = [
|
|
574
|
+
'# API Reference',
|
|
575
|
+
'',
|
|
576
|
+
`Generated: ${new Date().toISOString()}`,
|
|
577
|
+
'',
|
|
578
|
+
'## Modules',
|
|
579
|
+
'',
|
|
580
|
+
];
|
|
581
|
+
|
|
582
|
+
// Group by directory
|
|
583
|
+
const byDir = new Map();
|
|
584
|
+
for (const result of results) {
|
|
585
|
+
const relPath = path.relative(dir, result.source);
|
|
586
|
+
const dirName = path.dirname(relPath) || 'root';
|
|
587
|
+
|
|
588
|
+
if (!byDir.has(dirName)) {
|
|
589
|
+
byDir.set(dirName, []);
|
|
590
|
+
}
|
|
591
|
+
byDir.get(dirName).push({
|
|
592
|
+
name: path.basename(result.source, path.extname(result.source)),
|
|
593
|
+
path: result.path,
|
|
594
|
+
});
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
for (const [dirName, files] of byDir) {
|
|
598
|
+
lines.push(`### ${dirName}`, '');
|
|
599
|
+
for (const file of files) {
|
|
600
|
+
const relDocPath = path.relative(this.outputDir, file.path);
|
|
601
|
+
lines.push(`- [${file.name}](${relDocPath})`);
|
|
602
|
+
}
|
|
603
|
+
lines.push('');
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
return lines.join('\n');
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
/**
|
|
610
|
+
* Generate full documentation
|
|
611
|
+
* @param {string} dir - Source directory
|
|
612
|
+
* @param {boolean} dryRun - If true, don't write files
|
|
613
|
+
* @returns {object}
|
|
614
|
+
*/
|
|
615
|
+
generateAll(dir, dryRun = false) {
|
|
616
|
+
const moduleResults = this.generateForDirectory(dir, dryRun);
|
|
617
|
+
const indexContent = this.generateApiIndex(dir);
|
|
618
|
+
|
|
619
|
+
const results = {
|
|
620
|
+
modules: moduleResults,
|
|
621
|
+
index: {
|
|
622
|
+
path: path.join(this.outputDir, 'API.md'),
|
|
623
|
+
content: indexContent,
|
|
624
|
+
written: false,
|
|
625
|
+
},
|
|
626
|
+
};
|
|
627
|
+
|
|
628
|
+
if (!dryRun) {
|
|
629
|
+
if (!fs.existsSync(this.outputDir)) {
|
|
630
|
+
fs.mkdirSync(this.outputDir, { recursive: true });
|
|
631
|
+
}
|
|
632
|
+
fs.writeFileSync(results.index.path, indexContent);
|
|
633
|
+
results.index.written = true;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
return results;
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
module.exports = {
|
|
641
|
+
DocGenerator,
|
|
642
|
+
DOC_TYPES,
|
|
643
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Automation Module
|
|
3
|
+
*
|
|
4
|
+
* Tools for automating development workflows:
|
|
5
|
+
* - Dependency analysis
|
|
6
|
+
* - Test generation
|
|
7
|
+
* - Documentation generation
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const {
|
|
11
|
+
DependencyAnalyzer,
|
|
12
|
+
DEP_TYPES,
|
|
13
|
+
BUILTIN_MODULES,
|
|
14
|
+
} = require('./dependency-analyzer');
|
|
15
|
+
|
|
16
|
+
const {
|
|
17
|
+
TestGenerator,
|
|
18
|
+
TEST_FRAMEWORKS,
|
|
19
|
+
} = require('./test-generator');
|
|
20
|
+
|
|
21
|
+
const {
|
|
22
|
+
DocGenerator,
|
|
23
|
+
DOC_TYPES,
|
|
24
|
+
} = require('./doc-generator');
|
|
25
|
+
|
|
26
|
+
module.exports = {
|
|
27
|
+
// Classes
|
|
28
|
+
DependencyAnalyzer,
|
|
29
|
+
TestGenerator,
|
|
30
|
+
DocGenerator,
|
|
31
|
+
|
|
32
|
+
// Constants
|
|
33
|
+
DEP_TYPES,
|
|
34
|
+
BUILTIN_MODULES,
|
|
35
|
+
TEST_FRAMEWORKS,
|
|
36
|
+
DOC_TYPES,
|
|
37
|
+
|
|
38
|
+
// Factory functions
|
|
39
|
+
createDependencyAnalyzer: (options) => new DependencyAnalyzer(options),
|
|
40
|
+
createTestGenerator: (options) => new TestGenerator(options),
|
|
41
|
+
createDocGenerator: (options) => new DocGenerator(options),
|
|
42
|
+
};
|