ccsetup 1.2.0 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +93 -24
- package/bin/create-project.js +373 -773
- package/lib/templates/README.md +2 -2
- package/lib/templates/metadata/agents.json +1 -1
- package/package.json +3 -2
- package/template/.claude/settings.json +18 -1
- package/template/.claude/skills/codex-review/SKILL.md +139 -0
- package/template/.claude/skills/secops/SKILL.md +259 -0
- package/template/.codex/skills/codex-review/SKILL.md +139 -0
- package/template/.codex/skills/prd/SKILL.md +343 -0
- package/template/.codex/skills/ralph/SKILL.md +339 -0
- package/template/AGENTS.md +43 -0
- package/template/CLAUDE.md +106 -4
- package/template/docs/codex-setup.md +32 -0
- package/template/hooks/codex-review/index.js +105 -0
- package/template/scripts/codex-review/codex-review.sh +266 -0
- package/template/scripts/ralph/CODEX.md +76 -0
- package/template/scripts/ralph/ralph.sh +32 -9
- package/bin/lib/contextGenerator.js +0 -287
- package/bin/lib/scanner/index.js +0 -28
- package/bin/scan.js +0 -367
- package/lib/aiMergeHelper.js +0 -112
- package/lib/contextGenerator.js +0 -574
- package/lib/contextMerger.js +0 -812
- package/lib/progressReporter.js +0 -88
- package/lib/scanConfig.js +0 -200
- package/lib/scanner/fileAnalyzer.js +0 -605
- package/lib/scanner/index.js +0 -164
- package/lib/scanner/patterns.js +0 -277
- package/lib/scanner/projectDetector.js +0 -147
|
@@ -1,605 +0,0 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
const patterns = require('./patterns');
|
|
4
|
-
|
|
5
|
-
class FileAnalyzer {
|
|
6
|
-
constructor(projectPath, options = {}) {
|
|
7
|
-
this.projectPath = projectPath;
|
|
8
|
-
this.options = options;
|
|
9
|
-
this.gitignorePatterns = this.loadGitignore();
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
loadGitignore() {
|
|
13
|
-
const gitignorePath = path.join(this.projectPath, '.gitignore');
|
|
14
|
-
const patterns = ['node_modules/', '.git/', 'dist/', 'build/', '*.log'];
|
|
15
|
-
|
|
16
|
-
try {
|
|
17
|
-
if (fs.existsSync(gitignorePath)) {
|
|
18
|
-
const content = fs.readFileSync(gitignorePath, 'utf8');
|
|
19
|
-
const gitPatterns = content
|
|
20
|
-
.split('\n')
|
|
21
|
-
.map(line => line.trim())
|
|
22
|
-
.filter(line => line && !line.startsWith('#'));
|
|
23
|
-
patterns.push(...gitPatterns);
|
|
24
|
-
}
|
|
25
|
-
} catch (error) {
|
|
26
|
-
console.warn('Warning: Could not read .gitignore file');
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
return patterns;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
shouldIgnore(filePath) {
|
|
33
|
-
if (!this.options.respectGitignore) return false;
|
|
34
|
-
|
|
35
|
-
const relativePath = path.relative(this.projectPath, filePath);
|
|
36
|
-
return this.gitignorePatterns.some(pattern => {
|
|
37
|
-
if (pattern.endsWith('/')) {
|
|
38
|
-
return relativePath.startsWith(pattern.slice(0, -1));
|
|
39
|
-
}
|
|
40
|
-
return relativePath.includes(pattern) || relativePath.endsWith(pattern);
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
async analyzeStructure() {
|
|
45
|
-
const structure = {
|
|
46
|
-
directories: [],
|
|
47
|
-
keyFiles: [],
|
|
48
|
-
fileTypes: {},
|
|
49
|
-
totalFiles: 0,
|
|
50
|
-
totalSize: 0
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
await this.walkDirectory(this.projectPath, structure, 0);
|
|
54
|
-
|
|
55
|
-
structure.keyFiles = this.identifyKeyFiles(structure.directories);
|
|
56
|
-
|
|
57
|
-
return structure;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
async walkDirectory(dirPath, structure, depth) {
|
|
61
|
-
if (depth > 10 || structure.totalFiles > this.options.maxFiles) return;
|
|
62
|
-
|
|
63
|
-
try {
|
|
64
|
-
const items = fs.readdirSync(dirPath);
|
|
65
|
-
|
|
66
|
-
for (const item of items) {
|
|
67
|
-
const fullPath = path.join(dirPath, item);
|
|
68
|
-
const relativePath = path.relative(this.projectPath, fullPath);
|
|
69
|
-
|
|
70
|
-
if (this.shouldIgnore(fullPath)) continue;
|
|
71
|
-
|
|
72
|
-
const stats = fs.statSync(fullPath);
|
|
73
|
-
|
|
74
|
-
if (stats.isDirectory()) {
|
|
75
|
-
structure.directories.push({
|
|
76
|
-
path: relativePath,
|
|
77
|
-
name: item,
|
|
78
|
-
depth
|
|
79
|
-
});
|
|
80
|
-
await this.walkDirectory(fullPath, structure, depth + 1);
|
|
81
|
-
} else if (stats.isFile()) {
|
|
82
|
-
structure.totalFiles++;
|
|
83
|
-
structure.totalSize += stats.size;
|
|
84
|
-
|
|
85
|
-
const ext = path.extname(item);
|
|
86
|
-
structure.fileTypes[ext] = (structure.fileTypes[ext] || 0) + 1;
|
|
87
|
-
|
|
88
|
-
if (stats.size < this.options.maxFileSize) {
|
|
89
|
-
this.analyzeFile(fullPath, relativePath, structure);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
} catch (error) {
|
|
94
|
-
console.warn(`Warning: Could not read directory ${dirPath}: ${error.message}`);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
analyzeFile(filePath, relativePath, structure) {
|
|
99
|
-
const fileName = path.basename(filePath);
|
|
100
|
-
|
|
101
|
-
if (patterns.KEY_FILES.includes(fileName.toLowerCase()) ||
|
|
102
|
-
patterns.CONFIG_FILES.some(pattern => fileName.match(pattern))) {
|
|
103
|
-
structure.keyFiles.push({
|
|
104
|
-
path: relativePath,
|
|
105
|
-
name: fileName,
|
|
106
|
-
type: this.categorizeFile(fileName)
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
categorizeFile(fileName) {
|
|
112
|
-
const name = fileName.toLowerCase();
|
|
113
|
-
|
|
114
|
-
if (name.includes('package.json')) return 'package-manager';
|
|
115
|
-
if (name.includes('dockerfile')) return 'containerization';
|
|
116
|
-
if (name.includes('docker-compose')) return 'containerization';
|
|
117
|
-
if (name.includes('makefile')) return 'build';
|
|
118
|
-
if (name.includes('readme')) return 'documentation';
|
|
119
|
-
if (name.includes('license')) return 'legal';
|
|
120
|
-
if (name.includes('changelog')) return 'documentation';
|
|
121
|
-
if (name.includes('config') || name.includes('settings')) return 'configuration';
|
|
122
|
-
if (name.includes('env')) return 'environment';
|
|
123
|
-
if (name.includes('test') || name.includes('spec')) return 'testing';
|
|
124
|
-
|
|
125
|
-
return 'other';
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
identifyKeyFiles(directories) {
|
|
129
|
-
const keyFiles = [];
|
|
130
|
-
const importantPaths = [
|
|
131
|
-
'src', 'lib', 'app', 'components', 'pages', 'routes',
|
|
132
|
-
'controllers', 'models', 'views', 'services', 'utils',
|
|
133
|
-
'tests', 'test', '__tests__', 'spec', 'specs',
|
|
134
|
-
'docs', 'documentation', 'config', 'configurations'
|
|
135
|
-
];
|
|
136
|
-
|
|
137
|
-
for (const dir of directories) {
|
|
138
|
-
if (importantPaths.includes(dir.name.toLowerCase())) {
|
|
139
|
-
keyFiles.push({
|
|
140
|
-
path: dir.path,
|
|
141
|
-
name: dir.name,
|
|
142
|
-
type: 'directory',
|
|
143
|
-
importance: this.calculateImportance(dir.name)
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
return keyFiles.sort((a, b) => b.importance - a.importance);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
calculateImportance(dirName) {
|
|
152
|
-
const importance = {
|
|
153
|
-
src: 10, lib: 9, app: 8, components: 7, pages: 6,
|
|
154
|
-
controllers: 8, models: 7, views: 6, services: 7,
|
|
155
|
-
tests: 5, docs: 4, config: 3
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
return importance[dirName.toLowerCase()] || 1;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
async extractDependencies() {
|
|
162
|
-
const dependencies = {
|
|
163
|
-
runtime: [],
|
|
164
|
-
development: [],
|
|
165
|
-
system: [],
|
|
166
|
-
frameworks: []
|
|
167
|
-
};
|
|
168
|
-
|
|
169
|
-
await this.extractFromPackageJson(dependencies);
|
|
170
|
-
await this.extractFromRequirementsTxt(dependencies);
|
|
171
|
-
await this.extractFromGoMod(dependencies);
|
|
172
|
-
await this.extractFromCargoToml(dependencies);
|
|
173
|
-
await this.extractFromPomXml(dependencies);
|
|
174
|
-
|
|
175
|
-
return dependencies;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
async extractFromPackageJson(dependencies) {
|
|
179
|
-
const packagePath = path.join(this.projectPath, 'package.json');
|
|
180
|
-
|
|
181
|
-
try {
|
|
182
|
-
if (fs.existsSync(packagePath)) {
|
|
183
|
-
const content = fs.readFileSync(packagePath, 'utf8');
|
|
184
|
-
const pkg = JSON.parse(content);
|
|
185
|
-
|
|
186
|
-
if (pkg.dependencies) {
|
|
187
|
-
for (const [name, version] of Object.entries(pkg.dependencies)) {
|
|
188
|
-
dependencies.runtime.push({ name, version, type: 'npm' });
|
|
189
|
-
if (patterns.FRAMEWORK_PACKAGES[name]) {
|
|
190
|
-
dependencies.frameworks.push({
|
|
191
|
-
name: patterns.FRAMEWORK_PACKAGES[name],
|
|
192
|
-
package: name,
|
|
193
|
-
version
|
|
194
|
-
});
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
if (pkg.devDependencies) {
|
|
200
|
-
for (const [name, version] of Object.entries(pkg.devDependencies)) {
|
|
201
|
-
dependencies.development.push({ name, version, type: 'npm' });
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
} catch (error) {
|
|
206
|
-
console.warn('Warning: Could not parse package.json');
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
async extractFromRequirementsTxt(dependencies) {
|
|
211
|
-
const reqPath = path.join(this.projectPath, 'requirements.txt');
|
|
212
|
-
|
|
213
|
-
try {
|
|
214
|
-
if (fs.existsSync(reqPath)) {
|
|
215
|
-
const content = fs.readFileSync(reqPath, 'utf8');
|
|
216
|
-
const lines = content.split('\n').filter(line => line.trim() && !line.startsWith('#'));
|
|
217
|
-
|
|
218
|
-
for (const line of lines) {
|
|
219
|
-
const match = line.match(/^([a-zA-Z0-9_-]+)([>=<~!]+.+)?$/);
|
|
220
|
-
if (match) {
|
|
221
|
-
dependencies.runtime.push({
|
|
222
|
-
name: match[1],
|
|
223
|
-
version: match[2] || 'latest',
|
|
224
|
-
type: 'pip'
|
|
225
|
-
});
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
} catch (error) {
|
|
230
|
-
console.warn('Warning: Could not parse requirements.txt');
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
async extractFromGoMod(dependencies) {
|
|
235
|
-
const goModPath = path.join(this.projectPath, 'go.mod');
|
|
236
|
-
|
|
237
|
-
try {
|
|
238
|
-
if (fs.existsSync(goModPath)) {
|
|
239
|
-
const content = fs.readFileSync(goModPath, 'utf8');
|
|
240
|
-
const requireRegex = /require\s+([^\s]+)\s+([^\s]+)/g;
|
|
241
|
-
let match;
|
|
242
|
-
|
|
243
|
-
while ((match = requireRegex.exec(content)) !== null) {
|
|
244
|
-
dependencies.runtime.push({
|
|
245
|
-
name: match[1],
|
|
246
|
-
version: match[2],
|
|
247
|
-
type: 'go'
|
|
248
|
-
});
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
} catch (error) {
|
|
252
|
-
console.warn('Warning: Could not parse go.mod');
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
async extractFromCargoToml(dependencies) {
|
|
257
|
-
const cargoPath = path.join(this.projectPath, 'Cargo.toml');
|
|
258
|
-
|
|
259
|
-
try {
|
|
260
|
-
if (fs.existsSync(cargoPath)) {
|
|
261
|
-
const content = fs.readFileSync(cargoPath, 'utf8');
|
|
262
|
-
const depSection = content.match(/\[dependencies\]([\s\S]*?)(?=\[|$)/);
|
|
263
|
-
|
|
264
|
-
if (depSection) {
|
|
265
|
-
const lines = depSection[1].split('\n').filter(line => line.trim() && !line.startsWith('#'));
|
|
266
|
-
for (const line of lines) {
|
|
267
|
-
const match = line.match(/^([a-zA-Z0-9_-]+)\s*=\s*["']([^"']+)["']/);
|
|
268
|
-
if (match) {
|
|
269
|
-
dependencies.runtime.push({
|
|
270
|
-
name: match[1],
|
|
271
|
-
version: match[2],
|
|
272
|
-
type: 'cargo'
|
|
273
|
-
});
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
} catch (error) {
|
|
279
|
-
console.warn('Warning: Could not parse Cargo.toml');
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
async extractFromPomXml(dependencies) {
|
|
284
|
-
const pomPath = path.join(this.projectPath, 'pom.xml');
|
|
285
|
-
|
|
286
|
-
try {
|
|
287
|
-
if (fs.existsSync(pomPath)) {
|
|
288
|
-
const content = fs.readFileSync(pomPath, 'utf8');
|
|
289
|
-
const depRegex = /<groupId>([^<]+)<\/groupId>\s*<artifactId>([^<]+)<\/artifactId>\s*<version>([^<]+)<\/version>/g;
|
|
290
|
-
let match;
|
|
291
|
-
|
|
292
|
-
while ((match = depRegex.exec(content)) !== null) {
|
|
293
|
-
dependencies.runtime.push({
|
|
294
|
-
name: `${match[1]}:${match[2]}`,
|
|
295
|
-
version: match[3],
|
|
296
|
-
type: 'maven'
|
|
297
|
-
});
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
} catch (error) {
|
|
301
|
-
console.warn('Warning: Could not parse pom.xml');
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
async extractCommands() {
|
|
306
|
-
const commands = {
|
|
307
|
-
build: [],
|
|
308
|
-
dev: [],
|
|
309
|
-
test: [],
|
|
310
|
-
deploy: [],
|
|
311
|
-
other: []
|
|
312
|
-
};
|
|
313
|
-
|
|
314
|
-
await this.extractFromPackageJsonScripts(commands);
|
|
315
|
-
await this.extractFromMakefile(commands);
|
|
316
|
-
await this.extractFromDockerfile(commands);
|
|
317
|
-
|
|
318
|
-
return commands;
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
async extractFromPackageJsonScripts(commands) {
|
|
322
|
-
const packagePath = path.join(this.projectPath, 'package.json');
|
|
323
|
-
|
|
324
|
-
try {
|
|
325
|
-
if (fs.existsSync(packagePath)) {
|
|
326
|
-
const content = fs.readFileSync(packagePath, 'utf8');
|
|
327
|
-
const pkg = JSON.parse(content);
|
|
328
|
-
|
|
329
|
-
if (pkg.scripts) {
|
|
330
|
-
for (const [name, script] of Object.entries(pkg.scripts)) {
|
|
331
|
-
const category = this.categorizeCommand(name);
|
|
332
|
-
commands[category].push({
|
|
333
|
-
name: `npm run ${name}`,
|
|
334
|
-
script,
|
|
335
|
-
description: this.describeCommand(name, script)
|
|
336
|
-
});
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
} catch (error) {
|
|
341
|
-
console.warn('Warning: Could not extract npm scripts');
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
async extractFromMakefile(commands) {
|
|
346
|
-
const makefilePath = path.join(this.projectPath, 'Makefile');
|
|
347
|
-
|
|
348
|
-
try {
|
|
349
|
-
if (fs.existsSync(makefilePath)) {
|
|
350
|
-
const content = fs.readFileSync(makefilePath, 'utf8');
|
|
351
|
-
const targetRegex = /^([a-zA-Z0-9_-]+):/gm;
|
|
352
|
-
let match;
|
|
353
|
-
|
|
354
|
-
while ((match = targetRegex.exec(content)) !== null) {
|
|
355
|
-
const target = match[1];
|
|
356
|
-
if (target !== '.PHONY') {
|
|
357
|
-
const category = this.categorizeCommand(target);
|
|
358
|
-
commands[category].push({
|
|
359
|
-
name: `make ${target}`,
|
|
360
|
-
description: `Execute make target: ${target}`
|
|
361
|
-
});
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
} catch (error) {
|
|
366
|
-
console.warn('Warning: Could not parse Makefile');
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
async extractFromDockerfile(commands) {
|
|
371
|
-
const dockerfilePath = path.join(this.projectPath, 'Dockerfile');
|
|
372
|
-
const composePath = path.join(this.projectPath, 'docker-compose.yml');
|
|
373
|
-
|
|
374
|
-
if (fs.existsSync(dockerfilePath)) {
|
|
375
|
-
commands.deploy.push({
|
|
376
|
-
name: 'docker build .',
|
|
377
|
-
description: 'Build Docker image from Dockerfile'
|
|
378
|
-
});
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
if (fs.existsSync(composePath)) {
|
|
382
|
-
commands.dev.push({
|
|
383
|
-
name: 'docker-compose up',
|
|
384
|
-
description: 'Start development environment with Docker Compose'
|
|
385
|
-
});
|
|
386
|
-
commands.deploy.push({
|
|
387
|
-
name: 'docker-compose up -d',
|
|
388
|
-
description: 'Deploy with Docker Compose in detached mode'
|
|
389
|
-
});
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
categorizeCommand(commandName) {
|
|
394
|
-
const name = commandName.toLowerCase();
|
|
395
|
-
|
|
396
|
-
if (name.includes('build') || name.includes('compile')) return 'build';
|
|
397
|
-
if (name.includes('dev') || name.includes('start') || name.includes('serve')) return 'dev';
|
|
398
|
-
if (name.includes('test') || name.includes('spec')) return 'test';
|
|
399
|
-
if (name.includes('deploy') || name.includes('publish') || name.includes('release')) return 'deploy';
|
|
400
|
-
|
|
401
|
-
return 'other';
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
describeCommand(name, script) {
|
|
405
|
-
const descriptions = {
|
|
406
|
-
start: 'Start the application',
|
|
407
|
-
dev: 'Start development server',
|
|
408
|
-
build: 'Build the application for production',
|
|
409
|
-
test: 'Run test suite',
|
|
410
|
-
lint: 'Run code linting',
|
|
411
|
-
format: 'Format code',
|
|
412
|
-
deploy: 'Deploy the application'
|
|
413
|
-
};
|
|
414
|
-
|
|
415
|
-
return descriptions[name] || `Execute: ${script}`;
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
async detectPatterns() {
|
|
419
|
-
const detectedPatterns = {
|
|
420
|
-
architecture: [],
|
|
421
|
-
authentication: [],
|
|
422
|
-
database: [],
|
|
423
|
-
api: [],
|
|
424
|
-
testing: [],
|
|
425
|
-
deployment: []
|
|
426
|
-
};
|
|
427
|
-
|
|
428
|
-
await this.detectArchitecturePatterns(detectedPatterns);
|
|
429
|
-
await this.detectAuthPatterns(detectedPatterns);
|
|
430
|
-
await this.detectDatabasePatterns(detectedPatterns);
|
|
431
|
-
await this.detectApiPatterns(detectedPatterns);
|
|
432
|
-
await this.detectTestingPatterns(detectedPatterns);
|
|
433
|
-
await this.detectDeploymentPatterns(detectedPatterns);
|
|
434
|
-
|
|
435
|
-
return detectedPatterns;
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
async detectArchitecturePatterns(patterns) {
|
|
439
|
-
const directories = fs.readdirSync(this.projectPath).filter(item => {
|
|
440
|
-
const fullPath = path.join(this.projectPath, item);
|
|
441
|
-
return fs.statSync(fullPath).isDirectory() && !this.shouldIgnore(fullPath);
|
|
442
|
-
});
|
|
443
|
-
|
|
444
|
-
if (directories.includes('controllers') && directories.includes('models') && directories.includes('views')) {
|
|
445
|
-
patterns.architecture.push('MVC (Model-View-Controller)');
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
if (directories.includes('components') || directories.includes('containers')) {
|
|
449
|
-
patterns.architecture.push('Component-based architecture');
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
if (directories.includes('services') || directories.includes('domain')) {
|
|
453
|
-
patterns.architecture.push('Service-oriented architecture');
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
if (directories.includes('microservices') || fs.existsSync(path.join(this.projectPath, 'docker-compose.yml'))) {
|
|
457
|
-
patterns.architecture.push('Microservices architecture');
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
async detectAuthPatterns(patterns) {
|
|
462
|
-
const authKeywords = ['jwt', 'auth', 'passport', 'oauth', 'session'];
|
|
463
|
-
const packagePath = path.join(this.projectPath, 'package.json');
|
|
464
|
-
|
|
465
|
-
try {
|
|
466
|
-
if (fs.existsSync(packagePath)) {
|
|
467
|
-
const content = fs.readFileSync(packagePath, 'utf8');
|
|
468
|
-
const pkg = JSON.parse(content);
|
|
469
|
-
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
470
|
-
|
|
471
|
-
for (const dep of Object.keys(allDeps)) {
|
|
472
|
-
if (authKeywords.some(keyword => dep.toLowerCase().includes(keyword))) {
|
|
473
|
-
if (dep.includes('jwt')) patterns.authentication.push('JWT (JSON Web Tokens)');
|
|
474
|
-
if (dep.includes('passport')) patterns.authentication.push('Passport.js authentication');
|
|
475
|
-
if (dep.includes('oauth')) patterns.authentication.push('OAuth integration');
|
|
476
|
-
if (dep.includes('session')) patterns.authentication.push('Session-based authentication');
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
} catch (error) {
|
|
481
|
-
console.warn('Warning: Could not detect auth patterns');
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
async detectDatabasePatterns(patterns) {
|
|
486
|
-
const dbKeywords = {
|
|
487
|
-
'mongodb': 'MongoDB',
|
|
488
|
-
'mongoose': 'MongoDB with Mongoose ODM',
|
|
489
|
-
'mysql': 'MySQL',
|
|
490
|
-
'postgres': 'PostgreSQL',
|
|
491
|
-
'prisma': 'Prisma ORM',
|
|
492
|
-
'sequelize': 'Sequelize ORM',
|
|
493
|
-
'typeorm': 'TypeORM',
|
|
494
|
-
'redis': 'Redis'
|
|
495
|
-
};
|
|
496
|
-
|
|
497
|
-
const packagePath = path.join(this.projectPath, 'package.json');
|
|
498
|
-
|
|
499
|
-
try {
|
|
500
|
-
if (fs.existsSync(packagePath)) {
|
|
501
|
-
const content = fs.readFileSync(packagePath, 'utf8');
|
|
502
|
-
const pkg = JSON.parse(content);
|
|
503
|
-
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
504
|
-
|
|
505
|
-
for (const [keyword, description] of Object.entries(dbKeywords)) {
|
|
506
|
-
if (allDeps[keyword] || Object.keys(allDeps).some(dep => dep.includes(keyword))) {
|
|
507
|
-
patterns.database.push(description);
|
|
508
|
-
}
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
} catch (error) {
|
|
512
|
-
console.warn('Warning: Could not detect database patterns');
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
async detectApiPatterns(patterns) {
|
|
517
|
-
const apiKeywords = {
|
|
518
|
-
'express': 'Express.js REST API',
|
|
519
|
-
'fastify': 'Fastify API framework',
|
|
520
|
-
'koa': 'Koa.js API framework',
|
|
521
|
-
'graphql': 'GraphQL API',
|
|
522
|
-
'apollo': 'Apollo GraphQL',
|
|
523
|
-
'swagger': 'Swagger/OpenAPI documentation',
|
|
524
|
-
'axios': 'HTTP client with Axios',
|
|
525
|
-
'fetch': 'Fetch API usage'
|
|
526
|
-
};
|
|
527
|
-
|
|
528
|
-
const packagePath = path.join(this.projectPath, 'package.json');
|
|
529
|
-
|
|
530
|
-
try {
|
|
531
|
-
if (fs.existsSync(packagePath)) {
|
|
532
|
-
const content = fs.readFileSync(packagePath, 'utf8');
|
|
533
|
-
const pkg = JSON.parse(content);
|
|
534
|
-
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
535
|
-
|
|
536
|
-
for (const [keyword, description] of Object.entries(apiKeywords)) {
|
|
537
|
-
if (allDeps[keyword] || Object.keys(allDeps).some(dep => dep.includes(keyword))) {
|
|
538
|
-
patterns.api.push(description);
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
} catch (error) {
|
|
543
|
-
console.warn('Warning: Could not detect API patterns');
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
async detectTestingPatterns(patterns) {
|
|
548
|
-
const testKeywords = {
|
|
549
|
-
'jest': 'Jest testing framework',
|
|
550
|
-
'mocha': 'Mocha testing framework',
|
|
551
|
-
'chai': 'Chai assertion library',
|
|
552
|
-
'cypress': 'Cypress end-to-end testing',
|
|
553
|
-
'playwright': 'Playwright browser testing',
|
|
554
|
-
'supertest': 'API testing with Supertest',
|
|
555
|
-
'testing-library': 'React Testing Library',
|
|
556
|
-
'enzyme': 'Enzyme React testing'
|
|
557
|
-
};
|
|
558
|
-
|
|
559
|
-
const packagePath = path.join(this.projectPath, 'package.json');
|
|
560
|
-
|
|
561
|
-
try {
|
|
562
|
-
if (fs.existsSync(packagePath)) {
|
|
563
|
-
const content = fs.readFileSync(packagePath, 'utf8');
|
|
564
|
-
const pkg = JSON.parse(content);
|
|
565
|
-
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
566
|
-
|
|
567
|
-
for (const [keyword, description] of Object.entries(testKeywords)) {
|
|
568
|
-
if (allDeps[keyword] || Object.keys(allDeps).some(dep => dep.includes(keyword))) {
|
|
569
|
-
patterns.testing.push(description);
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
} catch (error) {
|
|
574
|
-
console.warn('Warning: Could not detect testing patterns');
|
|
575
|
-
}
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
async detectDeploymentPatterns(patterns) {
|
|
579
|
-
if (fs.existsSync(path.join(this.projectPath, 'Dockerfile'))) {
|
|
580
|
-
patterns.deployment.push('Docker containerization');
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
if (fs.existsSync(path.join(this.projectPath, 'docker-compose.yml'))) {
|
|
584
|
-
patterns.deployment.push('Docker Compose orchestration');
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
if (fs.existsSync(path.join(this.projectPath, '.github'))) {
|
|
588
|
-
patterns.deployment.push('GitHub Actions CI/CD');
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
if (fs.existsSync(path.join(this.projectPath, 'vercel.json'))) {
|
|
592
|
-
patterns.deployment.push('Vercel deployment');
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
if (fs.existsSync(path.join(this.projectPath, 'netlify.toml'))) {
|
|
596
|
-
patterns.deployment.push('Netlify deployment');
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
if (fs.existsSync(path.join(this.projectPath, 'serverless.yml'))) {
|
|
600
|
-
patterns.deployment.push('Serverless framework');
|
|
601
|
-
}
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
module.exports = FileAnalyzer;
|