projscan 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +193 -0
  3. package/dist/analyzers/architectureCheck.d.ts +2 -0
  4. package/dist/analyzers/architectureCheck.js +91 -0
  5. package/dist/analyzers/architectureCheck.js.map +1 -0
  6. package/dist/analyzers/dependencyRiskCheck.d.ts +2 -0
  7. package/dist/analyzers/dependencyRiskCheck.js +17 -0
  8. package/dist/analyzers/dependencyRiskCheck.js.map +1 -0
  9. package/dist/analyzers/eslintCheck.d.ts +2 -0
  10. package/dist/analyzers/eslintCheck.js +49 -0
  11. package/dist/analyzers/eslintCheck.js.map +1 -0
  12. package/dist/analyzers/prettierCheck.d.ts +2 -0
  13. package/dist/analyzers/prettierCheck.js +53 -0
  14. package/dist/analyzers/prettierCheck.js.map +1 -0
  15. package/dist/analyzers/testCheck.d.ts +2 -0
  16. package/dist/analyzers/testCheck.js +52 -0
  17. package/dist/analyzers/testCheck.js.map +1 -0
  18. package/dist/cli/index.d.ts +2 -0
  19. package/dist/cli/index.js +558 -0
  20. package/dist/cli/index.js.map +1 -0
  21. package/dist/core/dependencyAnalyzer.d.ts +2 -0
  22. package/dist/core/dependencyAnalyzer.js +96 -0
  23. package/dist/core/dependencyAnalyzer.js.map +1 -0
  24. package/dist/core/frameworkDetector.d.ts +2 -0
  25. package/dist/core/frameworkDetector.js +152 -0
  26. package/dist/core/frameworkDetector.js.map +1 -0
  27. package/dist/core/issueEngine.d.ts +2 -0
  28. package/dist/core/issueEngine.js +21 -0
  29. package/dist/core/issueEngine.js.map +1 -0
  30. package/dist/core/languageDetector.d.ts +2 -0
  31. package/dist/core/languageDetector.js +107 -0
  32. package/dist/core/languageDetector.js.map +1 -0
  33. package/dist/core/repositoryScanner.d.ts +2 -0
  34. package/dist/core/repositoryScanner.js +79 -0
  35. package/dist/core/repositoryScanner.js.map +1 -0
  36. package/dist/fixes/editorconfigFix.d.ts +2 -0
  37. package/dist/fixes/editorconfigFix.js +28 -0
  38. package/dist/fixes/editorconfigFix.js.map +1 -0
  39. package/dist/fixes/eslintFix.d.ts +2 -0
  40. package/dist/fixes/eslintFix.js +46 -0
  41. package/dist/fixes/eslintFix.js.map +1 -0
  42. package/dist/fixes/fixRegistry.d.ts +3 -0
  43. package/dist/fixes/fixRegistry.js +24 -0
  44. package/dist/fixes/fixRegistry.js.map +1 -0
  45. package/dist/fixes/prettierFix.d.ts +2 -0
  46. package/dist/fixes/prettierFix.js +39 -0
  47. package/dist/fixes/prettierFix.js.map +1 -0
  48. package/dist/fixes/testFix.d.ts +2 -0
  49. package/dist/fixes/testFix.js +61 -0
  50. package/dist/fixes/testFix.js.map +1 -0
  51. package/dist/index.d.ts +7 -0
  52. package/dist/index.js +7 -0
  53. package/dist/index.js.map +1 -0
  54. package/dist/reporters/consoleReporter.d.ts +9 -0
  55. package/dist/reporters/consoleReporter.js +240 -0
  56. package/dist/reporters/consoleReporter.js.map +1 -0
  57. package/dist/reporters/jsonReporter.d.ts +7 -0
  58. package/dist/reporters/jsonReporter.js +27 -0
  59. package/dist/reporters/jsonReporter.js.map +1 -0
  60. package/dist/reporters/markdownReporter.d.ts +7 -0
  61. package/dist/reporters/markdownReporter.js +129 -0
  62. package/dist/reporters/markdownReporter.js.map +1 -0
  63. package/dist/types.d.ts +110 -0
  64. package/dist/types.js +3 -0
  65. package/dist/types.js.map +1 -0
  66. package/dist/utils/cache.d.ts +3 -0
  67. package/dist/utils/cache.js +51 -0
  68. package/dist/utils/cache.js.map +1 -0
  69. package/dist/utils/fileWalker.d.ts +7 -0
  70. package/dist/utils/fileWalker.js +45 -0
  71. package/dist/utils/fileWalker.js.map +1 -0
  72. package/dist/utils/logger.d.ts +9 -0
  73. package/dist/utils/logger.js +41 -0
  74. package/dist/utils/logger.js.map +1 -0
  75. package/package.json +48 -0
@@ -0,0 +1,96 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ const DEPRECATED_PACKAGES = {
4
+ moment: 'Consider using date-fns or dayjs instead',
5
+ request: 'Deprecated — use node-fetch, undici, or axios instead',
6
+ 'node-uuid': 'Renamed to uuid',
7
+ nomnom: 'Deprecated — use commander or yargs instead',
8
+ 'coffee-script': 'CoffeeScript is no longer maintained',
9
+ };
10
+ const HEAVY_PACKAGES = {
11
+ lodash: 'Consider lodash-es or individual imports (e.g., lodash/get) to reduce bundle size',
12
+ underscore: 'Many utilities are now available as native JS methods',
13
+ jquery: 'Consider using native DOM APIs if possible',
14
+ };
15
+ export async function analyzeDependencies(rootPath) {
16
+ const pkgPath = path.join(rootPath, 'package.json');
17
+ let raw;
18
+ try {
19
+ raw = await fs.readFile(pkgPath, 'utf-8');
20
+ }
21
+ catch {
22
+ return null;
23
+ }
24
+ const pkg = JSON.parse(raw);
25
+ const dependencies = pkg.dependencies ?? {};
26
+ const devDependencies = pkg.devDependencies ?? {};
27
+ const risks = [];
28
+ // Check for deprecated packages
29
+ for (const [name, reason] of Object.entries(DEPRECATED_PACKAGES)) {
30
+ if (dependencies[name] || devDependencies[name]) {
31
+ risks.push({ name, reason, severity: 'high' });
32
+ }
33
+ }
34
+ // Check for heavy packages
35
+ for (const [name, reason] of Object.entries(HEAVY_PACKAGES)) {
36
+ if (dependencies[name]) {
37
+ risks.push({ name, reason, severity: 'medium' });
38
+ }
39
+ }
40
+ // Check for excessive dependencies
41
+ const totalDeps = Object.keys(dependencies).length;
42
+ if (totalDeps > 100) {
43
+ risks.push({
44
+ name: 'excessive-dependencies',
45
+ reason: `${totalDeps} production dependencies — consider auditing for unused packages`,
46
+ severity: 'high',
47
+ });
48
+ }
49
+ else if (totalDeps > 50) {
50
+ risks.push({
51
+ name: 'many-dependencies',
52
+ reason: `${totalDeps} production dependencies — review for opportunities to reduce`,
53
+ severity: 'medium',
54
+ });
55
+ }
56
+ // Check for wildcard version ranges
57
+ for (const [name, version] of Object.entries(dependencies)) {
58
+ if (version === '*' || version.startsWith('>=')) {
59
+ risks.push({
60
+ name,
61
+ reason: `Wildcard version range "${version}" — pin to a specific version for reproducible builds`,
62
+ severity: 'high',
63
+ });
64
+ }
65
+ }
66
+ // Check for missing lockfile
67
+ const hasLockfile = await checkLockfile(rootPath);
68
+ if (!hasLockfile && totalDeps > 0) {
69
+ risks.push({
70
+ name: 'no-lockfile',
71
+ reason: 'No lockfile found — run npm install to generate package-lock.json',
72
+ severity: 'medium',
73
+ });
74
+ }
75
+ return {
76
+ totalDependencies: totalDeps,
77
+ totalDevDependencies: Object.keys(devDependencies).length,
78
+ dependencies,
79
+ devDependencies,
80
+ risks,
81
+ };
82
+ }
83
+ async function checkLockfile(rootPath) {
84
+ const lockfiles = ['package-lock.json', 'yarn.lock', 'pnpm-lock.yaml'];
85
+ for (const lockfile of lockfiles) {
86
+ try {
87
+ await fs.access(path.join(rootPath, lockfile));
88
+ return true;
89
+ }
90
+ catch {
91
+ // continue
92
+ }
93
+ }
94
+ return false;
95
+ }
96
+ //# sourceMappingURL=dependencyAnalyzer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dependencyAnalyzer.js","sourceRoot":"","sources":["../../src/core/dependencyAnalyzer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { FileEntry, FrameworkResult } from '../types.js';
2
+ export declare function detectFrameworks(rootPath: string, files: FileEntry[]): Promise<FrameworkResult>;
@@ -0,0 +1,152 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ // Maps dependency name → framework info
4
+ const DEPENDENCY_FRAMEWORKS = {
5
+ react: { name: 'React', category: 'frontend' },
6
+ 'react-dom': { name: 'React', category: 'frontend' },
7
+ next: { name: 'Next.js', category: 'frontend' },
8
+ vue: { name: 'Vue.js', category: 'frontend' },
9
+ nuxt: { name: 'Nuxt.js', category: 'frontend' },
10
+ svelte: { name: 'Svelte', category: 'frontend' },
11
+ '@sveltejs/kit': { name: 'SvelteKit', category: 'frontend' },
12
+ angular: { name: 'Angular', category: 'frontend' },
13
+ '@angular/core': { name: 'Angular', category: 'frontend' },
14
+ solid: { name: 'Solid.js', category: 'frontend' },
15
+ 'solid-js': { name: 'Solid.js', category: 'frontend' },
16
+ express: { name: 'Express', category: 'backend' },
17
+ fastify: { name: 'Fastify', category: 'backend' },
18
+ '@nestjs/core': { name: 'NestJS', category: 'backend' },
19
+ hono: { name: 'Hono', category: 'backend' },
20
+ koa: { name: 'Koa', category: 'backend' },
21
+ 'socket.io': { name: 'Socket.IO', category: 'backend' },
22
+ vitest: { name: 'Vitest', category: 'testing' },
23
+ jest: { name: 'Jest', category: 'testing' },
24
+ mocha: { name: 'Mocha', category: 'testing' },
25
+ cypress: { name: 'Cypress', category: 'testing' },
26
+ playwright: { name: 'Playwright', category: 'testing' },
27
+ '@playwright/test': { name: 'Playwright', category: 'testing' },
28
+ vite: { name: 'Vite', category: 'bundler' },
29
+ webpack: { name: 'Webpack', category: 'bundler' },
30
+ rollup: { name: 'Rollup', category: 'bundler' },
31
+ esbuild: { name: 'esbuild', category: 'bundler' },
32
+ turbo: { name: 'Turborepo', category: 'bundler' },
33
+ tailwindcss: { name: 'Tailwind CSS', category: 'css' },
34
+ 'styled-components': { name: 'styled-components', category: 'css' },
35
+ '@emotion/react': { name: 'Emotion', category: 'css' },
36
+ prisma: { name: 'Prisma', category: 'other' },
37
+ '@prisma/client': { name: 'Prisma', category: 'other' },
38
+ drizzle: { name: 'Drizzle ORM', category: 'other' },
39
+ 'drizzle-orm': { name: 'Drizzle ORM', category: 'other' },
40
+ mongoose: { name: 'Mongoose', category: 'other' },
41
+ typeorm: { name: 'TypeORM', category: 'other' },
42
+ sequelize: { name: 'Sequelize', category: 'other' },
43
+ graphql: { name: 'GraphQL', category: 'other' },
44
+ 'apollo-server': { name: 'Apollo Server', category: 'backend' },
45
+ '@apollo/server': { name: 'Apollo Server', category: 'backend' },
46
+ trpc: { name: 'tRPC', category: 'backend' },
47
+ '@trpc/server': { name: 'tRPC', category: 'backend' },
48
+ };
49
+ const BUILD_TOOL_INDICATORS = {
50
+ 'tsconfig.json': 'TypeScript',
51
+ 'webpack.config.js': 'Webpack',
52
+ 'webpack.config.ts': 'Webpack',
53
+ 'rollup.config.js': 'Rollup',
54
+ 'rollup.config.ts': 'Rollup',
55
+ 'vite.config.js': 'Vite',
56
+ 'vite.config.ts': 'Vite',
57
+ 'turbo.json': 'Turborepo',
58
+ 'Makefile': 'Make',
59
+ 'Dockerfile': 'Docker',
60
+ 'docker-compose.yml': 'Docker Compose',
61
+ 'docker-compose.yaml': 'Docker Compose',
62
+ };
63
+ export async function detectFrameworks(rootPath, files) {
64
+ const pkg = await readPackageJson(rootPath);
65
+ const fileNames = new Set(files.map((f) => f.relativePath));
66
+ const rootFiles = new Set(files.filter((f) => !f.directory || f.directory === '.').map((f) => path.basename(f.relativePath)));
67
+ const frameworks = new Map();
68
+ // Detect from package.json dependencies
69
+ if (pkg) {
70
+ const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
71
+ for (const [dep, info] of Object.entries(DEPENDENCY_FRAMEWORKS)) {
72
+ if (allDeps[dep]) {
73
+ if (!frameworks.has(info.name)) {
74
+ frameworks.set(info.name, {
75
+ name: info.name,
76
+ version: allDeps[dep],
77
+ category: info.category,
78
+ confidence: 'high',
79
+ });
80
+ }
81
+ }
82
+ }
83
+ }
84
+ // Detect from config files
85
+ for (const file of rootFiles) {
86
+ // Next.js config
87
+ if (file.startsWith('next.config')) {
88
+ if (!frameworks.has('Next.js')) {
89
+ frameworks.set('Next.js', {
90
+ name: 'Next.js',
91
+ category: 'frontend',
92
+ confidence: 'high',
93
+ });
94
+ }
95
+ }
96
+ // Tailwind config
97
+ if (file.startsWith('tailwind.config')) {
98
+ if (!frameworks.has('Tailwind CSS')) {
99
+ frameworks.set('Tailwind CSS', {
100
+ name: 'Tailwind CSS',
101
+ category: 'css',
102
+ confidence: 'high',
103
+ });
104
+ }
105
+ }
106
+ }
107
+ // Detect from special directories
108
+ if (fileNames.has('prisma/schema.prisma')) {
109
+ if (!frameworks.has('Prisma')) {
110
+ frameworks.set('Prisma', {
111
+ name: 'Prisma',
112
+ category: 'other',
113
+ confidence: 'high',
114
+ });
115
+ }
116
+ }
117
+ // Detect build tools
118
+ const buildTools = [];
119
+ for (const [file, tool] of Object.entries(BUILD_TOOL_INDICATORS)) {
120
+ if (rootFiles.has(file) || fileNames.has(file)) {
121
+ if (!buildTools.includes(tool)) {
122
+ buildTools.push(tool);
123
+ }
124
+ }
125
+ }
126
+ // Detect package manager
127
+ const packageManager = detectPackageManager(rootFiles);
128
+ return {
129
+ frameworks: [...frameworks.values()],
130
+ buildTools,
131
+ packageManager,
132
+ };
133
+ }
134
+ function detectPackageManager(rootFiles) {
135
+ if (rootFiles.has('pnpm-lock.yaml'))
136
+ return 'pnpm';
137
+ if (rootFiles.has('yarn.lock'))
138
+ return 'yarn';
139
+ if (rootFiles.has('package-lock.json'))
140
+ return 'npm';
141
+ return 'unknown';
142
+ }
143
+ async function readPackageJson(rootPath) {
144
+ try {
145
+ const raw = await fs.readFile(path.join(rootPath, 'package.json'), 'utf-8');
146
+ return JSON.parse(raw);
147
+ }
148
+ catch {
149
+ return null;
150
+ }
151
+ }
152
+ //# sourceMappingURL=frameworkDetector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frameworkDetector.js","sourceRoot":"","sources":["../../src/core/frameworkDetector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAS7B,wCAAwC;AACxC,MAAM,qBAAqB,GAGvB;IACF,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE;IAC9C,WAAW,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE;IACpD,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE;IAC/C,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE;IAC7C,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE;IAC/C,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE;IAChD,eAAe,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE;IAC5D,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE;IAClD,eAAe,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE;IAC1D,KAAK,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,EAAE;IACjD,UAAU,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,EAAE;IACtD,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE;IACjD,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE;IACjD,cAAc,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE;IACvD,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE;IAC3C,GAAG,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE;IACzC,WAAW,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAE;IACvD,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE;IAC/C,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE;IAC3C,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE;IAC7C,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE;IACjD,UAAU,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE;IACvD,kBAAkB,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE;IAC/D,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE;IAC3C,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE;IACjD,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE;IAC/C,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE;IACjD,KAAK,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAE;IACjD,WAAW,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,QAAQ,EAAE,KAAK,EAAE;IACtD,mBAAmB,EAAE,EAAE,IAAI,EAAE,mBAAmB,EAAE,QAAQ,EAAE,KAAK,EAAE;IACnE,gBAAgB,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE;IACtD,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE;IAC7C,gBAAgB,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE;IACvD,OAAO,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE,QAAQ,EAAE,OAAO,EAAE;IACnD,aAAa,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE,QAAQ,EAAE,OAAO,EAAE;IACzD,QAAQ,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO,EAAE;IACjD,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE;IAC/C,SAAS,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,OAAO,EAAE;IACnD,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE;IAC/C,eAAe,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,QAAQ,EAAE,SAAS,EAAE;IAC/D,gBAAgB,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,QAAQ,EAAE,SAAS,EAAE;IAChE,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE;IAC3C,cAAc,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE;CACtD,CAAC;AAEF,MAAM,qBAAqB,GAA2B;IACpD,eAAe,EAAE,YAAY;IAC7B,mBAAmB,EAAE,SAAS;IAC9B,mBAAmB,EAAE,SAAS;IAC9B,kBAAkB,EAAE,QAAQ;IAC5B,kBAAkB,EAAE,QAAQ;IAC5B,gBAAgB,EAAE,MAAM;IACxB,gBAAgB,EAAE,MAAM;IACxB,YAAY,EAAE,WAAW;IACzB,UAAU,EAAE,MAAM;IAClB,YAAY,EAAE,QAAQ;IACtB,oBAAoB,EAAE,gBAAgB;IACtC,qBAAqB,EAAE,gBAAgB;CACxC,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,QAAgB,EAChB,KAAkB;IAElB,MAAM,GAAG,GAAG,MAAM,eAAe,CAAC,QAAQ,CAAC,CAAC;IAC5C,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC;IAC5D,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,SAAS,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAE9H,MAAM,UAAU,GAAG,IAAI,GAAG,EAA6B,CAAC;IAExD,wCAAwC;IACxC,IAAI,GAAG,EAAE,CAAC;QACR,MAAM,OAAO,GAAG,EAAE,GAAG,GAAG,CAAC,YAAY,EAAE,GAAG,GAAG,CAAC,eAAe,EAAE,CAAC;QAChE,KAAK,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,qBAAqB,CAAC,EAAE,CAAC;YAChE,IAAI,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;gBACjB,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;oBAC/B,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE;wBACxB,IAAI,EAAE,IAAI,CAAC,IAAI;wBACf,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC;wBACrB,QAAQ,EAAE,IAAI,CAAC,QAAQ;wBACvB,UAAU,EAAE,MAAM;qBACnB,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,2BAA2B;IAC3B,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;QAC7B,iBAAiB;QACjB,IAAI,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;YACnC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC/B,UAAU,CAAC,GAAG,CAAC,SAAS,EAAE;oBACxB,IAAI,EAAE,SAAS;oBACf,QAAQ,EAAE,UAAU;oBACpB,UAAU,EAAE,MAAM;iBACnB,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QACD,kBAAkB;QAClB,IAAI,IAAI,CAAC,UAAU,CAAC,iBAAiB,CAAC,EAAE,CAAC;YACvC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,CAAC;gBACpC,UAAU,CAAC,GAAG,CAAC,cAAc,EAAE;oBAC7B,IAAI,EAAE,cAAc;oBACpB,QAAQ,EAAE,KAAK;oBACf,UAAU,EAAE,MAAM;iBACnB,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED,kCAAkC;IAClC,IAAI,SAAS,CAAC,GAAG,CAAC,sBAAsB,CAAC,EAAE,CAAC;QAC1C,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC9B,UAAU,CAAC,GAAG,CAAC,QAAQ,EAAE;gBACvB,IAAI,EAAE,QAAQ;gBACd,QAAQ,EAAE,OAAO;gBACjB,UAAU,EAAE,MAAM;aACnB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,qBAAqB;IACrB,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,qBAAqB,CAAC,EAAE,CAAC;QACjE,IAAI,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAC/C,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC/B,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACxB,CAAC;QACH,CAAC;IACH,CAAC;IAED,yBAAyB;IACzB,MAAM,cAAc,GAAG,oBAAoB,CAAC,SAAS,CAAC,CAAC;IAEvD,OAAO;QACL,UAAU,EAAE,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC;QACpC,UAAU;QACV,cAAc;KACf,CAAC;AACJ,CAAC;AAED,SAAS,oBAAoB,CAAC,SAAsB;IAClD,IAAI,SAAS,CAAC,GAAG,CAAC,gBAAgB,CAAC;QAAE,OAAO,MAAM,CAAC;IACnD,IAAI,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC;QAAE,OAAO,MAAM,CAAC;IAC9C,IAAI,SAAS,CAAC,GAAG,CAAC,mBAAmB,CAAC;QAAE,OAAO,KAAK,CAAC;IACrD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,KAAK,UAAU,eAAe,CAAC,QAAgB;IAC7C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,cAAc,CAAC,EAAE,OAAO,CAAC,CAAC;QAC5E,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAgB,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { FileEntry, Issue } from '../types.js';
2
+ export declare function collectIssues(rootPath: string, files: FileEntry[]): Promise<Issue[]>;
@@ -0,0 +1,21 @@
1
+ import { check as eslintCheck } from '../analyzers/eslintCheck.js';
2
+ import { check as prettierCheck } from '../analyzers/prettierCheck.js';
3
+ import { check as testCheck } from '../analyzers/testCheck.js';
4
+ import { check as architectureCheck } from '../analyzers/architectureCheck.js';
5
+ import { check as dependencyRiskCheck } from '../analyzers/dependencyRiskCheck.js';
6
+ const checkers = [
7
+ eslintCheck,
8
+ prettierCheck,
9
+ testCheck,
10
+ architectureCheck,
11
+ dependencyRiskCheck,
12
+ ];
13
+ export async function collectIssues(rootPath, files) {
14
+ const results = await Promise.all(checkers.map((check) => check(rootPath, files)));
15
+ const issues = results.flat();
16
+ // Sort by severity: error > warning > info
17
+ const severityOrder = { error: 0, warning: 1, info: 2 };
18
+ issues.sort((a, b) => (severityOrder[a.severity] ?? 3) - (severityOrder[b.severity] ?? 3));
19
+ return issues;
20
+ }
21
+ //# sourceMappingURL=issueEngine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"issueEngine.js","sourceRoot":"","sources":["../../src/core/issueEngine.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,IAAI,WAAW,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,KAAK,IAAI,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,KAAK,IAAI,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AAC/E,OAAO,EAAE,KAAK,IAAI,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;AAInF,MAAM,QAAQ,GAAc;IAC1B,WAAW;IACX,aAAa;IACb,SAAS;IACT,iBAAiB;IACjB,mBAAmB;CACpB,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,QAAgB,EAAE,KAAkB;IACtE,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IACnF,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IAE9B,2CAA2C;IAC3C,MAAM,aAAa,GAA2B,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;IAChF,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAE3F,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { FileEntry, LanguageBreakdown } from '../types.js';
2
+ export declare function detectLanguages(files: FileEntry[]): LanguageBreakdown;
@@ -0,0 +1,107 @@
1
+ const EXTENSION_MAP = {
2
+ '.ts': 'TypeScript',
3
+ '.tsx': 'TypeScript',
4
+ '.js': 'JavaScript',
5
+ '.jsx': 'JavaScript',
6
+ '.mjs': 'JavaScript',
7
+ '.cjs': 'JavaScript',
8
+ '.py': 'Python',
9
+ '.pyw': 'Python',
10
+ '.rb': 'Ruby',
11
+ '.go': 'Go',
12
+ '.rs': 'Rust',
13
+ '.java': 'Java',
14
+ '.kt': 'Kotlin',
15
+ '.kts': 'Kotlin',
16
+ '.swift': 'Swift',
17
+ '.cs': 'C#',
18
+ '.cpp': 'C++',
19
+ '.cc': 'C++',
20
+ '.cxx': 'C++',
21
+ '.c': 'C',
22
+ '.h': 'C',
23
+ '.hpp': 'C++',
24
+ '.php': 'PHP',
25
+ '.dart': 'Dart',
26
+ '.scala': 'Scala',
27
+ '.clj': 'Clojure',
28
+ '.ex': 'Elixir',
29
+ '.exs': 'Elixir',
30
+ '.erl': 'Erlang',
31
+ '.hs': 'Haskell',
32
+ '.lua': 'Lua',
33
+ '.r': 'R',
34
+ '.R': 'R',
35
+ '.pl': 'Perl',
36
+ '.pm': 'Perl',
37
+ '.sh': 'Shell',
38
+ '.bash': 'Shell',
39
+ '.zsh': 'Shell',
40
+ '.fish': 'Shell',
41
+ '.css': 'CSS',
42
+ '.scss': 'SCSS',
43
+ '.sass': 'SASS',
44
+ '.less': 'Less',
45
+ '.html': 'HTML',
46
+ '.htm': 'HTML',
47
+ '.vue': 'Vue',
48
+ '.svelte': 'Svelte',
49
+ '.sql': 'SQL',
50
+ '.graphql': 'GraphQL',
51
+ '.gql': 'GraphQL',
52
+ '.proto': 'Protocol Buffers',
53
+ '.json': 'JSON',
54
+ '.yaml': 'YAML',
55
+ '.yml': 'YAML',
56
+ '.toml': 'TOML',
57
+ '.xml': 'XML',
58
+ '.md': 'Markdown',
59
+ '.mdx': 'MDX',
60
+ '.txt': 'Text',
61
+ };
62
+ // Languages excluded from "primary" calculation (config/doc languages)
63
+ const EXCLUDED_FROM_PRIMARY = new Set([
64
+ 'JSON',
65
+ 'YAML',
66
+ 'TOML',
67
+ 'XML',
68
+ 'Markdown',
69
+ 'Text',
70
+ 'MDX',
71
+ ]);
72
+ export function detectLanguages(files) {
73
+ const langCounts = new Map();
74
+ let totalCounted = 0;
75
+ for (const file of files) {
76
+ const ext = file.extension;
77
+ const lang = EXTENSION_MAP[ext];
78
+ if (!lang)
79
+ continue;
80
+ totalCounted++;
81
+ const entry = langCounts.get(lang);
82
+ if (entry) {
83
+ entry.count++;
84
+ entry.extensions.add(ext);
85
+ }
86
+ else {
87
+ langCounts.set(lang, { count: 1, extensions: new Set([ext]) });
88
+ }
89
+ }
90
+ const languages = {};
91
+ let primaryLang = 'Unknown';
92
+ let primaryCount = 0;
93
+ for (const [lang, data] of langCounts) {
94
+ languages[lang] = {
95
+ name: lang,
96
+ fileCount: data.count,
97
+ percentage: totalCounted > 0 ? Math.round((data.count / totalCounted) * 1000) / 10 : 0,
98
+ extensions: [...data.extensions].sort(),
99
+ };
100
+ if (!EXCLUDED_FROM_PRIMARY.has(lang) && data.count > primaryCount) {
101
+ primaryCount = data.count;
102
+ primaryLang = lang;
103
+ }
104
+ }
105
+ return { primary: primaryLang, languages };
106
+ }
107
+ //# sourceMappingURL=languageDetector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"languageDetector.js","sourceRoot":"","sources":["../../src/core/languageDetector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { ScanResult } from '../types.js';
2
+ export declare function scanRepository(rootPath: string): Promise<ScanResult>;
@@ -0,0 +1,79 @@
1
+ import path from 'node:path';
2
+ import { walkFiles } from '../utils/fileWalker.js';
3
+ export async function scanRepository(rootPath) {
4
+ const start = performance.now();
5
+ const files = await walkFiles(rootPath);
6
+ const directoryTree = buildDirectoryTree(files, rootPath);
7
+ const directories = new Set(files.map((f) => f.directory));
8
+ const scanDurationMs = performance.now() - start;
9
+ return {
10
+ rootPath,
11
+ totalFiles: files.length,
12
+ totalDirectories: directories.size,
13
+ files,
14
+ directoryTree,
15
+ scanDurationMs,
16
+ };
17
+ }
18
+ function buildDirectoryTree(files, rootPath) {
19
+ const root = {
20
+ name: path.basename(rootPath),
21
+ path: '.',
22
+ children: [],
23
+ fileCount: 0,
24
+ totalFileCount: 0,
25
+ };
26
+ const nodeMap = new Map();
27
+ nodeMap.set('.', root);
28
+ for (const file of files) {
29
+ const dir = file.directory;
30
+ ensureNode(dir, nodeMap, root);
31
+ }
32
+ // Count files per directory
33
+ for (const file of files) {
34
+ const dir = file.directory === '' ? '.' : file.directory;
35
+ const node = nodeMap.get(dir);
36
+ if (node) {
37
+ node.fileCount++;
38
+ }
39
+ }
40
+ // Compute totalFileCount bottom-up
41
+ computeTotalFileCount(root);
42
+ // Sort children alphabetically
43
+ sortTree(root);
44
+ return root;
45
+ }
46
+ function ensureNode(dirPath, nodeMap, root) {
47
+ if (dirPath === '' || dirPath === '.')
48
+ return root;
49
+ const existing = nodeMap.get(dirPath);
50
+ if (existing)
51
+ return existing;
52
+ const parentPath = path.dirname(dirPath);
53
+ const parent = ensureNode(parentPath === '.' ? '.' : parentPath, nodeMap, root);
54
+ const node = {
55
+ name: path.basename(dirPath),
56
+ path: dirPath,
57
+ children: [],
58
+ fileCount: 0,
59
+ totalFileCount: 0,
60
+ };
61
+ parent.children.push(node);
62
+ nodeMap.set(dirPath, node);
63
+ return node;
64
+ }
65
+ function computeTotalFileCount(node) {
66
+ let total = node.fileCount;
67
+ for (const child of node.children) {
68
+ total += computeTotalFileCount(child);
69
+ }
70
+ node.totalFileCount = total;
71
+ return total;
72
+ }
73
+ function sortTree(node) {
74
+ node.children.sort((a, b) => a.name.localeCompare(b.name));
75
+ for (const child of node.children) {
76
+ sortTree(child);
77
+ }
78
+ }
79
+ //# sourceMappingURL=repositoryScanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repositoryScanner.js","sourceRoot":"","sources":["../../src/core/repositoryScanner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { Fix } from '../types.js';
2
+ export declare const editorconfigFix: Fix;
@@ -0,0 +1,28 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ export const editorconfigFix = {
4
+ id: 'add-editorconfig',
5
+ title: 'Add .editorconfig',
6
+ description: 'Creates a standard .editorconfig file for consistent editor settings',
7
+ issueId: 'missing-editorconfig',
8
+ async apply(rootPath) {
9
+ const content = `root = true
10
+
11
+ [*]
12
+ indent_style = space
13
+ indent_size = 2
14
+ end_of_line = lf
15
+ charset = utf-8
16
+ trim_trailing_whitespace = true
17
+ insert_final_newline = true
18
+
19
+ [*.md]
20
+ trim_trailing_whitespace = false
21
+
22
+ [Makefile]
23
+ indent_style = tab
24
+ `;
25
+ await fs.writeFile(path.join(rootPath, '.editorconfig'), content, 'utf-8');
26
+ },
27
+ };
28
+ //# sourceMappingURL=editorconfigFix.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"editorconfigFix.js","sourceRoot":"","sources":["../../src/fixes/editorconfigFix.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAG7B,MAAM,CAAC,MAAM,eAAe,GAAQ;IAClC,EAAE,EAAE,kBAAkB;IACtB,KAAK,EAAE,mBAAmB;IAC1B,WAAW,EAAE,sEAAsE;IACnF,OAAO,EAAE,sBAAsB;IAE/B,KAAK,CAAC,KAAK,CAAC,QAAgB;QAC1B,MAAM,OAAO,GAAG;;;;;;;;;;;;;;;CAenB,CAAC;QAEE,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,eAAe,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAC7E,CAAC;CACF,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { Fix } from '../types.js';
2
+ export declare const eslintFix: Fix;
@@ -0,0 +1,46 @@
1
+ import { execSync } from 'node:child_process';
2
+ import fs from 'node:fs/promises';
3
+ import path from 'node:path';
4
+ export const eslintFix = {
5
+ id: 'add-eslint',
6
+ title: 'Install and configure ESLint',
7
+ description: 'Installs ESLint and creates a configuration file',
8
+ issueId: 'missing-eslint',
9
+ async apply(rootPath) {
10
+ const hasTypeScript = await fileExists(path.join(rootPath, 'tsconfig.json'));
11
+ const packages = ['eslint'];
12
+ if (hasTypeScript) {
13
+ packages.push('@typescript-eslint/parser', '@typescript-eslint/eslint-plugin');
14
+ }
15
+ execSync(`npm install --save-dev ${packages.join(' ')}`, {
16
+ cwd: rootPath,
17
+ stdio: 'pipe',
18
+ });
19
+ const config = hasTypeScript
20
+ ? {
21
+ env: { node: true, es2022: true },
22
+ parser: '@typescript-eslint/parser',
23
+ plugins: ['@typescript-eslint'],
24
+ extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'],
25
+ parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
26
+ rules: {},
27
+ }
28
+ : {
29
+ env: { node: true, es2022: true },
30
+ extends: ['eslint:recommended'],
31
+ parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
32
+ rules: {},
33
+ };
34
+ await fs.writeFile(path.join(rootPath, '.eslintrc.json'), JSON.stringify(config, null, 2) + '\n', 'utf-8');
35
+ },
36
+ };
37
+ async function fileExists(filePath) {
38
+ try {
39
+ await fs.access(filePath);
40
+ return true;
41
+ }
42
+ catch {
43
+ return false;
44
+ }
45
+ }
46
+ //# sourceMappingURL=eslintFix.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eslintFix.js","sourceRoot":"","sources":["../../src/fixes/eslintFix.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAG7B,MAAM,CAAC,MAAM,SAAS,GAAQ;IAC5B,EAAE,EAAE,YAAY;IAChB,KAAK,EAAE,8BAA8B;IACrC,WAAW,EAAE,kDAAkD;IAC/D,OAAO,EAAE,gBAAgB;IAEzB,KAAK,CAAC,KAAK,CAAC,QAAgB;QAC1B,MAAM,aAAa,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC,CAAC;QAE7E,MAAM,QAAQ,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC5B,IAAI,aAAa,EAAE,CAAC;YAClB,QAAQ,CAAC,IAAI,CAAC,2BAA2B,EAAE,kCAAkC,CAAC,CAAC;QACjF,CAAC;QAED,QAAQ,CAAC,0BAA0B,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE;YACvD,GAAG,EAAE,QAAQ;YACb,KAAK,EAAE,MAAM;SACd,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,aAAa;YAC1B,CAAC,CAAC;gBACE,GAAG,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE;gBACjC,MAAM,EAAE,2BAA2B;gBACnC,OAAO,EAAE,CAAC,oBAAoB,CAAC;gBAC/B,OAAO,EAAE,CAAC,oBAAoB,EAAE,uCAAuC,CAAC;gBACxE,aAAa,EAAE,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE;gBAC9D,KAAK,EAAE,EAAE;aACV;YACH,CAAC,CAAC;gBACE,GAAG,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE;gBACjC,OAAO,EAAE,CAAC,oBAAoB,CAAC;gBAC/B,aAAa,EAAE,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE;gBAC9D,KAAK,EAAE,EAAE;aACV,CAAC;QAEN,MAAM,EAAE,CAAC,SAAS,CAChB,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,gBAAgB,CAAC,EACrC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EACtC,OAAO,CACR,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,KAAK,UAAU,UAAU,CAAC,QAAgB;IACxC,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC1B,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Fix, Issue } from '../types.js';
2
+ export declare function getFixForIssue(issue: Issue): Fix | null;
3
+ export declare function getAllAvailableFixes(issues: Issue[]): Fix[];
@@ -0,0 +1,24 @@
1
+ import { eslintFix } from './eslintFix.js';
2
+ import { prettierFix } from './prettierFix.js';
3
+ import { testFix } from './testFix.js';
4
+ import { editorconfigFix } from './editorconfigFix.js';
5
+ const fixes = [eslintFix, prettierFix, testFix, editorconfigFix];
6
+ const fixMap = new Map(fixes.map((f) => [f.id, f]));
7
+ export function getFixForIssue(issue) {
8
+ if (!issue.fixAvailable || !issue.fixId)
9
+ return null;
10
+ return fixMap.get(issue.fixId) ?? null;
11
+ }
12
+ export function getAllAvailableFixes(issues) {
13
+ const result = [];
14
+ const seen = new Set();
15
+ for (const issue of issues) {
16
+ const fix = getFixForIssue(issue);
17
+ if (fix && !seen.has(fix.id)) {
18
+ seen.add(fix.id);
19
+ result.push(fix);
20
+ }
21
+ }
22
+ return result;
23
+ }
24
+ //# sourceMappingURL=fixRegistry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fixRegistry.js","sourceRoot":"","sources":["../../src/fixes/fixRegistry.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEvD,MAAM,KAAK,GAAU,CAAC,SAAS,EAAE,WAAW,EAAE,OAAO,EAAE,eAAe,CAAC,CAAC;AAExE,MAAM,MAAM,GAAG,IAAI,GAAG,CAAc,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AAEjE,MAAM,UAAU,cAAc,CAAC,KAAY;IACzC,IAAI,CAAC,KAAK,CAAC,YAAY,IAAI,CAAC,KAAK,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACrD,OAAO,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,MAAe;IAClD,MAAM,MAAM,GAAU,EAAE,CAAC;IACzB,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAE/B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,GAAG,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;QAClC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;YAC7B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACjB,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACnB,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { Fix } from '../types.js';
2
+ export declare const prettierFix: Fix;