crapifyme
Version:
Ultra-fast developer productivity CLI tools - remove comments, logs, and more
205 lines • 9.88 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.charsCommand = void 0;
const commander_1 = require("commander");
const shared_1 = require("../../shared");
const logic_1 = require("./logic");
const types_1 = require("./types");
exports.charsCommand = new commander_1.Command('chars')
.description('Detect and fix non-Latin characters that may cause encoding issues')
.argument('[paths...]', 'Files or directories to process', ['.'])
.option('-e, --extensions <ext>', 'File extensions to process', 'js,ts,jsx,tsx,vue,svelte,astro,html,css,scss,less,sass,py,java,c,cpp,cs,php,rb,go,rs')
.option('-x, --exclude <patterns>', 'Glob patterns to exclude')
.option('--fix', 'Automatically fix detected issues with ASCII replacements')
.option('--strict', 'Enable strict mode (flag all non-ASCII characters)')
.option('--interactive', 'Prompt for each replacement (requires --fix)')
.option('--show-context <number>', 'Number of characters to show around each issue', '40')
.option('--ignore-strings', 'Ignore characters inside string literals')
.option('--ignore-comments', 'Ignore characters inside comments')
.option('--severity <level>', 'Minimum severity level to report (low,medium,high,critical)', 'low')
.action(async (paths, options, command) => {
const globalOptions = command.parent?.opts() || {};
const logger = new shared_1.Logger(globalOptions.verbose, globalOptions.quiet, globalOptions.json);
if (!globalOptions.force) {
const vcsResult = (0, shared_1.detectVersionControl)();
if (!vcsResult.detected && options.fix) {
logger.error('No version control system detected in this project or its parent directories.');
logger.error('This tool can modify your code files, which is a potentially destructive operation.');
logger.error('Use --force to proceed without version control.');
process.exit(shared_1.ExitCode.Error);
}
if (globalOptions.verbose && vcsResult.detected) {
logger.info(`Version control detected: ${vcsResult.type} at ${vcsResult.path}`);
}
}
try {
const extensions = options.extensions.split(',').map((e) => e.trim());
const patterns = (0, shared_1.createFilePatterns)(paths, extensions);
const excludePatterns = options.exclude
?.split(',')
.map((p) => p.trim())
.filter(Boolean) || [];
logger.info(`Search patterns: ${patterns.join(', ')}`);
if (excludePatterns.length > 0) {
logger.info(`Exclude patterns: ${excludePatterns.join(', ')}`);
}
const files = await (0, shared_1.findFiles)(patterns, excludePatterns);
if (files.length === 0) {
logger.warn('No files found to process');
logger.info(`Searched in: ${paths.join(', ')}`);
logger.info(`Extensions: ${extensions.join(', ')}`);
process.exit(shared_1.ExitCode.Success);
}
logger.info(`Found ${files.length} file${files.length === 1 ? '' : 's'} to process`);
if (globalOptions.dryRun || !options.fix) {
logger.info(options.fix
? 'DRY RUN - No files will be modified'
: 'DETECTION MODE - No files will be modified');
}
const detectorOptions = {
strict: options.strict,
interactive: options.interactive,
showContext: parseInt(options.showContext) || 40,
ignoreStrings: options.ignoreStrings,
ignoreComments: options.ignoreComments
};
const detector = new logic_1.CharacterDetector(logger, detectorOptions);
const minSeverity = parseSeverity(options.severity);
const stats = {
filesProcessed: 0,
itemsRemoved: 0,
itemsPreserved: 0,
charactersFound: 0,
charactersFixed: 0,
scriptTypes: {},
errors: []
};
for (const scriptType of Object.values(types_1.ScriptType)) {
stats.scriptTypes[scriptType] = 0;
}
for (const file of files) {
try {
const content = await (0, shared_1.readFile)(file);
const result = options.fix && !globalOptions.dryRun
? detector.fixCharacters(content, file)
: detector.detectCharacters(content, file);
const filteredIssues = result.issues.filter(issue => getSeverityLevel(issue.severity) >= getSeverityLevel(minSeverity));
if (result.modified && !globalOptions.dryRun) {
await (0, shared_1.writeFile)(file, result.content);
}
stats.filesProcessed++;
stats.charactersFound += filteredIssues.length;
stats.charactersFixed += result.fixed;
const scriptStats = detector.getScriptTypeStats(filteredIssues);
for (const [scriptType, count] of Object.entries(scriptStats)) {
stats.scriptTypes[scriptType] += count;
}
if (filteredIssues.length > 0) {
logger.success(`${file}`);
if (globalOptions.verbose || !globalOptions.json) {
for (const issue of filteredIssues.slice(0, 10)) {
const prefix = issue.severity === types_1.IssueSeverity.CRITICAL
? '⚠️ '
: issue.severity === types_1.IssueSeverity.HIGH
? '🔴 '
: issue.severity === types_1.IssueSeverity.MEDIUM
? '🟡 '
: '🔵 ';
console.log(` ${prefix}Line ${issue.line}:${issue.column} - ${issue.character} (U+${issue.codePoint.toString(16).toUpperCase().padStart(4, '0')}) [${issue.script}]`);
if (issue.replacement) {
console.log(` ↳ Suggests: "${issue.replacement}"`);
}
console.log(` Context: ${issue.context}`);
}
if (filteredIssues.length > 10) {
console.log(` ... and ${filteredIssues.length - 10} more issues`);
}
}
console.log(` ┣ Characters found: ${filteredIssues.length}`);
if (options.fix) {
console.log(` ┣ Characters fixed: ${result.fixed}`);
}
console.log(` ┗ Status: ${globalOptions.dryRun ? 'DRY RUN - would be modified' : result.modified ? 'Modified' : 'Detected only'}`);
}
else if (globalOptions.verbose) {
logger.info(`${file} - No issues found`);
}
}
catch (error) {
stats.errors.push({ file, error: error.message });
logger.error(`Failed to process ${file}`, error);
}
}
if (globalOptions.json) {
logger.json(stats);
}
else {
if (stats.errors.length > 0) {
logger.error(`Processing completed with ${stats.errors.length} error${stats.errors.length === 1 ? '' : 's'}`);
}
else {
logger.success('Processing completed successfully');
}
logger.info(`Files processed: ${stats.filesProcessed}`);
logger.info(`Characters found: ${stats.charactersFound}`);
if (options.fix) {
logger.info(`Characters fixed: ${stats.charactersFixed}`);
}
if (stats.charactersFound > 0) {
console.log('\nScript distribution:');
for (const [scriptType, count] of Object.entries(stats.scriptTypes)) {
if (count > 0) {
console.log(` ${scriptType}: ${count}`);
}
}
}
(0, shared_1.showComplete)();
if (globalOptions.dryRun && options.fix && stats.charactersFound > 0) {
logger.warn('DRY RUN MODE - No files were actually modified');
logger.info('Remove --dry-run to apply changes');
}
else if (!options.fix && stats.charactersFound > 0) {
logger.info('Add --fix flag to automatically replace characters');
}
}
const exitCode = stats.errors.length > 0
? shared_1.ExitCode.Error
: stats.charactersFound > 0
? shared_1.ExitCode.IssuesFound
: shared_1.ExitCode.Success;
process.exit(exitCode);
}
catch (error) {
logger.error('Fatal error', error);
process.exit(shared_1.ExitCode.Error);
}
});
function parseSeverity(severity) {
switch (severity.toLowerCase()) {
case 'low':
return types_1.IssueSeverity.LOW;
case 'medium':
return types_1.IssueSeverity.MEDIUM;
case 'high':
return types_1.IssueSeverity.HIGH;
case 'critical':
return types_1.IssueSeverity.CRITICAL;
default:
return types_1.IssueSeverity.LOW;
}
}
function getSeverityLevel(severity) {
switch (severity) {
case types_1.IssueSeverity.LOW:
return 1;
case types_1.IssueSeverity.MEDIUM:
return 2;
case types_1.IssueSeverity.HIGH:
return 3;
case types_1.IssueSeverity.CRITICAL:
return 4;
default:
return 1;
}
}
//# sourceMappingURL=index.js.map