project-context-ai 2.2.5 → 2.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.
Files changed (39) hide show
  1. package/dist/generators/template-sections.d.ts +8 -0
  2. package/dist/generators/template-sections.d.ts.map +1 -0
  3. package/dist/generators/template-sections.js +261 -0
  4. package/dist/generators/template-sections.js.map +1 -0
  5. package/dist/generators/template.d.ts +1 -6
  6. package/dist/generators/template.d.ts.map +1 -1
  7. package/dist/generators/template.js +2 -280
  8. package/dist/generators/template.js.map +1 -1
  9. package/dist/scanner/business.d.ts.map +1 -1
  10. package/dist/scanner/business.js +12 -726
  11. package/dist/scanner/business.js.map +1 -1
  12. package/dist/scanner/conventions.js +25 -6
  13. package/dist/scanner/conventions.js.map +1 -1
  14. package/dist/scanner/dependencies.d.ts.map +1 -1
  15. package/dist/scanner/dependencies.js +30 -0
  16. package/dist/scanner/dependencies.js.map +1 -1
  17. package/dist/scanner/description.d.ts +7 -0
  18. package/dist/scanner/description.d.ts.map +1 -0
  19. package/dist/scanner/description.js +172 -0
  20. package/dist/scanner/description.js.map +1 -0
  21. package/dist/scanner/domain.d.ts +10 -0
  22. package/dist/scanner/domain.d.ts.map +1 -0
  23. package/dist/scanner/domain.js +323 -0
  24. package/dist/scanner/domain.js.map +1 -0
  25. package/dist/scanner/frameworks.d.ts.map +1 -1
  26. package/dist/scanner/frameworks.js +13 -0
  27. package/dist/scanner/frameworks.js.map +1 -1
  28. package/dist/scanner/patterns-code.d.ts +9 -0
  29. package/dist/scanner/patterns-code.d.ts.map +1 -0
  30. package/dist/scanner/patterns-code.js +283 -0
  31. package/dist/scanner/patterns-code.js.map +1 -0
  32. package/dist/scanner/patterns.d.ts.map +1 -1
  33. package/dist/scanner/patterns.js +2 -288
  34. package/dist/scanner/patterns.js.map +1 -1
  35. package/dist/scanner/skills.d.ts +5 -0
  36. package/dist/scanner/skills.d.ts.map +1 -0
  37. package/dist/scanner/skills.js +242 -0
  38. package/dist/scanner/skills.js.map +1 -0
  39. package/package.json +1 -1
@@ -0,0 +1,283 @@
1
+ // ─── Code Detection Patterns (Error, Test, Architecture, Examples, Workflows, Conventions)
2
+ import { join } from "node:path";
3
+ import { readTextFile, readFilesMatching } from "../utils/files.js";
4
+ import { getScanConfig } from "./config.js";
5
+ // ─── Error Handling ───────────────────────────────────────
6
+ export async function detectErrorHandling(rootPath, allFiles) {
7
+ const patterns = [];
8
+ const cfg = getScanConfig();
9
+ const sourceFiles = await readFilesMatching(rootPath, allFiles, {
10
+ extensions: [".ts", ".js"],
11
+ maxFiles: cfg.maxFiles,
12
+ maxFileSize: cfg.maxFileSize,
13
+ });
14
+ for (const { file, content } of sourceFiles) {
15
+ const regex = /class\s+(\w+)\s+extends\s+(Error|BaseError|DomainError|AppError|HttpException|CustomError|BusinessError|NotFound|BadRequest|Unauthorized|Forbidden)\b/g;
16
+ let match;
17
+ while ((match = regex.exec(content)) !== null) {
18
+ patterns.push({ className: match[1], extendsFrom: match[2], file });
19
+ }
20
+ if (patterns.length >= 30)
21
+ break;
22
+ }
23
+ const seen = new Set();
24
+ return patterns.filter((p) => {
25
+ if (seen.has(p.className))
26
+ return false;
27
+ seen.add(p.className);
28
+ return true;
29
+ });
30
+ }
31
+ // ─── Test Patterns ────────────────────────────────────────
32
+ export async function detectTestPatterns(rootPath, allFiles, deps, frameworks) {
33
+ const depNames = deps.map((d) => d.name);
34
+ const fwNames = frameworks.map((f) => f.name);
35
+ let framework = "";
36
+ if (depNames.includes("vitest") || fwNames.includes("Vitest"))
37
+ framework = "Vitest";
38
+ else if (depNames.includes("jest") || depNames.includes("ts-jest") || fwNames.includes("Jest"))
39
+ framework = "Jest";
40
+ else if (depNames.includes("mocha"))
41
+ framework = "Mocha";
42
+ if (!framework)
43
+ return null;
44
+ let coverageThreshold = null;
45
+ const configFiles = allFiles.filter((f) => f.match(/(jest|vitest)\..*config\.(ts|js|mjs|cjs|json)$/));
46
+ for (const cf of configFiles.slice(0, 3)) {
47
+ const content = await readTextFile(join(rootPath, cf));
48
+ if (!content)
49
+ continue;
50
+ const thresholdMatch = content.match(/(?:branches|lines|functions|statements)\s*:\s*(\d+)/);
51
+ if (thresholdMatch) {
52
+ coverageThreshold = parseInt(thresholdMatch[1], 10);
53
+ break;
54
+ }
55
+ }
56
+ const testFiles = allFiles.filter((f) => f.match(/\.(test|spec)\.(ts|tsx|js|jsx)$/));
57
+ const specCount = testFiles.filter((f) => f.includes(".spec.")).length;
58
+ const testCount = testFiles.filter((f) => f.includes(".test.")).length;
59
+ const unitFilePattern = specCount > testCount ? "*.spec.ts" : "*.test.ts";
60
+ let integrationFilePattern = null;
61
+ if (allFiles.some((f) => f.includes("__tests__/")))
62
+ integrationFilePattern = "__tests__/**/*.test.ts";
63
+ else if (allFiles.some((f) => f.includes("e2e/")))
64
+ integrationFilePattern = "e2e/**/*.test.ts";
65
+ let testDir = "src/";
66
+ if (allFiles.some((f) => f.includes("__tests__/")))
67
+ testDir = "__tests__/";
68
+ else if (allFiles.some((f) => f.match(/^tests?\//)))
69
+ testDir = "tests/";
70
+ let assertionStyle = null;
71
+ if (testFiles.length > 0) {
72
+ const content = await readTextFile(join(rootPath, testFiles[0]));
73
+ if (content) {
74
+ if (content.includes("expect("))
75
+ assertionStyle = "expect() (Jest/Vitest)";
76
+ else if (content.includes("assert."))
77
+ assertionStyle = "assert (Node.js/Chai)";
78
+ }
79
+ }
80
+ return { framework, coverageThreshold, unitFilePattern, integrationFilePattern, testDir, assertionStyle };
81
+ }
82
+ // ─── Architectural Rules ──────────────────────────────────
83
+ export async function detectArchitecturalRules(rootPath, allFiles) {
84
+ const rules = [];
85
+ const dcFile = allFiles.find((f) => f.match(/\.dependency-cruiser\.(cjs|js|json)$/));
86
+ if (dcFile) {
87
+ const content = await readTextFile(join(rootPath, dcFile));
88
+ if (content) {
89
+ const nameRegex = /name\s*:\s*['"`]([^'"`]+)['"`]/g;
90
+ let match;
91
+ while ((match = nameRegex.exec(content)) !== null) {
92
+ rules.push(`Dependency rule: ${match[1]}`);
93
+ if (rules.length >= 10)
94
+ break;
95
+ }
96
+ }
97
+ }
98
+ const eslintFiles = allFiles.filter((f) => f.match(/eslint/i) && !f.includes("node_modules"));
99
+ for (const ef of eslintFiles.slice(0, 2)) {
100
+ const content = await readTextFile(join(rootPath, ef));
101
+ if (!content)
102
+ continue;
103
+ if (content.includes("import/no-restricted-paths") || content.includes("boundaries/element-types")) {
104
+ rules.push("ESLint enforced import boundaries between layers");
105
+ }
106
+ }
107
+ const hasDomain = allFiles.some((f) => f.match(/src\/(domain|core)\//));
108
+ const hasInfra = allFiles.some((f) => f.match(/src\/(infra|infrastructure)\//));
109
+ const hasApp = allFiles.some((f) => f.match(/src\/(application|use-?cases)\//));
110
+ if (hasDomain && hasInfra) {
111
+ const cfg = getScanConfig();
112
+ const domainFiles = await readFilesMatching(rootPath, allFiles, {
113
+ extensions: [".ts", ".js"],
114
+ maxFiles: cfg.maxFiles,
115
+ maxFileSize: cfg.maxFileSize,
116
+ pathPatterns: [/src\/(domain|core)\//],
117
+ });
118
+ let domainImportsInfra = false;
119
+ for (const { content } of domainFiles) {
120
+ if (content.match(/from\s+['"].*\/(infra|infrastructure)\//)) {
121
+ domainImportsInfra = true;
122
+ break;
123
+ }
124
+ }
125
+ if (!domainImportsInfra) {
126
+ rules.push("Domain/Core layer does NOT import from Infrastructure (Clean Architecture)");
127
+ }
128
+ if (hasApp) {
129
+ rules.push("Layers: Domain → Application → Infrastructure");
130
+ }
131
+ }
132
+ return rules;
133
+ }
134
+ // ─── Code Examples ────────────────────────────────────────
135
+ export async function extractCodeExamples(rootPath, allFiles, deps) {
136
+ const examples = [];
137
+ const depNames = deps.map((d) => d.name);
138
+ const categories = [
139
+ { category: "service", patterns: [/services?\//i], label: "Service pattern" },
140
+ { category: "controller", patterns: [/controllers?\//i], label: "Controller pattern" },
141
+ { category: "repository", patterns: [/repositor/i], label: "Repository pattern" },
142
+ { category: "middleware", patterns: [/middleware/i], label: "Middleware pattern" },
143
+ { category: "error-handling", patterns: [/(errors|exceptions)\//i], label: "Error handling" },
144
+ ];
145
+ for (const cat of categories) {
146
+ const candidates = allFiles.filter((f) => f.match(/\.(ts|js)$/) &&
147
+ cat.patterns.some((p) => p.test(f)) &&
148
+ !f.includes(".test.") && !f.includes(".spec.") &&
149
+ !f.includes("index.") && !f.includes("generated/"));
150
+ if (candidates.length === 0)
151
+ continue;
152
+ const content = await readTextFile(join(rootPath, candidates[0]));
153
+ if (!content)
154
+ continue;
155
+ const lines = content.split("\n").slice(0, 40);
156
+ const snippet = lines.join("\n");
157
+ const classMatch = snippet.match(/((?:export\s+)?(?:abstract\s+)?class\s+\w+[^{]*\{[^}]*(?:\n[^}]*){0,8})/);
158
+ const fnMatch = snippet.match(/((?:export\s+)?(?:async\s+)?function\s+\w+[^{]*\{[^}]*(?:\n[^}]*){0,5})/);
159
+ const code = classMatch?.[1] || fnMatch?.[1] || lines.slice(0, 15).join("\n");
160
+ if (code.trim().length > 30) {
161
+ examples.push({
162
+ file: candidates[0],
163
+ label: cat.label,
164
+ code: code.trim().slice(0, 500),
165
+ category: cat.category,
166
+ });
167
+ }
168
+ if (examples.length >= 6)
169
+ break;
170
+ }
171
+ if (depNames.includes("@cubos/inject") || depNames.includes("tsyringe") || depNames.includes("inversify")) {
172
+ const cfg = getScanConfig();
173
+ const diFiles = await readFilesMatching(rootPath, allFiles, {
174
+ extensions: [".ts"],
175
+ maxFiles: cfg.maxFiles,
176
+ maxFileSize: cfg.maxFileSize,
177
+ pathPatterns: [/(services?|controllers?|use-?cases?)\//],
178
+ });
179
+ for (const { file, content } of diFiles) {
180
+ const useMatch = content.match(/.*use\(\w+\).*/);
181
+ const injectMatch = content.match(/.*@Inject.*|.*@injectable.*/i);
182
+ const line = useMatch?.[0] || injectMatch?.[0];
183
+ if (line) {
184
+ examples.push({ file, label: "DI usage", code: line.trim(), category: "di" });
185
+ break;
186
+ }
187
+ }
188
+ }
189
+ return examples;
190
+ }
191
+ // ─── Workflows ────────────────────────────────────────────
192
+ export async function detectWorkflows(rootPath, allFiles, deps, frameworks) {
193
+ const workflows = [];
194
+ const depNames = deps.map((d) => d.name);
195
+ if (allFiles.some((f) => f.endsWith(".sdkgen"))) {
196
+ workflows.push("SDKGEN: define .sdkgen schema → `pnpm run sdkgen` → implement controllers");
197
+ }
198
+ if (depNames.includes("@graphql-codegen/cli") || allFiles.some((f) => f.includes("codegen"))) {
199
+ workflows.push("GraphQL Codegen: .graphql schema → generated types/resolvers");
200
+ }
201
+ if (allFiles.some((f) => f.endsWith("schema.prisma"))) {
202
+ workflows.push("Prisma: edit schema.prisma → `prisma generate` → `prisma migrate dev`");
203
+ }
204
+ if (depNames.includes("drizzle-kit")) {
205
+ workflows.push("Drizzle: edit schema → `drizzle-kit generate` → `drizzle-kit migrate`");
206
+ }
207
+ if (allFiles.some((f) => f.includes("knexfile"))) {
208
+ workflows.push("Knex migrations: `knex migrate:make <name>` → edit → `knex migrate:latest`");
209
+ }
210
+ if (allFiles.some((f) => f.match(/openapi|swagger/i) && f.match(/\.(json|yaml|yml)$/))) {
211
+ workflows.push("OpenAPI/Swagger spec → generated client/types");
212
+ }
213
+ if (depNames.includes("turbo"))
214
+ workflows.push("Turborepo: `turbo run <task>` across packages");
215
+ if (depNames.includes("lerna"))
216
+ workflows.push("Lerna: `lerna run <task>` across packages");
217
+ if (allFiles.includes("nx.json"))
218
+ workflows.push("Nx: `nx run <project>:<task>`");
219
+ if (allFiles.some((f) => f.includes(".github/workflows/")))
220
+ workflows.push("GitHub Actions CI/CD");
221
+ if (allFiles.some((f) => f.includes(".gitlab-ci")))
222
+ workflows.push("GitLab CI/CD");
223
+ if (allFiles.includes("Jenkinsfile"))
224
+ workflows.push("Jenkins CI/CD");
225
+ if (depNames.includes("husky"))
226
+ workflows.push("Husky: pre-commit hooks for linting/formatting");
227
+ if (depNames.includes("commitizen") || depNames.includes("git-cz"))
228
+ workflows.push("Commitizen: standardized commit messages (`git cz`)");
229
+ if (allFiles.includes("Dockerfile"))
230
+ workflows.push("Docker: containerized deployment");
231
+ if (allFiles.some((f) => f.match(/(docker-)?compose\.(yml|yaml)$/)))
232
+ workflows.push("Docker Compose: multi-service local dev");
233
+ if (depNames.includes("electron") || depNames.includes("electron-builder")) {
234
+ workflows.push("Electron: build → bundle → `electron-builder` dist");
235
+ }
236
+ return workflows;
237
+ }
238
+ // ─── Code Conventions ─────────────────────────────────────
239
+ export async function detectCodeConventions(rootPath, allFiles) {
240
+ const conventions = [];
241
+ const tsconfig = await readTextFile(join(rootPath, "tsconfig.json"));
242
+ if (tsconfig) {
243
+ if (tsconfig.includes('"strict": true') || tsconfig.includes('"strict":true')) {
244
+ conventions.push("TypeScript strict mode enabled");
245
+ }
246
+ if (tsconfig.includes('"noImplicitAny"')) {
247
+ conventions.push("No implicit any types");
248
+ }
249
+ }
250
+ const eslintFiles = allFiles.filter((f) => f.match(/eslint/i) && !f.includes("node_modules"));
251
+ if (eslintFiles.length > 0) {
252
+ const content = await readTextFile(join(rootPath, eslintFiles[0]));
253
+ if (content) {
254
+ if (content.includes("no-any") || content.includes("@typescript-eslint/no-explicit-any")) {
255
+ conventions.push("No `any` type allowed (ESLint enforced)");
256
+ }
257
+ if (content.includes("no-console")) {
258
+ conventions.push("No console.log (use logger instead)");
259
+ }
260
+ }
261
+ }
262
+ const cfg = getScanConfig();
263
+ const repoFiles = await readFilesMatching(rootPath, allFiles, {
264
+ extensions: [".ts", ".js"],
265
+ maxFiles: cfg.maxFiles,
266
+ maxFileSize: cfg.maxFileSize,
267
+ pathPatterns: [/repositor/i],
268
+ });
269
+ for (const { content } of repoFiles) {
270
+ if (content.includes("isDeleted") || content.includes("is_deleted") || content.includes("deletedAt")) {
271
+ conventions.push("Soft delete pattern (filter `isDeleted`/`deletedAt`)");
272
+ break;
273
+ }
274
+ }
275
+ for (const { content } of repoFiles) {
276
+ if (content.match(/class\s+\w+\s+extends\s+Base(Repository|Repo)/)) {
277
+ conventions.push("BaseRepository pattern for data access");
278
+ break;
279
+ }
280
+ }
281
+ return conventions;
282
+ }
283
+ //# sourceMappingURL=patterns-code.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patterns-code.js","sourceRoot":"","sources":["../../src/scanner/patterns-code.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"patterns.d.ts","sourceRoot":"","sources":["../../src/scanner/patterns.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAIlE,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,iBAAiB,CAAC;IAC1B,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,aAAa,EAAE,YAAY,EAAE,CAAC;IAC9B,YAAY,EAAE,eAAe,GAAG,IAAI,CAAC;IACrC,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,YAAY,EAAE,WAAW,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,eAAe,EAAE,MAAM,CAAC;IACxB,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAAE,EAClB,IAAI,EAAE,eAAe,EAAE,EACvB,UAAU,EAAE,aAAa,EAAE,GAC1B,OAAO,CAAC,YAAY,CAAC,CAoBvB"}
1
+ {"version":3,"file":"patterns.d.ts","sourceRoot":"","sources":["../../src/scanner/patterns.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAQlE,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,iBAAiB,CAAC;IAC1B,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,aAAa,EAAE,YAAY,EAAE,CAAC;IAC9B,YAAY,EAAE,eAAe,GAAG,IAAI,CAAC;IACrC,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,YAAY,EAAE,WAAW,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,eAAe,EAAE,MAAM,CAAC;IACxB,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAAE,EAClB,IAAI,EAAE,eAAe,EAAE,EACvB,UAAU,EAAE,aAAa,EAAE,GAC1B,OAAO,CAAC,YAAY,CAAC,CAoBvB"}
@@ -1,6 +1,8 @@
1
+ // ─── Code Patterns Scanner — Orchestrator + Import/Naming/IDE
1
2
  import { join } from "node:path";
2
3
  import { readTextFile, readFilesMatching } from "../utils/files.js";
3
4
  import { getScanConfig } from "./config.js";
5
+ import { detectErrorHandling, detectTestPatterns, detectArchitecturalRules, extractCodeExamples, detectWorkflows, detectCodeConventions, } from "./patterns-code.js";
4
6
  export async function scanCodePatterns(rootPath, allFiles, deps, frameworks) {
5
7
  const [di, imports, naming, workflows, codeConventions, ideSkills, ideCommands, errorHandling, testPatterns, architecturalRules, codeExamples] = await Promise.all([
6
8
  detectDI(rootPath, allFiles, deps),
@@ -120,7 +122,6 @@ async function detectNaming(rootPath, allFiles) {
120
122
  fileNaming = "PascalCase (MyComponent.ts)";
121
123
  else if (camelCount === maxCount && camelCount > kebabCount + pascalCount)
122
124
  fileNaming = "camelCase (myComponent.ts)";
123
- // DB column naming — read actual schema/migrations
124
125
  let dbColumns = "unknown";
125
126
  const prismaFile = allFiles.find((f) => f.endsWith("schema.prisma"));
126
127
  if (prismaFile) {
@@ -158,293 +159,6 @@ async function detectNaming(rootPath, allFiles) {
158
159
  }
159
160
  return { files: fileNaming, variables: "camelCase", dbColumns };
160
161
  }
161
- // ─── Error Handling ───────────────────────────────────────
162
- async function detectErrorHandling(rootPath, allFiles) {
163
- const patterns = [];
164
- const cfg = getScanConfig();
165
- const sourceFiles = await readFilesMatching(rootPath, allFiles, {
166
- extensions: [".ts", ".js"],
167
- maxFiles: cfg.maxFiles,
168
- maxFileSize: cfg.maxFileSize,
169
- });
170
- for (const { file, content } of sourceFiles) {
171
- const regex = /class\s+(\w+)\s+extends\s+(Error|BaseError|DomainError|AppError|HttpException|CustomError|BusinessError|NotFound|BadRequest|Unauthorized|Forbidden)\b/g;
172
- let match;
173
- while ((match = regex.exec(content)) !== null) {
174
- patterns.push({ className: match[1], extendsFrom: match[2], file });
175
- }
176
- if (patterns.length >= 30)
177
- break;
178
- }
179
- // Dedupe by className
180
- const seen = new Set();
181
- return patterns.filter((p) => {
182
- if (seen.has(p.className))
183
- return false;
184
- seen.add(p.className);
185
- return true;
186
- });
187
- }
188
- // ─── Test Patterns ────────────────────────────────────────
189
- async function detectTestPatterns(rootPath, allFiles, deps, frameworks) {
190
- const depNames = deps.map((d) => d.name);
191
- const fwNames = frameworks.map((f) => f.name);
192
- let framework = "";
193
- if (depNames.includes("vitest") || fwNames.includes("Vitest"))
194
- framework = "Vitest";
195
- else if (depNames.includes("jest") || depNames.includes("ts-jest") || fwNames.includes("Jest"))
196
- framework = "Jest";
197
- else if (depNames.includes("mocha"))
198
- framework = "Mocha";
199
- if (!framework)
200
- return null;
201
- // Coverage threshold
202
- let coverageThreshold = null;
203
- const configFiles = allFiles.filter((f) => f.match(/(jest|vitest)\..*config\.(ts|js|mjs|cjs|json)$/));
204
- for (const cf of configFiles.slice(0, 3)) {
205
- const content = await readTextFile(join(rootPath, cf));
206
- if (!content)
207
- continue;
208
- const thresholdMatch = content.match(/(?:branches|lines|functions|statements)\s*:\s*(\d+)/);
209
- if (thresholdMatch) {
210
- coverageThreshold = parseInt(thresholdMatch[1], 10);
211
- break;
212
- }
213
- }
214
- // File patterns
215
- const testFiles = allFiles.filter((f) => f.match(/\.(test|spec)\.(ts|tsx|js|jsx)$/));
216
- const specCount = testFiles.filter((f) => f.includes(".spec.")).length;
217
- const testCount = testFiles.filter((f) => f.includes(".test.")).length;
218
- const unitFilePattern = specCount > testCount ? "*.spec.ts" : "*.test.ts";
219
- let integrationFilePattern = null;
220
- if (allFiles.some((f) => f.includes("__tests__/")))
221
- integrationFilePattern = "__tests__/**/*.test.ts";
222
- else if (allFiles.some((f) => f.includes("e2e/")))
223
- integrationFilePattern = "e2e/**/*.test.ts";
224
- let testDir = "src/";
225
- if (allFiles.some((f) => f.includes("__tests__/")))
226
- testDir = "__tests__/";
227
- else if (allFiles.some((f) => f.match(/^tests?\//)))
228
- testDir = "tests/";
229
- // Assertion style
230
- let assertionStyle = null;
231
- if (testFiles.length > 0) {
232
- const content = await readTextFile(join(rootPath, testFiles[0]));
233
- if (content) {
234
- if (content.includes("expect("))
235
- assertionStyle = "expect() (Jest/Vitest)";
236
- else if (content.includes("assert."))
237
- assertionStyle = "assert (Node.js/Chai)";
238
- }
239
- }
240
- return { framework, coverageThreshold, unitFilePattern, integrationFilePattern, testDir, assertionStyle };
241
- }
242
- // ─── Architectural Rules ──────────────────────────────────
243
- async function detectArchitecturalRules(rootPath, allFiles) {
244
- const rules = [];
245
- // 1. dependency-cruiser config
246
- const dcFile = allFiles.find((f) => f.match(/\.dependency-cruiser\.(cjs|js|json)$/));
247
- if (dcFile) {
248
- const content = await readTextFile(join(rootPath, dcFile));
249
- if (content) {
250
- const nameRegex = /name\s*:\s*['"`]([^'"`]+)['"`]/g;
251
- let match;
252
- while ((match = nameRegex.exec(content)) !== null) {
253
- rules.push(`Dependency rule: ${match[1]}`);
254
- if (rules.length >= 10)
255
- break;
256
- }
257
- }
258
- }
259
- // 2. ESLint boundary rules
260
- const eslintFiles = allFiles.filter((f) => f.match(/eslint/i) && !f.includes("node_modules"));
261
- for (const ef of eslintFiles.slice(0, 2)) {
262
- const content = await readTextFile(join(rootPath, ef));
263
- if (!content)
264
- continue;
265
- if (content.includes("import/no-restricted-paths") || content.includes("boundaries/element-types")) {
266
- rules.push("ESLint enforced import boundaries between layers");
267
- }
268
- }
269
- // 3. Infer from structure — check if domain doesn't import from infra
270
- const hasDomain = allFiles.some((f) => f.match(/src\/(domain|core)\//));
271
- const hasInfra = allFiles.some((f) => f.match(/src\/(infra|infrastructure)\//));
272
- const hasApp = allFiles.some((f) => f.match(/src\/(application|use-?cases)\//));
273
- if (hasDomain && hasInfra) {
274
- const cfg = getScanConfig();
275
- const domainFiles = await readFilesMatching(rootPath, allFiles, {
276
- extensions: [".ts", ".js"],
277
- maxFiles: cfg.maxFiles,
278
- maxFileSize: cfg.maxFileSize,
279
- pathPatterns: [/src\/(domain|core)\//],
280
- });
281
- let domainImportsInfra = false;
282
- for (const { content } of domainFiles) {
283
- if (content.match(/from\s+['"].*\/(infra|infrastructure)\//)) {
284
- domainImportsInfra = true;
285
- break;
286
- }
287
- }
288
- if (!domainImportsInfra) {
289
- rules.push("Domain/Core layer does NOT import from Infrastructure (Clean Architecture)");
290
- }
291
- if (hasApp) {
292
- rules.push("Layers: Domain → Application → Infrastructure");
293
- }
294
- }
295
- return rules;
296
- }
297
- // ─── Code Examples ────────────────────────────────────────
298
- async function extractCodeExamples(rootPath, allFiles, deps) {
299
- const examples = [];
300
- const depNames = deps.map((d) => d.name);
301
- const categories = [
302
- { category: "service", patterns: [/services?\//i], label: "Service pattern" },
303
- { category: "controller", patterns: [/controllers?\//i], label: "Controller pattern" },
304
- { category: "repository", patterns: [/repositor/i], label: "Repository pattern" },
305
- { category: "middleware", patterns: [/middleware/i], label: "Middleware pattern" },
306
- { category: "error-handling", patterns: [/(errors|exceptions)\//i], label: "Error handling" },
307
- ];
308
- for (const cat of categories) {
309
- const candidates = allFiles.filter((f) => f.match(/\.(ts|js)$/) &&
310
- cat.patterns.some((p) => p.test(f)) &&
311
- !f.includes(".test.") && !f.includes(".spec.") &&
312
- !f.includes("index.") && !f.includes("generated/"));
313
- if (candidates.length === 0)
314
- continue;
315
- const content = await readTextFile(join(rootPath, candidates[0]));
316
- if (!content)
317
- continue;
318
- const lines = content.split("\n").slice(0, 40);
319
- // Extract meaningful code: class definition or function
320
- const snippet = lines.join("\n");
321
- const classMatch = snippet.match(/((?:export\s+)?(?:abstract\s+)?class\s+\w+[^{]*\{[^}]*(?:\n[^}]*){0,8})/);
322
- const fnMatch = snippet.match(/((?:export\s+)?(?:async\s+)?function\s+\w+[^{]*\{[^}]*(?:\n[^}]*){0,5})/);
323
- const code = classMatch?.[1] || fnMatch?.[1] || lines.slice(0, 15).join("\n");
324
- if (code.trim().length > 30) {
325
- examples.push({
326
- file: candidates[0],
327
- label: cat.label,
328
- code: code.trim().slice(0, 500),
329
- category: cat.category,
330
- });
331
- }
332
- if (examples.length >= 6)
333
- break;
334
- }
335
- // DI example
336
- if (depNames.includes("@cubos/inject") || depNames.includes("tsyringe") || depNames.includes("inversify")) {
337
- const cfg = getScanConfig();
338
- const diFiles = await readFilesMatching(rootPath, allFiles, {
339
- extensions: [".ts"],
340
- maxFiles: cfg.maxFiles,
341
- maxFileSize: cfg.maxFileSize,
342
- pathPatterns: [/(services?|controllers?|use-?cases?)\//],
343
- });
344
- for (const { file, content } of diFiles) {
345
- const useMatch = content.match(/.*use\(\w+\).*/);
346
- const injectMatch = content.match(/.*@Inject.*|.*@injectable.*/i);
347
- const line = useMatch?.[0] || injectMatch?.[0];
348
- if (line) {
349
- examples.push({ file, label: "DI usage", code: line.trim(), category: "di" });
350
- break;
351
- }
352
- }
353
- }
354
- return examples;
355
- }
356
- // ─── Workflows ────────────────────────────────────────────
357
- async function detectWorkflows(rootPath, allFiles, deps, frameworks) {
358
- const workflows = [];
359
- const depNames = deps.map((d) => d.name);
360
- if (allFiles.some((f) => f.endsWith(".sdkgen"))) {
361
- workflows.push("SDKGEN: define .sdkgen schema → `pnpm run sdkgen` → implement controllers");
362
- }
363
- if (depNames.includes("@graphql-codegen/cli") || allFiles.some((f) => f.includes("codegen"))) {
364
- workflows.push("GraphQL Codegen: .graphql schema → generated types/resolvers");
365
- }
366
- if (allFiles.some((f) => f.endsWith("schema.prisma"))) {
367
- workflows.push("Prisma: edit schema.prisma → `prisma generate` → `prisma migrate dev`");
368
- }
369
- if (depNames.includes("drizzle-kit")) {
370
- workflows.push("Drizzle: edit schema → `drizzle-kit generate` → `drizzle-kit migrate`");
371
- }
372
- if (allFiles.some((f) => f.includes("knexfile"))) {
373
- workflows.push("Knex migrations: `knex migrate:make <name>` → edit → `knex migrate:latest`");
374
- }
375
- if (allFiles.some((f) => f.match(/openapi|swagger/i) && f.match(/\.(json|yaml|yml)$/))) {
376
- workflows.push("OpenAPI/Swagger spec → generated client/types");
377
- }
378
- if (depNames.includes("turbo"))
379
- workflows.push("Turborepo: `turbo run <task>` across packages");
380
- if (depNames.includes("lerna"))
381
- workflows.push("Lerna: `lerna run <task>` across packages");
382
- if (allFiles.includes("nx.json"))
383
- workflows.push("Nx: `nx run <project>:<task>`");
384
- if (allFiles.some((f) => f.includes(".github/workflows/")))
385
- workflows.push("GitHub Actions CI/CD");
386
- if (allFiles.some((f) => f.includes(".gitlab-ci")))
387
- workflows.push("GitLab CI/CD");
388
- if (allFiles.includes("Jenkinsfile"))
389
- workflows.push("Jenkins CI/CD");
390
- if (depNames.includes("husky"))
391
- workflows.push("Husky: pre-commit hooks for linting/formatting");
392
- if (depNames.includes("commitizen") || depNames.includes("git-cz"))
393
- workflows.push("Commitizen: standardized commit messages (`git cz`)");
394
- if (allFiles.includes("Dockerfile"))
395
- workflows.push("Docker: containerized deployment");
396
- if (allFiles.some((f) => f.match(/(docker-)?compose\.(yml|yaml)$/)))
397
- workflows.push("Docker Compose: multi-service local dev");
398
- if (depNames.includes("electron") || depNames.includes("electron-builder")) {
399
- workflows.push("Electron: build → bundle → `electron-builder` dist");
400
- }
401
- return workflows;
402
- }
403
- // ─── Code Conventions ─────────────────────────────────────
404
- async function detectCodeConventions(rootPath, allFiles) {
405
- const conventions = [];
406
- const tsconfig = await readTextFile(join(rootPath, "tsconfig.json"));
407
- if (tsconfig) {
408
- if (tsconfig.includes('"strict": true') || tsconfig.includes('"strict":true')) {
409
- conventions.push("TypeScript strict mode enabled");
410
- }
411
- if (tsconfig.includes('"noImplicitAny"')) {
412
- conventions.push("No implicit any types");
413
- }
414
- }
415
- const eslintFiles = allFiles.filter((f) => f.match(/eslint/i) && !f.includes("node_modules"));
416
- if (eslintFiles.length > 0) {
417
- const content = await readTextFile(join(rootPath, eslintFiles[0]));
418
- if (content) {
419
- if (content.includes("no-any") || content.includes("@typescript-eslint/no-explicit-any")) {
420
- conventions.push("No `any` type allowed (ESLint enforced)");
421
- }
422
- if (content.includes("no-console")) {
423
- conventions.push("No console.log (use logger instead)");
424
- }
425
- }
426
- }
427
- const cfg = getScanConfig();
428
- const repoFiles = await readFilesMatching(rootPath, allFiles, {
429
- extensions: [".ts", ".js"],
430
- maxFiles: cfg.maxFiles,
431
- maxFileSize: cfg.maxFileSize,
432
- pathPatterns: [/repositor/i],
433
- });
434
- for (const { content } of repoFiles) {
435
- if (content.includes("isDeleted") || content.includes("is_deleted") || content.includes("deletedAt")) {
436
- conventions.push("Soft delete pattern (filter `isDeleted`/`deletedAt`)");
437
- break;
438
- }
439
- }
440
- for (const { content } of repoFiles) {
441
- if (content.match(/class\s+\w+\s+extends\s+Base(Repository|Repo)/)) {
442
- conventions.push("BaseRepository pattern for data access");
443
- break;
444
- }
445
- }
446
- return conventions;
447
- }
448
162
  // ─── IDE Skills ───────────────────────────────────────────
449
163
  async function scanIDESkills(rootPath, allFiles) {
450
164
  const skills = [];