aios-core 2.1.4 → 2.1.6
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/.aios-core/development/tasks/analyze-brownfield.md +456 -456
- package/.aios-core/development/tasks/setup-project-docs.md +440 -444
- package/.aios-core/infrastructure/scripts/documentation-integrity/brownfield-analyzer.js +501 -501
- package/.aios-core/infrastructure/scripts/documentation-integrity/config-generator.js +368 -329
- package/.aios-core/infrastructure/scripts/documentation-integrity/deployment-config-loader.js +308 -282
- package/.aios-core/infrastructure/scripts/documentation-integrity/doc-generator.js +331 -331
- package/.aios-core/infrastructure/scripts/documentation-integrity/gitignore-generator.js +312 -312
- package/.aios-core/infrastructure/scripts/documentation-integrity/index.js +74 -74
- package/.aios-core/infrastructure/scripts/documentation-integrity/mode-detector.js +389 -358
- package/.aios-core/infrastructure/scripts/llm-routing/install-llm-routing.js +6 -6
- package/.aios-core/infrastructure/templates/core-config/core-config-brownfield.tmpl.yaml +176 -182
- package/.aios-core/infrastructure/templates/core-config/core-config-greenfield.tmpl.yaml +127 -127
- package/.aios-core/infrastructure/templates/project-docs/coding-standards-tmpl.md +346 -346
- package/.aios-core/infrastructure/templates/project-docs/source-tree-tmpl.md +177 -177
- package/.aios-core/infrastructure/templates/project-docs/tech-stack-tmpl.md +267 -267
- package/package.json +1 -1
- package/packages/installer/src/config/templates/env-template.js +2 -2
- package/packages/installer/src/wizard/wizard.js +1 -1
- package/packages/installer/tests/integration/environment-configuration.test.js +2 -1
- package/packages/installer/tests/unit/env-template.test.js +3 -2
- package/src/wizard/index.js +2 -2
- package/.aios-core/development/tasks/validate-structure.md +0 -243
- package/.aios-core/infrastructure/scripts/source-tree-guardian/index.js +0 -375
- package/.aios-core/infrastructure/scripts/source-tree-guardian/manifest-generator.js +0 -410
- package/.aios-core/infrastructure/scripts/source-tree-guardian/rules/naming-rules.yaml +0 -285
- package/.aios-core/infrastructure/scripts/source-tree-guardian/rules/placement-rules.yaml +0 -262
- package/.aios-core/infrastructure/scripts/source-tree-guardian/validator.js +0 -468
|
@@ -1,331 +1,331 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Documentation Generator Module
|
|
3
|
-
*
|
|
4
|
-
* Generates project-specific documentation from templates.
|
|
5
|
-
* Supports Node.js, Python, Go, and Rust projects.
|
|
6
|
-
*
|
|
7
|
-
* @module documentation-integrity/doc-generator
|
|
8
|
-
* @version 1.0.0
|
|
9
|
-
* @story 6.9
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
const fs = require('fs');
|
|
13
|
-
const path = require('path');
|
|
14
|
-
|
|
15
|
-
// Template directory
|
|
16
|
-
const TEMPLATES_DIR = path.join(__dirname, '..', '..', 'templates', 'project-docs');
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Template file names
|
|
20
|
-
* @enum {string}
|
|
21
|
-
*/
|
|
22
|
-
const TemplateFiles = {
|
|
23
|
-
SOURCE_TREE: 'source-tree-tmpl.md',
|
|
24
|
-
CODING_STANDARDS: 'coding-standards-tmpl.md',
|
|
25
|
-
TECH_STACK: 'tech-stack-tmpl.md',
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Output file names
|
|
30
|
-
* @enum {string}
|
|
31
|
-
*/
|
|
32
|
-
const OutputFiles = {
|
|
33
|
-
SOURCE_TREE: 'source-tree.md',
|
|
34
|
-
CODING_STANDARDS: 'coding-standards.md',
|
|
35
|
-
TECH_STACK: 'tech-stack.md',
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Documentation context for template rendering
|
|
40
|
-
* @typedef {Object} DocContext
|
|
41
|
-
* @property {string} PROJECT_NAME - Project name
|
|
42
|
-
* @property {string} GENERATED_DATE - Generation date
|
|
43
|
-
* @property {string} INSTALLATION_MODE - Installation mode
|
|
44
|
-
* @property {string} TECH_STACK - Detected tech stack
|
|
45
|
-
* @property {boolean} IS_NODE - Is Node.js project
|
|
46
|
-
* @property {boolean} IS_PYTHON - Is Python project
|
|
47
|
-
* @property {boolean} IS_GO - Is Go project
|
|
48
|
-
* @property {boolean} IS_RUST - Is Rust project
|
|
49
|
-
* @property {boolean} IS_TYPESCRIPT - Uses TypeScript
|
|
50
|
-
*/
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Builds documentation context from detected markers
|
|
54
|
-
*
|
|
55
|
-
* @param {string} projectName - Project name
|
|
56
|
-
* @param {string} mode - Installation mode
|
|
57
|
-
* @param {Object} markers - Detected project markers
|
|
58
|
-
* @param {Object} [overrides] - Optional context overrides
|
|
59
|
-
* @returns {DocContext} Documentation context
|
|
60
|
-
*/
|
|
61
|
-
function buildDocContext(projectName, mode, markers, overrides = {}) {
|
|
62
|
-
// Detect tech stack from markers
|
|
63
|
-
const techStacks = [];
|
|
64
|
-
if (markers.hasPackageJson) techStacks.push('Node.js');
|
|
65
|
-
if (markers.hasPythonProject) techStacks.push('Python');
|
|
66
|
-
if (markers.hasGoMod) techStacks.push('Go');
|
|
67
|
-
if (markers.hasCargoToml) techStacks.push('Rust');
|
|
68
|
-
|
|
69
|
-
// Determine file extension
|
|
70
|
-
let fileExt = 'js';
|
|
71
|
-
if (markers.hasTsconfig) fileExt = 'ts';
|
|
72
|
-
|
|
73
|
-
// Build context
|
|
74
|
-
const context = {
|
|
75
|
-
// Basic info
|
|
76
|
-
PROJECT_NAME: projectName,
|
|
77
|
-
GENERATED_DATE: new Date().toISOString().split('T')[0],
|
|
78
|
-
INSTALLATION_MODE: mode,
|
|
79
|
-
TECH_STACK: techStacks.join(', ') || 'Unknown',
|
|
80
|
-
|
|
81
|
-
// Language flags
|
|
82
|
-
IS_NODE: markers.hasPackageJson || false,
|
|
83
|
-
IS_PYTHON: markers.hasPythonProject || false,
|
|
84
|
-
IS_GO: markers.hasGoMod || false,
|
|
85
|
-
IS_RUST: markers.hasCargoToml || false,
|
|
86
|
-
IS_TYPESCRIPT: markers.hasTsconfig || false,
|
|
87
|
-
|
|
88
|
-
// Node.js specific
|
|
89
|
-
FILE_EXT: fileExt,
|
|
90
|
-
NODE_VERSION: '18+',
|
|
91
|
-
TYPESCRIPT_VERSION: '5.0+',
|
|
92
|
-
NPM_VERSION: '9+',
|
|
93
|
-
SEMICOLONS: 'Required',
|
|
94
|
-
SEMICOLONS_RULE: 'always',
|
|
95
|
-
PRETTIER_SEMI: true,
|
|
96
|
-
|
|
97
|
-
// Python specific
|
|
98
|
-
PYTHON_PACKAGE_NAME: projectName.toLowerCase().replace(/[^a-z0-9]/g, '_'),
|
|
99
|
-
PYTHON_VERSION: '3.11+',
|
|
100
|
-
PYTHON_SHORT_VERSION: '311',
|
|
101
|
-
POETRY_VERSION: '1.5+',
|
|
102
|
-
|
|
103
|
-
// Go specific
|
|
104
|
-
GO_VERSION: '1.21+',
|
|
105
|
-
GO_MODULE: `github.com/user/${projectName}`,
|
|
106
|
-
|
|
107
|
-
// Rust specific
|
|
108
|
-
RUST_VERSION: '1.70+',
|
|
109
|
-
|
|
110
|
-
// Deployment
|
|
111
|
-
DEPLOYMENT_PLATFORM: null,
|
|
112
|
-
PRODUCTION_BRANCH: 'main',
|
|
113
|
-
STAGING_BRANCH: 'staging',
|
|
114
|
-
HAS_STAGING: false,
|
|
115
|
-
|
|
116
|
-
// Database
|
|
117
|
-
DATABASE: null,
|
|
118
|
-
CACHE: null,
|
|
119
|
-
|
|
120
|
-
// Quality gates
|
|
121
|
-
QUALITY_GATES: ['Lint', 'Type Check', 'Tests'],
|
|
122
|
-
|
|
123
|
-
// Dependencies (to be populated by analyzer)
|
|
124
|
-
DEPENDENCIES: [],
|
|
125
|
-
DEV_DEPENDENCIES: [],
|
|
126
|
-
ENV_VARS: [],
|
|
127
|
-
|
|
128
|
-
// Apply overrides
|
|
129
|
-
...overrides,
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
return context;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* Simple template renderer with Handlebars-like syntax
|
|
137
|
-
* Supports: {{variable}}, {{#if condition}}, {{/if}}, {{#each array}}, {{/each}}
|
|
138
|
-
*
|
|
139
|
-
* @param {string} template - Template string
|
|
140
|
-
* @param {Object} context - Context object
|
|
141
|
-
* @returns {string} Rendered template
|
|
142
|
-
*/
|
|
143
|
-
function renderTemplate(template, context) {
|
|
144
|
-
let result = template;
|
|
145
|
-
|
|
146
|
-
// Process {{#if}} blocks
|
|
147
|
-
result = processIfBlocks(result, context);
|
|
148
|
-
|
|
149
|
-
// Process {{#each}} blocks
|
|
150
|
-
result = processEachBlocks(result, context);
|
|
151
|
-
|
|
152
|
-
// Replace simple variables {{variable}}
|
|
153
|
-
result = result.replace(/\{\{([^#/}][^}]*)\}\}/g, (match, key) => {
|
|
154
|
-
const value = getNestedValue(context, key.trim());
|
|
155
|
-
return value !== undefined ? String(value) : match;
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
// Clean up empty lines from removed blocks
|
|
159
|
-
result = result.replace(/\n{3,}/g, '\n\n');
|
|
160
|
-
|
|
161
|
-
return result;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* Process {{#if condition}}...{{/if}} blocks
|
|
166
|
-
*
|
|
167
|
-
* @param {string} template - Template string
|
|
168
|
-
* @param {Object} context - Context object
|
|
169
|
-
* @returns {string} Processed template
|
|
170
|
-
*/
|
|
171
|
-
function processIfBlocks(template, context) {
|
|
172
|
-
// Match if blocks (non-greedy, innermost first)
|
|
173
|
-
const ifRegex = /\{\{#if\s+(\w+)\}\}([\s\S]*?)\{\{\/if\}\}/g;
|
|
174
|
-
|
|
175
|
-
let result = template;
|
|
176
|
-
let iterations = 0;
|
|
177
|
-
const maxIterations = 100; // Prevent infinite loops
|
|
178
|
-
|
|
179
|
-
while (ifRegex.test(result) && iterations < maxIterations) {
|
|
180
|
-
result = result.replace(ifRegex, (match, condition, content) => {
|
|
181
|
-
const value = context[condition];
|
|
182
|
-
if (value) {
|
|
183
|
-
return content;
|
|
184
|
-
}
|
|
185
|
-
return '';
|
|
186
|
-
});
|
|
187
|
-
iterations++;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
return result;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* Process {{#each array}}...{{/each}} blocks
|
|
195
|
-
*
|
|
196
|
-
* @param {string} template - Template string
|
|
197
|
-
* @param {Object} context - Context object
|
|
198
|
-
* @returns {string} Processed template
|
|
199
|
-
*/
|
|
200
|
-
function processEachBlocks(template, context) {
|
|
201
|
-
const eachRegex = /\{\{#each\s+(\w+)\}\}([\s\S]*?)\{\{\/each\}\}/g;
|
|
202
|
-
|
|
203
|
-
return template.replace(eachRegex, (match, arrayName, content) => {
|
|
204
|
-
const array = context[arrayName];
|
|
205
|
-
if (!Array.isArray(array) || array.length === 0) {
|
|
206
|
-
return '';
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
return array
|
|
210
|
-
.map((item) => {
|
|
211
|
-
let itemContent = content;
|
|
212
|
-
if (typeof item === 'object') {
|
|
213
|
-
// Replace {{this.property}} with item properties
|
|
214
|
-
itemContent = itemContent.replace(/\{\{this\.(\w+)\}\}/g, (m, prop) => {
|
|
215
|
-
return item[prop] !== undefined ? String(item[prop]) : m;
|
|
216
|
-
});
|
|
217
|
-
} else {
|
|
218
|
-
// Replace {{this}} with item value
|
|
219
|
-
itemContent = itemContent.replace(/\{\{this\}\}/g, String(item));
|
|
220
|
-
}
|
|
221
|
-
return itemContent;
|
|
222
|
-
})
|
|
223
|
-
.join('');
|
|
224
|
-
});
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
/**
|
|
228
|
-
* Get nested value from object using dot notation
|
|
229
|
-
*
|
|
230
|
-
* @param {Object} obj - Object to search
|
|
231
|
-
* @param {string} path - Dot-notation path
|
|
232
|
-
* @returns {*} Value at path or undefined
|
|
233
|
-
*/
|
|
234
|
-
function getNestedValue(obj, path) {
|
|
235
|
-
return path.split('.').reduce((current, key) => {
|
|
236
|
-
return current && current[key] !== undefined ? current[key] : undefined;
|
|
237
|
-
}, obj);
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
/**
|
|
241
|
-
* Loads a template file
|
|
242
|
-
*
|
|
243
|
-
* @param {string} templateName - Template file name
|
|
244
|
-
* @returns {string} Template content
|
|
245
|
-
* @throws {Error} If template not found
|
|
246
|
-
*/
|
|
247
|
-
function loadTemplate(templateName) {
|
|
248
|
-
const templatePath = path.join(TEMPLATES_DIR, templateName);
|
|
249
|
-
|
|
250
|
-
if (!fs.existsSync(templatePath)) {
|
|
251
|
-
throw new Error(`Template not found: ${templatePath}`);
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
return fs.readFileSync(templatePath, 'utf8');
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
/**
|
|
258
|
-
* Generates all documentation files for a project
|
|
259
|
-
*
|
|
260
|
-
* @param {string} targetDir - Target directory
|
|
261
|
-
* @param {DocContext} context - Documentation context
|
|
262
|
-
* @param {Object} [options] - Generation options
|
|
263
|
-
* @param {boolean} [options.dryRun] - Don't write files, just return content
|
|
264
|
-
* @returns {Object} Generated files with content
|
|
265
|
-
*/
|
|
266
|
-
function generateDocs(targetDir, context, options = {}) {
|
|
267
|
-
const docsDir = path.join(targetDir, 'docs', 'architecture');
|
|
268
|
-
const results = {};
|
|
269
|
-
|
|
270
|
-
// Ensure docs directory exists
|
|
271
|
-
if (!options.dryRun) {
|
|
272
|
-
fs.mkdirSync(docsDir, { recursive: true });
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
// Generate each doc
|
|
276
|
-
const templates = [
|
|
277
|
-
{ template: TemplateFiles.SOURCE_TREE, output: OutputFiles.SOURCE_TREE },
|
|
278
|
-
{ template: TemplateFiles.CODING_STANDARDS, output: OutputFiles.CODING_STANDARDS },
|
|
279
|
-
{ template: TemplateFiles.TECH_STACK, output: OutputFiles.TECH_STACK },
|
|
280
|
-
];
|
|
281
|
-
|
|
282
|
-
for (const { template, output } of templates) {
|
|
283
|
-
try {
|
|
284
|
-
const templateContent = loadTemplate(template);
|
|
285
|
-
const rendered = renderTemplate(templateContent, context);
|
|
286
|
-
const outputPath = path.join(docsDir, output);
|
|
287
|
-
|
|
288
|
-
results[output] = {
|
|
289
|
-
path: outputPath,
|
|
290
|
-
content: rendered,
|
|
291
|
-
success: true,
|
|
292
|
-
};
|
|
293
|
-
|
|
294
|
-
if (!options.dryRun) {
|
|
295
|
-
fs.writeFileSync(outputPath, rendered, 'utf8');
|
|
296
|
-
}
|
|
297
|
-
} catch (error) {
|
|
298
|
-
results[output] = {
|
|
299
|
-
path: path.join(docsDir, output),
|
|
300
|
-
content: null,
|
|
301
|
-
success: false,
|
|
302
|
-
error: error.message,
|
|
303
|
-
};
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
return results;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
/**
|
|
311
|
-
* Generates a single documentation file
|
|
312
|
-
*
|
|
313
|
-
* @param {string} templateName - Template file name
|
|
314
|
-
* @param {DocContext} context - Documentation context
|
|
315
|
-
* @returns {string} Rendered content
|
|
316
|
-
*/
|
|
317
|
-
function generateDoc(templateName, context) {
|
|
318
|
-
const template = loadTemplate(templateName);
|
|
319
|
-
return renderTemplate(template, context);
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
module.exports = {
|
|
323
|
-
buildDocContext,
|
|
324
|
-
renderTemplate,
|
|
325
|
-
loadTemplate,
|
|
326
|
-
generateDocs,
|
|
327
|
-
generateDoc,
|
|
328
|
-
TemplateFiles,
|
|
329
|
-
OutputFiles,
|
|
330
|
-
TEMPLATES_DIR,
|
|
331
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* Documentation Generator Module
|
|
3
|
+
*
|
|
4
|
+
* Generates project-specific documentation from templates.
|
|
5
|
+
* Supports Node.js, Python, Go, and Rust projects.
|
|
6
|
+
*
|
|
7
|
+
* @module documentation-integrity/doc-generator
|
|
8
|
+
* @version 1.0.0
|
|
9
|
+
* @story 6.9
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const fs = require('fs');
|
|
13
|
+
const path = require('path');
|
|
14
|
+
|
|
15
|
+
// Template directory
|
|
16
|
+
const TEMPLATES_DIR = path.join(__dirname, '..', '..', 'templates', 'project-docs');
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Template file names
|
|
20
|
+
* @enum {string}
|
|
21
|
+
*/
|
|
22
|
+
const TemplateFiles = {
|
|
23
|
+
SOURCE_TREE: 'source-tree-tmpl.md',
|
|
24
|
+
CODING_STANDARDS: 'coding-standards-tmpl.md',
|
|
25
|
+
TECH_STACK: 'tech-stack-tmpl.md',
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Output file names
|
|
30
|
+
* @enum {string}
|
|
31
|
+
*/
|
|
32
|
+
const OutputFiles = {
|
|
33
|
+
SOURCE_TREE: 'source-tree.md',
|
|
34
|
+
CODING_STANDARDS: 'coding-standards.md',
|
|
35
|
+
TECH_STACK: 'tech-stack.md',
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Documentation context for template rendering
|
|
40
|
+
* @typedef {Object} DocContext
|
|
41
|
+
* @property {string} PROJECT_NAME - Project name
|
|
42
|
+
* @property {string} GENERATED_DATE - Generation date
|
|
43
|
+
* @property {string} INSTALLATION_MODE - Installation mode
|
|
44
|
+
* @property {string} TECH_STACK - Detected tech stack
|
|
45
|
+
* @property {boolean} IS_NODE - Is Node.js project
|
|
46
|
+
* @property {boolean} IS_PYTHON - Is Python project
|
|
47
|
+
* @property {boolean} IS_GO - Is Go project
|
|
48
|
+
* @property {boolean} IS_RUST - Is Rust project
|
|
49
|
+
* @property {boolean} IS_TYPESCRIPT - Uses TypeScript
|
|
50
|
+
*/
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Builds documentation context from detected markers
|
|
54
|
+
*
|
|
55
|
+
* @param {string} projectName - Project name
|
|
56
|
+
* @param {string} mode - Installation mode
|
|
57
|
+
* @param {Object} markers - Detected project markers
|
|
58
|
+
* @param {Object} [overrides] - Optional context overrides
|
|
59
|
+
* @returns {DocContext} Documentation context
|
|
60
|
+
*/
|
|
61
|
+
function buildDocContext(projectName, mode, markers, overrides = {}) {
|
|
62
|
+
// Detect tech stack from markers
|
|
63
|
+
const techStacks = [];
|
|
64
|
+
if (markers.hasPackageJson) techStacks.push('Node.js');
|
|
65
|
+
if (markers.hasPythonProject) techStacks.push('Python');
|
|
66
|
+
if (markers.hasGoMod) techStacks.push('Go');
|
|
67
|
+
if (markers.hasCargoToml) techStacks.push('Rust');
|
|
68
|
+
|
|
69
|
+
// Determine file extension
|
|
70
|
+
let fileExt = 'js';
|
|
71
|
+
if (markers.hasTsconfig) fileExt = 'ts';
|
|
72
|
+
|
|
73
|
+
// Build context
|
|
74
|
+
const context = {
|
|
75
|
+
// Basic info
|
|
76
|
+
PROJECT_NAME: projectName,
|
|
77
|
+
GENERATED_DATE: new Date().toISOString().split('T')[0],
|
|
78
|
+
INSTALLATION_MODE: mode,
|
|
79
|
+
TECH_STACK: techStacks.join(', ') || 'Unknown',
|
|
80
|
+
|
|
81
|
+
// Language flags
|
|
82
|
+
IS_NODE: markers.hasPackageJson || false,
|
|
83
|
+
IS_PYTHON: markers.hasPythonProject || false,
|
|
84
|
+
IS_GO: markers.hasGoMod || false,
|
|
85
|
+
IS_RUST: markers.hasCargoToml || false,
|
|
86
|
+
IS_TYPESCRIPT: markers.hasTsconfig || false,
|
|
87
|
+
|
|
88
|
+
// Node.js specific
|
|
89
|
+
FILE_EXT: fileExt,
|
|
90
|
+
NODE_VERSION: '18+',
|
|
91
|
+
TYPESCRIPT_VERSION: '5.0+',
|
|
92
|
+
NPM_VERSION: '9+',
|
|
93
|
+
SEMICOLONS: 'Required',
|
|
94
|
+
SEMICOLONS_RULE: 'always',
|
|
95
|
+
PRETTIER_SEMI: true,
|
|
96
|
+
|
|
97
|
+
// Python specific
|
|
98
|
+
PYTHON_PACKAGE_NAME: projectName.toLowerCase().replace(/[^a-z0-9]/g, '_'),
|
|
99
|
+
PYTHON_VERSION: '3.11+',
|
|
100
|
+
PYTHON_SHORT_VERSION: '311',
|
|
101
|
+
POETRY_VERSION: '1.5+',
|
|
102
|
+
|
|
103
|
+
// Go specific
|
|
104
|
+
GO_VERSION: '1.21+',
|
|
105
|
+
GO_MODULE: `github.com/user/${projectName}`,
|
|
106
|
+
|
|
107
|
+
// Rust specific
|
|
108
|
+
RUST_VERSION: '1.70+',
|
|
109
|
+
|
|
110
|
+
// Deployment
|
|
111
|
+
DEPLOYMENT_PLATFORM: null,
|
|
112
|
+
PRODUCTION_BRANCH: 'main',
|
|
113
|
+
STAGING_BRANCH: 'staging',
|
|
114
|
+
HAS_STAGING: false,
|
|
115
|
+
|
|
116
|
+
// Database
|
|
117
|
+
DATABASE: null,
|
|
118
|
+
CACHE: null,
|
|
119
|
+
|
|
120
|
+
// Quality gates
|
|
121
|
+
QUALITY_GATES: ['Lint', 'Type Check', 'Tests'],
|
|
122
|
+
|
|
123
|
+
// Dependencies (to be populated by analyzer)
|
|
124
|
+
DEPENDENCIES: [],
|
|
125
|
+
DEV_DEPENDENCIES: [],
|
|
126
|
+
ENV_VARS: [],
|
|
127
|
+
|
|
128
|
+
// Apply overrides
|
|
129
|
+
...overrides,
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
return context;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Simple template renderer with Handlebars-like syntax
|
|
137
|
+
* Supports: {{variable}}, {{#if condition}}, {{/if}}, {{#each array}}, {{/each}}
|
|
138
|
+
*
|
|
139
|
+
* @param {string} template - Template string
|
|
140
|
+
* @param {Object} context - Context object
|
|
141
|
+
* @returns {string} Rendered template
|
|
142
|
+
*/
|
|
143
|
+
function renderTemplate(template, context) {
|
|
144
|
+
let result = template;
|
|
145
|
+
|
|
146
|
+
// Process {{#if}} blocks
|
|
147
|
+
result = processIfBlocks(result, context);
|
|
148
|
+
|
|
149
|
+
// Process {{#each}} blocks
|
|
150
|
+
result = processEachBlocks(result, context);
|
|
151
|
+
|
|
152
|
+
// Replace simple variables {{variable}}
|
|
153
|
+
result = result.replace(/\{\{([^#/}][^}]*)\}\}/g, (match, key) => {
|
|
154
|
+
const value = getNestedValue(context, key.trim());
|
|
155
|
+
return value !== undefined ? String(value) : match;
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
// Clean up empty lines from removed blocks
|
|
159
|
+
result = result.replace(/\n{3,}/g, '\n\n');
|
|
160
|
+
|
|
161
|
+
return result;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Process {{#if condition}}...{{/if}} blocks
|
|
166
|
+
*
|
|
167
|
+
* @param {string} template - Template string
|
|
168
|
+
* @param {Object} context - Context object
|
|
169
|
+
* @returns {string} Processed template
|
|
170
|
+
*/
|
|
171
|
+
function processIfBlocks(template, context) {
|
|
172
|
+
// Match if blocks (non-greedy, innermost first)
|
|
173
|
+
const ifRegex = /\{\{#if\s+(\w+)\}\}([\s\S]*?)\{\{\/if\}\}/g;
|
|
174
|
+
|
|
175
|
+
let result = template;
|
|
176
|
+
let iterations = 0;
|
|
177
|
+
const maxIterations = 100; // Prevent infinite loops
|
|
178
|
+
|
|
179
|
+
while (ifRegex.test(result) && iterations < maxIterations) {
|
|
180
|
+
result = result.replace(ifRegex, (match, condition, content) => {
|
|
181
|
+
const value = context[condition];
|
|
182
|
+
if (value) {
|
|
183
|
+
return content;
|
|
184
|
+
}
|
|
185
|
+
return '';
|
|
186
|
+
});
|
|
187
|
+
iterations++;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return result;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Process {{#each array}}...{{/each}} blocks
|
|
195
|
+
*
|
|
196
|
+
* @param {string} template - Template string
|
|
197
|
+
* @param {Object} context - Context object
|
|
198
|
+
* @returns {string} Processed template
|
|
199
|
+
*/
|
|
200
|
+
function processEachBlocks(template, context) {
|
|
201
|
+
const eachRegex = /\{\{#each\s+(\w+)\}\}([\s\S]*?)\{\{\/each\}\}/g;
|
|
202
|
+
|
|
203
|
+
return template.replace(eachRegex, (match, arrayName, content) => {
|
|
204
|
+
const array = context[arrayName];
|
|
205
|
+
if (!Array.isArray(array) || array.length === 0) {
|
|
206
|
+
return '';
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
return array
|
|
210
|
+
.map((item) => {
|
|
211
|
+
let itemContent = content;
|
|
212
|
+
if (typeof item === 'object') {
|
|
213
|
+
// Replace {{this.property}} with item properties
|
|
214
|
+
itemContent = itemContent.replace(/\{\{this\.(\w+)\}\}/g, (m, prop) => {
|
|
215
|
+
return item[prop] !== undefined ? String(item[prop]) : m;
|
|
216
|
+
});
|
|
217
|
+
} else {
|
|
218
|
+
// Replace {{this}} with item value
|
|
219
|
+
itemContent = itemContent.replace(/\{\{this\}\}/g, String(item));
|
|
220
|
+
}
|
|
221
|
+
return itemContent;
|
|
222
|
+
})
|
|
223
|
+
.join('');
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Get nested value from object using dot notation
|
|
229
|
+
*
|
|
230
|
+
* @param {Object} obj - Object to search
|
|
231
|
+
* @param {string} path - Dot-notation path
|
|
232
|
+
* @returns {*} Value at path or undefined
|
|
233
|
+
*/
|
|
234
|
+
function getNestedValue(obj, path) {
|
|
235
|
+
return path.split('.').reduce((current, key) => {
|
|
236
|
+
return current && current[key] !== undefined ? current[key] : undefined;
|
|
237
|
+
}, obj);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Loads a template file
|
|
242
|
+
*
|
|
243
|
+
* @param {string} templateName - Template file name
|
|
244
|
+
* @returns {string} Template content
|
|
245
|
+
* @throws {Error} If template not found
|
|
246
|
+
*/
|
|
247
|
+
function loadTemplate(templateName) {
|
|
248
|
+
const templatePath = path.join(TEMPLATES_DIR, templateName);
|
|
249
|
+
|
|
250
|
+
if (!fs.existsSync(templatePath)) {
|
|
251
|
+
throw new Error(`Template not found: ${templatePath}`);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
return fs.readFileSync(templatePath, 'utf8');
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Generates all documentation files for a project
|
|
259
|
+
*
|
|
260
|
+
* @param {string} targetDir - Target directory
|
|
261
|
+
* @param {DocContext} context - Documentation context
|
|
262
|
+
* @param {Object} [options] - Generation options
|
|
263
|
+
* @param {boolean} [options.dryRun] - Don't write files, just return content
|
|
264
|
+
* @returns {Object} Generated files with content
|
|
265
|
+
*/
|
|
266
|
+
function generateDocs(targetDir, context, options = {}) {
|
|
267
|
+
const docsDir = path.join(targetDir, 'docs', 'architecture');
|
|
268
|
+
const results = {};
|
|
269
|
+
|
|
270
|
+
// Ensure docs directory exists
|
|
271
|
+
if (!options.dryRun) {
|
|
272
|
+
fs.mkdirSync(docsDir, { recursive: true });
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Generate each doc
|
|
276
|
+
const templates = [
|
|
277
|
+
{ template: TemplateFiles.SOURCE_TREE, output: OutputFiles.SOURCE_TREE },
|
|
278
|
+
{ template: TemplateFiles.CODING_STANDARDS, output: OutputFiles.CODING_STANDARDS },
|
|
279
|
+
{ template: TemplateFiles.TECH_STACK, output: OutputFiles.TECH_STACK },
|
|
280
|
+
];
|
|
281
|
+
|
|
282
|
+
for (const { template, output } of templates) {
|
|
283
|
+
try {
|
|
284
|
+
const templateContent = loadTemplate(template);
|
|
285
|
+
const rendered = renderTemplate(templateContent, context);
|
|
286
|
+
const outputPath = path.join(docsDir, output);
|
|
287
|
+
|
|
288
|
+
results[output] = {
|
|
289
|
+
path: outputPath,
|
|
290
|
+
content: rendered,
|
|
291
|
+
success: true,
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
if (!options.dryRun) {
|
|
295
|
+
fs.writeFileSync(outputPath, rendered, 'utf8');
|
|
296
|
+
}
|
|
297
|
+
} catch (error) {
|
|
298
|
+
results[output] = {
|
|
299
|
+
path: path.join(docsDir, output),
|
|
300
|
+
content: null,
|
|
301
|
+
success: false,
|
|
302
|
+
error: error.message,
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
return results;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Generates a single documentation file
|
|
312
|
+
*
|
|
313
|
+
* @param {string} templateName - Template file name
|
|
314
|
+
* @param {DocContext} context - Documentation context
|
|
315
|
+
* @returns {string} Rendered content
|
|
316
|
+
*/
|
|
317
|
+
function generateDoc(templateName, context) {
|
|
318
|
+
const template = loadTemplate(templateName);
|
|
319
|
+
return renderTemplate(template, context);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
module.exports = {
|
|
323
|
+
buildDocContext,
|
|
324
|
+
renderTemplate,
|
|
325
|
+
loadTemplate,
|
|
326
|
+
generateDocs,
|
|
327
|
+
generateDoc,
|
|
328
|
+
TemplateFiles,
|
|
329
|
+
OutputFiles,
|
|
330
|
+
TEMPLATES_DIR,
|
|
331
|
+
};
|