build-in-public-bot
Version:
AI-powered CLI bot for automating build-in-public tweets with code screenshots
206 lines • 9.21 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.screenshotCommand = void 0;
const commander_1 = require("commander");
const chalk_1 = __importDefault(require("chalk"));
const ora_1 = __importDefault(require("ora"));
const fs = __importStar(require("fs/promises"));
const path = __importStar(require("path"));
const glob = require('glob');
const screenshot_1 = require("../services/screenshot");
const config_1 = require("../services/config");
const errors_1 = require("../utils/errors");
exports.screenshotCommand = new commander_1.Command('screenshot')
.description('Generate code screenshots')
.argument('[file]', 'File to screenshot')
.option('-o, --output <path>', 'Output file path')
.option('-t, --theme <theme>', 'Theme to use')
.option('-s, --shader <shader>', 'Shader effect to apply')
.option('-l, --lines <range>', 'Line range (e.g., "10-20")')
.option('--glob <pattern>', 'Process multiple files with glob pattern')
.option('--output-dir <dir>', 'Output directory for batch processing')
.option('--list-themes', 'List available themes')
.option('--list-shaders', 'List available shaders')
.option('--width <width>', 'Screenshot width', '800')
.option('--font-size <size>', 'Font size', '16')
.option('--no-window-controls', 'Hide window controls')
.option('--line-numbers', 'Show line numbers')
.option('--padding <padding>', 'Outer padding', '60')
.option('--dry-run', 'Show what would be done without creating files')
.action(async (file, options) => {
try {
const configService = config_1.ConfigService.getInstance();
const config = await configService.load();
const screenshotService = screenshot_1.ScreenshotService.getInstance();
if (options.listThemes) {
const themes = screenshotService.getAvailableThemes();
console.log(chalk_1.default.cyan('Available themes:'));
themes.forEach(theme => {
console.log(` - ${theme}`);
});
return;
}
if (options.listShaders) {
const shaders = ['wave-gradient', 'halftone', 'disruptor', 'matrix', 'cyberpunk'];
console.log(chalk_1.default.cyan('Available shaders:'));
shaders.forEach(shader => {
console.log(` - ${shader}`);
});
return;
}
if (options.glob) {
await processBatch(options.glob, options, config, screenshotService);
return;
}
if (!file) {
console.error(chalk_1.default.red('Error: File path or --glob pattern required'));
process.exit(1);
}
await processSingleFile(file, options, config, screenshotService);
}
catch (error) {
(0, errors_1.handleError)(error);
}
});
async function processSingleFile(file, options, config, screenshotService) {
const spinner = (0, ora_1.default)('Generating screenshot...').start();
try {
const { code, language } = await screenshotService.readCodeFile(file, options.lines);
const screenshotConfig = {
...config.screenshots,
theme: options.theme || config.screenshots.theme,
padding: parseInt(options.padding) || config.screenshots.padding
};
const screenshotOptions = {
windowControls: options.windowControls !== false,
lineNumbers: options.lineNumbers || false,
width: parseInt(options.width),
fontSize: parseInt(options.fontSize),
shader: options.shader
};
if (options.dryRun) {
spinner.stop();
console.log(chalk_1.default.yellow('Dry run - would generate:'));
console.log(` File: ${file}`);
console.log(` Theme: ${screenshotConfig.theme}`);
console.log(` Shader: ${options.shader || 'none'}`);
console.log(` Output: ${options.output || 'screenshot.png'}`);
return;
}
const buffer = await screenshotService.generateCodeScreenshot(code, language, screenshotConfig, screenshotOptions);
const outputPath = options.output || `screenshot-${Date.now()}.png`;
await fs.writeFile(outputPath, buffer);
spinner.succeed(chalk_1.default.green(`Screenshot saved to ${outputPath}`));
}
catch (error) {
spinner.fail(chalk_1.default.red('Failed to generate screenshot'));
throw error;
}
}
async function processBatch(pattern, options, config, screenshotService) {
const spinner = (0, ora_1.default)('Finding files...').start();
try {
const files = await new Promise((resolve, reject) => {
glob(pattern, { ignore: ['node_modules/**', '.git/**'] }, (err, matches) => {
if (err)
reject(err);
else
resolve(matches);
});
});
if (files.length === 0) {
spinner.fail(chalk_1.default.yellow('No files found matching pattern'));
return;
}
spinner.succeed(chalk_1.default.green(`Found ${files.length} files`));
if (options.outputDir && !options.dryRun) {
await fs.mkdir(options.outputDir, { recursive: true });
}
let processed = 0;
let failed = 0;
for (const file of files) {
const fileSpinner = (0, ora_1.default)(`Processing ${file}...`).start();
try {
const { code, language } = await screenshotService.readCodeFile(file);
const screenshotConfig = {
...config.screenshots,
theme: options.theme || config.screenshots.theme,
padding: parseInt(options.padding) || config.screenshots.padding
};
const screenshotOptions = {
windowControls: options.windowControls !== false,
lineNumbers: options.lineNumbers || false,
width: parseInt(options.width),
fontSize: parseInt(options.fontSize),
shader: options.shader
};
const baseName = path.basename(file, path.extname(file));
const outputName = `${baseName}-screenshot.png`;
const outputPath = options.outputDir
? path.join(options.outputDir, outputName)
: outputName;
if (options.dryRun) {
fileSpinner.succeed(chalk_1.default.yellow(`[DRY RUN] Would create: ${outputPath}`));
processed++;
continue;
}
const buffer = await screenshotService.generateCodeScreenshot(code, language, screenshotConfig, screenshotOptions);
await fs.writeFile(outputPath, buffer);
fileSpinner.succeed(chalk_1.default.green(`✓ ${file} → ${outputPath}`));
processed++;
}
catch (error) {
fileSpinner.fail(chalk_1.default.red(`✗ ${file}: ${error instanceof Error ? error.message : 'Unknown error'}`));
failed++;
}
}
console.log('');
console.log(chalk_1.default.cyan('Summary:'));
console.log(` Processed: ${chalk_1.default.green(processed)}`);
if (failed > 0) {
console.log(` Failed: ${chalk_1.default.red(failed)}`);
}
}
catch (error) {
spinner.fail(chalk_1.default.red('Batch processing failed'));
throw error;
}
}
exports.default = exports.screenshotCommand;
//# sourceMappingURL=screenshot.js.map
;