@dkoul/auto-testid-cli
Version:
Command-line interface for React and Vue.js custom attribute generation
238 lines ⢠10.7 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateCommand = generateCommand;
const chalk_1 = __importDefault(require("chalk"));
const ora_1 = __importDefault(require("ora"));
const auto_testid_core_1 = require("@dkoul/auto-testid-core");
const path = __importStar(require("path"));
const fs = __importStar(require("fs/promises"));
async function generateCommand(targetPath, options) {
const spinner = (0, ora_1.default)('Initializing Auto-TestID...').start();
try {
// Parse options
const config = {
frameworks: options.framework ? [options.framework] : ['react'],
namingStrategy: { type: options.naming || 'kebab-case' },
prefix: options.prefix || 'test',
attributeName: options.attributeName || 'data-testid',
maxIdLength: parseInt(options.maxLength || '50'),
exclude: options.exclude || [],
preserveExisting: true,
};
// Load custom config if specified
if (options.config) {
try {
const configContent = await fs.readFile(options.config, 'utf-8');
const customConfig = JSON.parse(configContent);
Object.assign(config, customConfig);
spinner.succeed(`Configuration loaded from ${options.config}`);
}
catch (error) {
spinner.warn(`Could not load config from ${options.config}, using defaults`);
}
}
else {
spinner.succeed('Using default configuration');
}
// Initialize the core API
const autoTestID = (0, auto_testid_core_1.createAutoTestID)(config);
// Resolve target path
const resolvedPath = path.resolve(targetPath);
// Check if path exists
try {
await fs.access(resolvedPath);
}
catch {
spinner.fail(`Path does not exist: ${resolvedPath}`);
process.exit(1);
}
// Determine if processing file or directory
const stats = await fs.stat(resolvedPath);
let filePaths = [];
if (stats.isFile()) {
filePaths = [resolvedPath];
spinner.succeed(`Processing single file: ${path.basename(resolvedPath)}`);
}
else if (stats.isDirectory()) {
spinner.text = 'Scanning directory for files...';
const scanOptions = {
include: options.include || ['**/*.{js,jsx,ts,tsx,vue,html}'],
exclude: options.exclude || [
'**/node_modules/**',
'**/dist/**',
'**/build/**',
'**/*.test.*',
'**/*.spec.*'
],
frameworks: config.frameworks || ['react'],
recursive: true,
};
filePaths = await autoTestID.scanDirectory(resolvedPath, scanOptions);
if (filePaths.length === 0) {
spinner.warn('No supported files found in directory');
process.exit(0);
}
spinner.succeed(`Found ${filePaths.length} files to process`);
}
// Progress tracking
let processedFiles = 0;
let totalElements = 0;
let totalTransformed = 0;
let totalErrors = 0;
const progressSpinner = (0, ora_1.default)('Processing files...').start();
const onProgress = (progress) => {
const percentage = Math.round((progress.completed / progress.total) * 100);
progressSpinner.text = `Processing ${progress.stage}: ${path.basename(progress.current)} (${percentage}%)`;
};
// Process files
const results = await autoTestID.processFiles(filePaths, {
dryRun: options.dryRun,
backup: options.backup,
config,
onProgress,
});
progressSpinner.stop();
// Analyze results
let hasErrors = false;
const successfulResults = [];
const failedResults = [];
results.forEach(result => {
processedFiles++;
totalElements += result.metrics.elementsFound;
totalTransformed += result.metrics.elementsTransformed;
totalErrors += result.errors.length;
if (result.success) {
successfulResults.push(result);
}
else {
failedResults.push(result);
hasErrors = true;
}
});
// Display results
console.log(chalk_1.default.cyan.bold('\nšÆ Auto-TestID Generation Results\n'));
if (options.dryRun) {
console.log(chalk_1.default.yellow('š Dry Run Mode - No files were modified\n'));
}
// Summary statistics
console.log(chalk_1.default.white('š Summary:'));
console.log(` ${chalk_1.default.green('Files processed:')} ${processedFiles}`);
console.log(` ${chalk_1.default.blue('Elements found:')} ${totalElements}`);
console.log(` ${chalk_1.default.green('Test IDs generated:')} ${totalTransformed}`);
if (totalErrors > 0) {
console.log(` ${chalk_1.default.red('Errors:')} ${totalErrors}`);
}
// Show successful transformations
if (successfulResults.length > 0) {
console.log(chalk_1.default.green.bold('\nā
Successfully processed:'));
successfulResults.forEach(result => {
const fileName = path.basename(result.filePath);
const transformCount = result.transformations.length;
const timeMs = result.metrics.processingTime;
console.log(` ${chalk_1.default.green('ā')} ${fileName} (${transformCount} test IDs, ${timeMs}ms)`);
// Show transformations in dry-run mode
if (options.dryRun && result.transformations.length > 0) {
result.transformations.slice(0, 3).forEach(transform => {
const element = transform.element;
const preview = element.content ? ` "${element.content}"` : '';
console.log(` ${chalk_1.default.dim('+')} ${element.tag}${preview} ā ${transform.attribute}="${transform.value}"`);
});
if (result.transformations.length > 3) {
console.log(` ${chalk_1.default.dim(`... and ${result.transformations.length - 3} more`)}`);
}
}
});
}
// Show errors
if (failedResults.length > 0) {
console.log(chalk_1.default.red.bold('\nā Failed to process:'));
failedResults.forEach(result => {
const fileName = path.basename(result.filePath);
console.log(` ${chalk_1.default.red('ā')} ${fileName}`);
result.errors.forEach(error => {
console.log(` ${chalk_1.default.red('ā')} ${error.message}`);
});
});
}
// Performance metrics
const totalTime = results.reduce((sum, r) => sum + r.metrics.processingTime, 0);
const avgTimePerFile = totalTime / results.length;
console.log(chalk_1.default.blue.bold('\nā” Performance:'));
console.log(` ${chalk_1.default.blue('Total time:')} ${totalTime}ms`);
console.log(` ${chalk_1.default.blue('Average per file:')} ${avgTimePerFile.toFixed(1)}ms`);
// Recommendations
if (totalTransformed === 0 && totalElements > 0) {
console.log(chalk_1.default.yellow.bold('\nš” Recommendations:'));
console.log(' ⢠Elements were found but no test IDs were generated');
console.log(' ⢠Check your include/exclude patterns');
console.log(' ⢠Verify the framework setting matches your files');
}
if (options.dryRun && totalTransformed > 0) {
console.log(chalk_1.default.yellow.bold('\nš” Next steps:'));
console.log(` ⢠Run without --dry-run to apply ${totalTransformed} changes`);
console.log(' ⢠Use --backup to create backup files');
}
// Exit with appropriate code
process.exit(hasErrors ? 1 : 0);
}
catch (error) {
spinner.fail(`Generation failed: ${error.message}`);
if (options.logLevel === 'debug') {
console.error(chalk_1.default.red('Stack trace:'), error.stack);
}
process.exit(1);
}
}
// Helper function to format file size
function formatFileSize(bytes) {
const sizes = ['B', 'KB', 'MB'];
if (bytes === 0)
return '0 B';
const i = Math.floor(Math.log(bytes) / Math.log(1024));
return `${(bytes / Math.pow(1024, i)).toFixed(1)} ${sizes[i]}`;
}
// Helper function to format duration
function formatDuration(ms) {
if (ms < 1000)
return `${ms}ms`;
if (ms < 60000)
return `${(ms / 1000).toFixed(1)}s`;
return `${Math.floor(ms / 60000)}m ${Math.floor((ms % 60000) / 1000)}s`;
}
//# sourceMappingURL=generate.js.map