analyze-codebase 1.2.2 → 1.3.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.
@@ -1,15 +1,96 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
2
25
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
26
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
27
  };
5
28
  Object.defineProperty(exports, "__esModule", { value: true });
6
29
  exports.analyzeCodebase = void 0;
7
30
  const chalk_1 = __importDefault(require("chalk"));
31
+ const fast_glob_1 = __importDefault(require("fast-glob"));
32
+ const path = __importStar(require("path"));
8
33
  const file_1 = require("../analyze/file");
9
- const file_2 = require("../utils/file");
10
34
  const output_1 = require("../utils/output");
35
+ const progress_1 = require("../utils/progress");
36
+ const spinner_1 = require("../utils/spinner");
37
+ const cancellation_1 = require("../utils/cancellation");
38
+ const collectFiles = async (directory, extensions, exclude) => {
39
+ const patterns = [];
40
+ const ignorePatterns = [
41
+ "**/node_modules/**",
42
+ "**/dist/**",
43
+ "**/build/**",
44
+ "**/coverage/**",
45
+ "**/.git/**",
46
+ "**/.next/**",
47
+ "**/public/**",
48
+ "**/test/**",
49
+ "**/tests/**",
50
+ "**/mocks/**",
51
+ ];
52
+ if (exclude) {
53
+ ignorePatterns.push(...exclude.map((ex) => `**/${ex}/**`));
54
+ }
55
+ if (extensions && extensions.length > 0) {
56
+ patterns.push(...extensions.map((ext) => `**/*${ext}`), "**/*" // Also include files without extensions
57
+ );
58
+ }
59
+ else {
60
+ patterns.push("**/*");
61
+ }
62
+ const files = await (0, fast_glob_1.default)(patterns, {
63
+ cwd: directory,
64
+ ignore: ignorePatterns,
65
+ absolute: true,
66
+ onlyFiles: true,
67
+ dot: false,
68
+ });
69
+ // Filter by extension if specified
70
+ if (extensions && extensions.length > 0) {
71
+ return files.filter((file) => {
72
+ const ext = path.extname(file);
73
+ return extensions.includes(ext);
74
+ });
75
+ }
76
+ return files;
77
+ };
78
+ const processFile = (filePath, output, fileNameCases) => {
79
+ const { fileNameCase } = (0, file_1.analyzeFile)(filePath, output);
80
+ if (fileNameCases[fileNameCase] !== undefined)
81
+ fileNameCases[fileNameCase] += 1;
82
+ else
83
+ fileNameCases[fileNameCase] = 1;
84
+ };
11
85
  const analyzeCodebase = async (options) => {
12
86
  const start = Date.now();
87
+ const cancellationToken = new cancellation_1.CancellationToken();
88
+ const spinner = (0, spinner_1.createSpinner)("šŸ” Discovering files...");
89
+ // Cleanup on cancellation
90
+ cancellationToken.onCancel(() => {
91
+ spinner.stop();
92
+ console.log(chalk_1.default.yellow("\n\nāš ļø Cancellation requested. Cleaning up...\n"));
93
+ });
13
94
  const fileNameCases = {};
14
95
  const output = {
15
96
  Physical: 0,
@@ -22,29 +103,110 @@ const analyzeCodebase = async (options) => {
22
103
  Empty: 0,
23
104
  ToDo: 0,
24
105
  };
25
- console.log(chalk_1.default.bold(`\n\nAnalyzing codebase in ${chalk_1.default.cyan(options.directory)} ${(options === null || options === void 0 ? void 0 : options.framework) ? `framework: ${chalk_1.default.cyan(options.framework)}` : ""}\n`));
26
- let fileCount = 0;
27
- await (0, file_2.traverseDirectory)({
28
- extensions: options.extensions,
29
- directory: options.directory,
30
- exclude: options.exclude,
31
- checkFileNames: options.checkFileNames,
32
- onFile: (filePath) => {
33
- fileCount++;
34
- const { fileNameCase } = (0, file_1.analyzeFile)(filePath, output);
35
- if (fileNameCases[fileNameCase] !== undefined)
36
- fileNameCases[fileNameCase] += 1;
37
- else
38
- fileNameCases[fileNameCase] = 0;
39
- },
40
- });
41
- await (0, output_1.logOutput)({
42
- fileCount,
43
- fileNameCases,
44
- options,
45
- output,
46
- });
47
- const totalSecond = ((Date.now() - start) / 1000).toFixed(2);
48
- console.log(chalk_1.default.bold(`Time taken: ${chalk_1.default.yellow(totalSecond)}s\n`));
106
+ let progressBar = null;
107
+ try {
108
+ // Collect all files first
109
+ spinner.update("šŸ” Scanning directory structure...");
110
+ const files = await collectFiles(options.directory, options.extensions, options.exclude);
111
+ spinner.succeed(`āœ… Found ${files.length} files to analyze`);
112
+ if (files.length === 0) {
113
+ await (0, output_1.logOutput)({
114
+ fileCount: 0,
115
+ fileNameCases: {},
116
+ options,
117
+ output,
118
+ duration: (Date.now() - start) / 1000,
119
+ });
120
+ return;
121
+ }
122
+ // Create progress bar
123
+ const showProgress = options.showProgress !== false;
124
+ progressBar = showProgress
125
+ ? new progress_1.ProgressBar({ total: files.length })
126
+ : null;
127
+ // Cleanup progress bar on cancellation
128
+ cancellationToken.onCancel(() => {
129
+ progressBar === null || progressBar === void 0 ? void 0 : progressBar.stop();
130
+ });
131
+ // Process files with optimized concurrency
132
+ // For file I/O operations, optimal concurrency is 20-30 to avoid I/O contention
133
+ // Too high concurrency can actually slow things down due to disk I/O bottlenecks
134
+ const fileCount = files.length;
135
+ // Optimal concurrency for file I/O: 20-30 is usually the sweet spot
136
+ const defaultConcurrency = fileCount > 500 ? 30 : fileCount > 100 ? 25 : 20;
137
+ const maxConcurrency = options.maxConcurrency || defaultConcurrency;
138
+ if (maxConcurrency > 1) {
139
+ // Parallel processing
140
+ const chunks = [];
141
+ for (let i = 0; i < files.length; i += maxConcurrency) {
142
+ chunks.push(files.slice(i, i + maxConcurrency));
143
+ }
144
+ for (const chunk of chunks) {
145
+ // Check for cancellation before processing each chunk
146
+ if (cancellationToken.isCancelled()) {
147
+ progressBar === null || progressBar === void 0 ? void 0 : progressBar.stop();
148
+ throw new Error("Operation cancelled by user");
149
+ }
150
+ // Use Promise.allSettled to handle cancellation better
151
+ const results = await Promise.allSettled(chunk.map(async (filePath) => {
152
+ if (cancellationToken.isCancelled()) {
153
+ throw new Error("Operation cancelled by user");
154
+ }
155
+ if (options.checkFileNames || options.checkFileContent) {
156
+ processFile(filePath, output, fileNameCases);
157
+ }
158
+ progressBar === null || progressBar === void 0 ? void 0 : progressBar.update(1);
159
+ }));
160
+ // Check if any promise was cancelled
161
+ const cancelled = results.some((result) => {
162
+ var _a;
163
+ return result.status === "rejected" &&
164
+ ((_a = result.reason) === null || _a === void 0 ? void 0 : _a.message) === "Operation cancelled by user";
165
+ });
166
+ if (cancelled || cancellationToken.isCancelled()) {
167
+ progressBar === null || progressBar === void 0 ? void 0 : progressBar.stop();
168
+ throw new Error("Operation cancelled by user");
169
+ }
170
+ }
171
+ }
172
+ else {
173
+ // Sequential processing
174
+ for (const filePath of files) {
175
+ if (cancellationToken.isCancelled()) {
176
+ progressBar === null || progressBar === void 0 ? void 0 : progressBar.stop();
177
+ throw new Error("Operation cancelled by user");
178
+ }
179
+ if (options.checkFileNames || options.checkFileContent) {
180
+ processFile(filePath, output, fileNameCases);
181
+ }
182
+ progressBar === null || progressBar === void 0 ? void 0 : progressBar.update(1);
183
+ }
184
+ }
185
+ if (cancellationToken.isCancelled()) {
186
+ progressBar === null || progressBar === void 0 ? void 0 : progressBar.stop();
187
+ throw new Error("Operation cancelled by user");
188
+ }
189
+ progressBar === null || progressBar === void 0 ? void 0 : progressBar.complete();
190
+ const duration = (Date.now() - start) / 1000;
191
+ await (0, output_1.logOutput)({
192
+ fileCount,
193
+ fileNameCases,
194
+ options,
195
+ output,
196
+ duration,
197
+ exportFormat: options.exportFormat,
198
+ exportPath: options.exportPath,
199
+ });
200
+ }
201
+ catch (error) {
202
+ spinner.stop();
203
+ progressBar === null || progressBar === void 0 ? void 0 : progressBar.stop();
204
+ if ((error === null || error === void 0 ? void 0 : error.message) === "Operation cancelled by user" || cancellationToken.isCancelled()) {
205
+ console.log(chalk_1.default.yellow("\n\nāœ… Analysis cancelled by user\n"));
206
+ process.exit(130); // Standard exit code for SIGINT
207
+ }
208
+ spinner.fail(`āŒ Error during analysis: ${error}`);
209
+ throw error;
210
+ }
49
211
  };
50
212
  exports.analyzeCodebase = analyzeCodebase;
package/dist/index.js CHANGED
@@ -1,37 +1,224 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || function (mod) {
20
+ if (mod && mod.__esModule) return mod;
21
+ var result = {};
22
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
23
+ __setModuleDefault(result, mod);
24
+ return result;
25
+ };
3
26
  var __importDefault = (this && this.__importDefault) || function (mod) {
4
27
  return (mod && mod.__esModule) ? mod : { "default": mod };
5
28
  };
6
29
  Object.defineProperty(exports, "__esModule", { value: true });
30
+ exports.mergeOptions = void 0;
7
31
  const chalk_1 = __importDefault(require("chalk"));
8
32
  const commander_1 = require("commander");
9
33
  const runner_1 = __importDefault(require("./runner"));
34
+ const i18n_1 = require("./analyze/i18n");
35
+ const config_1 = require("./utils/config");
36
+ const boxen_1 = __importDefault(require("boxen"));
10
37
  chalk_1.default.level = 3;
38
+ /**
39
+ * Calculates optimal concurrency based on system resources and project size
40
+ * For large projects, uses higher concurrency for better performance
41
+ */
42
+ const calculateOptimalConcurrency = () => {
43
+ // Get CPU count (default to 4 if unavailable)
44
+ const cpuCount = require("os").cpus().length || 4;
45
+ // For large projects, use more aggressive concurrency
46
+ // Base: 2x CPU cores, but cap at reasonable limits
47
+ // This allows 50-100+ concurrent operations on modern machines
48
+ const baseConcurrency = Math.max(cpuCount * 2, 20);
49
+ // Cap at 200 to prevent overwhelming the system
50
+ return Math.min(baseConcurrency, 200);
51
+ };
52
+ // Merge config with CLI options (CLI options take precedence)
53
+ const mergeOptions = (config, cliOptions) => {
54
+ var _a, _b, _c, _d, _e, _f, _g, _h;
55
+ return {
56
+ directory: cliOptions.directory || "",
57
+ framework: cliOptions.framework || (config === null || config === void 0 ? void 0 : config.framework),
58
+ extensions: ((_a = cliOptions.extensions) === null || _a === void 0 ? void 0 : _a.length)
59
+ ? cliOptions.extensions
60
+ : config === null || config === void 0 ? void 0 : config.extensions,
61
+ exclude: ((_b = cliOptions.exclude) === null || _b === void 0 ? void 0 : _b.length) ? cliOptions.exclude : config === null || config === void 0 ? void 0 : config.exclude,
62
+ checkFileNames: cliOptions.checkFileNames !== undefined
63
+ ? cliOptions.checkFileNames
64
+ : (_c = config === null || config === void 0 ? void 0 : config.checkFileNames) !== null && _c !== void 0 ? _c : true,
65
+ checkFileContent: cliOptions.checkFileContent !== undefined
66
+ ? cliOptions.checkFileContent
67
+ : (_d = config === null || config === void 0 ? void 0 : config.checkFileContent) !== null && _d !== void 0 ? _d : true,
68
+ writeJsonOutput: cliOptions.writeJsonOutput !== undefined
69
+ ? cliOptions.writeJsonOutput
70
+ : (_e = config === null || config === void 0 ? void 0 : config.writeJsonOutput) !== null && _e !== void 0 ? _e : false,
71
+ showProgress: (_f = config === null || config === void 0 ? void 0 : config.showProgress) !== null && _f !== void 0 ? _f : true,
72
+ parallel: (_g = config === null || config === void 0 ? void 0 : config.parallel) !== null && _g !== void 0 ? _g : true,
73
+ maxConcurrency: (_h = config === null || config === void 0 ? void 0 : config.maxConcurrency) !== null && _h !== void 0 ? _h : calculateOptimalConcurrency(),
74
+ };
75
+ };
76
+ exports.mergeOptions = mergeOptions;
11
77
  commander_1.program
12
- .arguments("<directory>")
13
- .description("Analyze the specified directory")
78
+ .name("analyze-codebase")
79
+ .description("šŸ“Š A powerful CLI tool for analyzing codebase structure, naming conventions, and code quality")
80
+ .version("1.3.1")
81
+ .arguments("[directory]")
14
82
  .option("-f, --framework <framework>", "Specify the framework")
15
83
  .option("-e, --extensions <extensions...>", "Specify the extensions", (value, previous) => previous.concat(value), [])
16
84
  .option("-exc, --exclude <exclude...>", "Specify the exclude", (value, previous) => previous.concat(value), [])
17
85
  .option("--checkFileNames [checkFileNames]", "Check file names", parseBoolean)
18
- .option("--checkFileContent [checkFileContent]", "Check directories", parseBoolean)
86
+ .option("--checkFileContent [checkFileContent]", "Check file content", parseBoolean)
19
87
  .option("-w, --writeJsonOutput [writeJsonOutput]", "Write json output", parseBoolean)
20
- .action((directory, options) => {
21
- var _a, _b, _c;
22
- if (options.checkFileNames === false &&
23
- options.checkFileContent === false) {
24
- return console.error(chalk_1.default.red(`\nError: You must specify ${chalk_1.default.yellow("true")} at least one of the following options: ${chalk_1.default.yellow("--checkFileNames")}, ${chalk_1.default.yellow("--checkFileContent")}\n`));
88
+ .option("--i18n-file <i18nFile>", "Check for unused translation keys in the specified i18n JSON file (e.g., messages/en.json)")
89
+ .option("--watch", "Watch mode: automatically re-analyze on file changes")
90
+ .option("--no-progress", "Disable progress bar")
91
+ .option("--max-concurrency <number>", "Max concurrent file processing (default: auto, up to 200 for large projects)", parseInt)
92
+ .option("--export <format>", "Export format: json, csv, or html", "json")
93
+ .option("--output <path>", "Output path for export")
94
+ .action(async (directory = ".", options) => {
95
+ try {
96
+ // Load config file
97
+ const config = await (0, config_1.loadConfig)(directory);
98
+ if (config) {
99
+ const configPath = await Promise.resolve().then(() => __importStar(require("./utils/config"))).then((m) => m.findConfigFile(directory));
100
+ if (configPath) {
101
+ (0, config_1.displayConfigInfo)(configPath);
102
+ }
103
+ }
104
+ // If i18n-file is specified, run i18n analysis instead
105
+ if (options.i18nFile) {
106
+ try {
107
+ await (0, i18n_1.analyzeAndRemoveUnusedKeys)({
108
+ directory,
109
+ i18nFile: options.i18nFile,
110
+ extensions: options.extensions,
111
+ exclude: options.exclude,
112
+ maxConcurrency: options.maxConcurrency,
113
+ });
114
+ return;
115
+ }
116
+ catch (error) {
117
+ console.error(chalk_1.default.red(`\nError during i18n analysis: ${error}\n`));
118
+ process.exit(1);
119
+ }
120
+ }
121
+ // Watch mode
122
+ if (options.watch) {
123
+ const { startWatchMode } = await Promise.resolve().then(() => __importStar(require("./utils/watch")));
124
+ await startWatchMode(directory, options, config);
125
+ return;
126
+ }
127
+ const mergedOptions = (0, exports.mergeOptions)(config, {
128
+ ...options,
129
+ directory,
130
+ });
131
+ if (mergedOptions.checkFileNames === false &&
132
+ mergedOptions.checkFileContent === false) {
133
+ return console.error(chalk_1.default.red(`\nError: You must specify ${chalk_1.default.yellow("true")} at least one of the following options: ${chalk_1.default.yellow("--checkFileNames")}, ${chalk_1.default.yellow("--checkFileContent")}\n`));
134
+ }
135
+ // Auto-fix extensions without dot prefix (e.g., "ts" -> ".ts")
136
+ if (mergedOptions.extensions) {
137
+ mergedOptions.extensions = mergedOptions.extensions.map((ext) => ext.startsWith(".") ? ext : `.${ext}`);
138
+ }
139
+ // Override maxConcurrency if explicitly provided via CLI
140
+ const finalOptions = {
141
+ ...mergedOptions,
142
+ exportFormat: options.export,
143
+ exportPath: options.output,
144
+ };
145
+ if (options.maxConcurrency !== undefined) {
146
+ finalOptions.maxConcurrency = options.maxConcurrency;
147
+ }
148
+ (0, runner_1.default)(finalOptions);
25
149
  }
26
- if ((_a = options === null || options === void 0 ? void 0 : options.extensions) === null || _a === void 0 ? void 0 : _a.find((d) => !d.includes("."))) {
27
- return console.error(chalk_1.default.red("\nError: Extensions must include a dot (.)\n"));
150
+ catch (error) {
151
+ console.error(chalk_1.default.red(`\nāŒ Error: ${error}\n`));
152
+ process.exit(1);
28
153
  }
29
- (0, runner_1.default)({
30
- ...options,
31
- directory,
32
- checkFileContent: (_b = options.checkFileContent) !== null && _b !== void 0 ? _b : true,
33
- checkFileNames: (_c = options.checkFileNames) !== null && _c !== void 0 ? _c : true,
34
- });
154
+ });
155
+ // Add init command for creating config file
156
+ commander_1.program
157
+ .command("init")
158
+ .description("Initialize a config file (.analyze-codebase.json)")
159
+ .action(async () => {
160
+ const inquirer = (await Promise.resolve().then(() => __importStar(require("inquirer")))).default;
161
+ const { createConfigFile } = await Promise.resolve().then(() => __importStar(require("./utils/config")));
162
+ const answers = await inquirer.prompt([
163
+ {
164
+ type: "input",
165
+ name: "framework",
166
+ message: "Framework (optional):",
167
+ },
168
+ {
169
+ type: "input",
170
+ name: "extensions",
171
+ message: "File extensions (comma-separated, e.g., .ts,.tsx):",
172
+ default: ".ts,.tsx,.js,.jsx",
173
+ },
174
+ {
175
+ type: "input",
176
+ name: "exclude",
177
+ message: "Exclude directories (comma-separated):",
178
+ default: "node_modules,dist,build",
179
+ },
180
+ {
181
+ type: "confirm",
182
+ name: "checkFileNames",
183
+ message: "Check file names?",
184
+ default: true,
185
+ },
186
+ {
187
+ type: "confirm",
188
+ name: "checkFileContent",
189
+ message: "Check file content?",
190
+ default: true,
191
+ },
192
+ {
193
+ type: "confirm",
194
+ name: "writeJsonOutput",
195
+ message: "Write JSON output by default?",
196
+ default: false,
197
+ },
198
+ ]);
199
+ const config = {
200
+ framework: answers.framework || undefined,
201
+ extensions: answers.extensions
202
+ .split(",")
203
+ .map((ext) => ext.trim())
204
+ .filter((ext) => ext),
205
+ exclude: answers.exclude
206
+ .split(",")
207
+ .map((ex) => ex.trim())
208
+ .filter((ex) => ex),
209
+ checkFileNames: answers.checkFileNames,
210
+ checkFileContent: answers.checkFileContent,
211
+ writeJsonOutput: answers.writeJsonOutput,
212
+ showProgress: true,
213
+ parallel: true,
214
+ // maxConcurrency will be auto-calculated based on project size
215
+ };
216
+ const configPath = await createConfigFile(".", config);
217
+ console.log((0, boxen_1.default)(chalk_1.default.green(`āœ… Config file created: ${chalk_1.default.cyan(configPath)}`), {
218
+ padding: 1,
219
+ borderColor: "green",
220
+ borderStyle: "round",
221
+ }));
35
222
  });
36
223
  commander_1.program.parse(process.argv);
37
224
  function parseBoolean(value) {
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ const vitest_1 = require("vitest");
27
+ const fs = __importStar(require("fs/promises"));
28
+ const path = __importStar(require("path"));
29
+ const config_1 = require("../config");
30
+ (0, vitest_1.describe)("Config", () => {
31
+ const testDir = path.join(__dirname, "../../../test-temp");
32
+ const configPath = path.join(testDir, ".analyze-codebase.json");
33
+ (0, vitest_1.beforeEach)(async () => {
34
+ // Create test directory
35
+ try {
36
+ await fs.mkdir(testDir, { recursive: true });
37
+ }
38
+ catch (_a) {
39
+ // Directory might already exist
40
+ }
41
+ });
42
+ (0, vitest_1.afterEach)(async () => {
43
+ // Clean up test files
44
+ try {
45
+ await fs.unlink(configPath);
46
+ }
47
+ catch (_a) {
48
+ // File might not exist
49
+ }
50
+ try {
51
+ await fs.rmdir(testDir);
52
+ }
53
+ catch (_b) {
54
+ // Directory might not be empty
55
+ }
56
+ });
57
+ (0, vitest_1.it)("should create a config file", async () => {
58
+ const config = {
59
+ extensions: [".ts", ".tsx"],
60
+ exclude: ["node_modules"],
61
+ checkFileNames: true,
62
+ checkFileContent: true,
63
+ };
64
+ const createdPath = await (0, config_1.createConfigFile)(testDir, config);
65
+ (0, vitest_1.expect)(createdPath).toBe(configPath);
66
+ const exists = await fs.access(configPath).then(() => true).catch(() => false);
67
+ (0, vitest_1.expect)(exists).toBe(true);
68
+ });
69
+ (0, vitest_1.it)("should load a config file", async () => {
70
+ const config = {
71
+ extensions: [".ts", ".tsx"],
72
+ exclude: ["node_modules"],
73
+ checkFileNames: true,
74
+ checkFileContent: true,
75
+ };
76
+ await (0, config_1.createConfigFile)(testDir, config);
77
+ const loaded = await (0, config_1.loadConfig)(testDir);
78
+ (0, vitest_1.expect)(loaded).toBeTruthy();
79
+ (0, vitest_1.expect)(loaded === null || loaded === void 0 ? void 0 : loaded.extensions).toEqual(config.extensions);
80
+ (0, vitest_1.expect)(loaded === null || loaded === void 0 ? void 0 : loaded.exclude).toEqual(config.exclude);
81
+ });
82
+ (0, vitest_1.it)("should find config file in directory", async () => {
83
+ const config = {
84
+ extensions: [".ts"],
85
+ };
86
+ await (0, config_1.createConfigFile)(testDir, config);
87
+ const found = await (0, config_1.findConfigFile)(testDir);
88
+ (0, vitest_1.expect)(found).toBe(configPath);
89
+ });
90
+ (0, vitest_1.it)("should return null if config file doesn't exist", async () => {
91
+ const found = await (0, config_1.findConfigFile)(testDir);
92
+ (0, vitest_1.expect)(found).toBeNull();
93
+ });
94
+ });
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const progress_1 = require("../progress");
5
+ (0, vitest_1.describe)("ProgressBar", () => {
6
+ let progressBar;
7
+ (0, vitest_1.beforeEach)(() => {
8
+ // Suppress console output during tests
9
+ vitest_1.vi.spyOn(console, "log").mockImplementation(() => { });
10
+ });
11
+ (0, vitest_1.afterEach)(() => {
12
+ if (progressBar) {
13
+ progressBar.stop();
14
+ }
15
+ vitest_1.vi.restoreAllMocks();
16
+ });
17
+ (0, vitest_1.it)("should create a progress bar with total", () => {
18
+ progressBar = new progress_1.ProgressBar({ total: 100 });
19
+ (0, vitest_1.expect)(progressBar).toBeInstanceOf(progress_1.ProgressBar);
20
+ progressBar.stop();
21
+ });
22
+ (0, vitest_1.it)("should update progress", () => {
23
+ progressBar = new progress_1.ProgressBar({ total: 100 });
24
+ progressBar.update(10);
25
+ progressBar.update(20);
26
+ progressBar.stop();
27
+ });
28
+ (0, vitest_1.it)("should set total", () => {
29
+ progressBar = new progress_1.ProgressBar({ total: 50 });
30
+ progressBar.setTotal(100);
31
+ progressBar.stop();
32
+ });
33
+ (0, vitest_1.it)("should complete progress bar", () => {
34
+ progressBar = new progress_1.ProgressBar({ total: 100 });
35
+ progressBar.complete();
36
+ });
37
+ });