UNPKG

image-asset-manager

Version:

A comprehensive image asset management tool for frontend projects

463 lines (461 loc) โ€ข 20.1 kB
#!/usr/bin/env node "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const commander_1 = require("commander"); const fs_1 = require("fs"); const ImageAssetManager_1 = require("./core/ImageAssetManager"); const config_1 = require("./config"); const progress_1 = require("./utils/progress"); const cli_validator_1 = require("./utils/cli-validator"); const program = new commander_1.Command(); const packageJson = require("../package.json"); program .name("image-asset-manager") .description("๐Ÿ–ผ๏ธ A comprehensive image asset management tool for frontend projects") .version(packageJson.version) .helpOption("-h, --help", "Display help information") .addHelpText("after", ` Examples: $ image-asset-manager # Start with default settings $ image-asset-manager ./my-project # Scan specific project $ image-asset-manager --optimize # Start with optimization enabled $ image-asset-manager scan --json # Scan and output JSON format $ image-asset-manager serve -p 8080 # Start web interface on port 8080 $ image-asset-manager optimize --quality 90 # Optimize with custom quality $ image-asset-manager generate --framework vue # Generate Vue components Configuration: Create image-asset.config.js or add "imageAssetManager" section to package.json Use --init to generate example configuration file For more information, visit: https://github.com/your-repo/image-asset-manager `); // ไธปๅ‘ฝไปค - ๅฏๅŠจๅฎŒๆ•ดๅŠŸ่ƒฝ program .argument("[project-path]", "Path to the project directory", process.cwd()) .option("-c, --config <config>", "Path to configuration file") .option("-e, --exclude <patterns...>", "Patterns to exclude from scanning") .option("-i, --include <patterns...>", "Patterns to include in scanning") .option("--no-watch", "Disable file watching") .option("--optimize", "Enable automatic optimization") .option("--silent", "Suppress non-error output") .option("--verbose", "Show detailed output") .action(async (projectPath, options) => { const startTime = Date.now(); const spinner = new progress_1.SpinnerDisplay(); try { if (!options.silent) { spinner.start("Initializing Image Asset Manager..."); } const configManager = new config_1.ConfigManager(options.config); const cliOptions = configManager.toCLIOptions({ projectPath: projectPath || process.cwd(), config: options.config, exclude: options.exclude, include: options.include, watch: options.watch !== false, optimize: options.optimize || false, }); const manager = new ImageAssetManager_1.ImageAssetManager(configManager); if (!options.silent) { spinner.stop(); console.log(`๐Ÿš€ Starting Image Asset Manager v${packageJson.version}`); console.log(`๐Ÿ“ Project: ${cliOptions.projectPath}`); console.log(`๐ŸŒ Port: ${cliOptions.port}`); console.log(`๐Ÿ‘€ Watch: ${cliOptions.watch ? "โœ…" : "โŒ"}`); console.log(`โšก Optimize: ${cliOptions.optimize ? "โœ…" : "โŒ"}`); console.log(""); } await manager.start(cliOptions); if (!options.silent) { const duration = (0, progress_1.formatDuration)(Date.now() - startTime); console.log(`โœ… Started successfully in ${duration}`); } } catch (error) { spinner.stop(); console.error("โŒ Error starting image asset manager:", error); if (options.verbose && error instanceof Error) { console.error("Stack trace:", error.stack); } process.exit(1); } }); // ๆ‰ซๆๅ‘ฝไปค program .command("scan") .description("๐Ÿ” Scan project for image assets") .argument("[project-path]", "Path to the project directory", process.cwd()) .option("-c, --config <config>", "Path to configuration file") .option("-e, --exclude <patterns...>", "Patterns to exclude from scanning") .option("-i, --include <patterns...>", "Patterns to include in scanning") .option("--json", "Output results in JSON format") .option("--csv", "Output results in CSV format") .option("--duplicates", "Show duplicate files only") .option("--unused", "Show unused files only") .option("--stats", "Show project statistics") .option("--silent", "Suppress non-error output") .option("--verbose", "Show detailed output") .addHelpText("after", ` Examples: $ image-asset-manager scan # Basic scan $ image-asset-manager scan --json # Output JSON $ image-asset-manager scan --duplicates # Find duplicates $ image-asset-manager scan --unused # Find unused images $ image-asset-manager scan --stats # Show statistics `) .action(async (projectPath, options) => { const startTime = Date.now(); const spinner = new progress_1.SpinnerDisplay(); try { if (!options.silent) { spinner.start("Scanning project for image assets..."); } const configManager = new config_1.ConfigManager(options.config); const cliOptions = configManager.toCLIOptions({ projectPath: projectPath || process.cwd(), exclude: options.exclude || undefined, include: options.include || undefined, watch: false, optimize: false, }); // ้ชŒ่ฏ้€‰้กน const validator = new cli_validator_1.CLIValidator(configManager); const scanOptions = { outputFormat: options.json ? "json" : options.csv ? "csv" : "table", showDuplicates: options.duplicates, showUnused: options.unused, showStats: options.stats, silent: options.silent, verbose: options.verbose, }; const validationResult = validator.validateScanOptions(cliOptions, scanOptions); if (!(0, cli_validator_1.displayValidationResult)(validationResult, options.silent)) { process.exit(1); } const manager = new ImageAssetManager_1.ImageAssetManager(configManager); if (!options.silent) { spinner.stop(); console.log(`๐Ÿ” Scanning: ${cliOptions.projectPath}`); } await manager.scan(cliOptions, scanOptions); if (!options.silent) { const duration = (0, progress_1.formatDuration)(Date.now() - startTime); console.log(`โœ… Scan completed in ${duration}`); } } catch (error) { spinner.stop(); console.error("โŒ Error scanning project:", error); if (options.verbose && error instanceof Error) { console.error("Stack trace:", error.stack); } process.exit(1); } }); // ๆœๅŠกๅ‘ฝไปค program .command("serve") .description("๐ŸŒ Start the web interface") .argument("[project-path]", "Path to the project directory", process.cwd()) .option("-p, --port <port>", "Port for the web server", "3000") .option("-c, --config <config>", "Path to configuration file") .option("--host <host>", "Host to bind the server", "localhost") .option("--no-cors", "Disable CORS") .option("--no-watch", "Disable file watching") .option("--auth <token>", "Enable authentication with token") .option("--ssl-cert <cert>", "SSL certificate file") .option("--ssl-key <key>", "SSL private key file") .option("--silent", "Suppress non-error output") .option("--verbose", "Show detailed output") .addHelpText("after", ` Examples: $ image-asset-manager serve # Start on localhost:3000 $ image-asset-manager serve -p 8080 # Custom port $ image-asset-manager serve --host 0.0.0.0 # Bind to all interfaces $ image-asset-manager serve --auth secret123 # Enable authentication `) .action(async (projectPath, options) => { const startTime = Date.now(); const spinner = new progress_1.SpinnerDisplay(); try { if (!options.silent) { spinner.start("Starting web server..."); } const configManager = new config_1.ConfigManager(options.config); const cliOptions = configManager.toCLIOptions({ projectPath: projectPath || process.cwd(), port: parseInt(options.port, 10), watch: options.watch !== false, optimize: false, }); const manager = new ImageAssetManager_1.ImageAssetManager(configManager); if (!options.silent) { spinner.stop(); console.log(`๐ŸŒ Starting web server...`); console.log(`๐Ÿ“ Project: ${cliOptions.projectPath}`); console.log(`๐ŸŒ Address: http://${options.host || "localhost"}:${cliOptions.port}`); console.log(`๐Ÿ‘€ Watch: ${cliOptions.watch ? "โœ…" : "โŒ"}`); if (options.auth) { console.log(`๐Ÿ” Auth: โœ… (token required)`); } console.log(""); } await manager.serve(cliOptions, { host: options.host, cors: options.cors !== false, auth: options.auth, ssl: options.sslCert && options.sslKey ? { cert: options.sslCert, key: options.sslKey, } : undefined, silent: options.silent, verbose: options.verbose, }); if (!options.silent) { const duration = (0, progress_1.formatDuration)(Date.now() - startTime); console.log(`โœ… Server started in ${duration}`); } } catch (error) { spinner.stop(); console.error("โŒ Error starting web server:", error); if (options.verbose && error instanceof Error) { console.error("Stack trace:", error.stack); } process.exit(1); } }); // ไผ˜ๅŒ–ๅ‘ฝไปค program .command("optimize") .description("โšก Optimize image assets") .argument("[project-path]", "Path to the project directory", process.cwd()) .option("-c, --config <config>", "Path to configuration file") .option("-o, --output <dir>", "Output directory for optimized images") .option("-q, --quality <quality>", "Image quality (1-100)", "80") .option("--png-quality <quality>", "PNG quality (1-100)") .option("--jpg-quality <quality>", "JPG quality (1-100)") .option("--webp-quality <quality>", "WebP quality (1-100)") .option("--no-progressive", "Disable progressive encoding") .option("--no-keep-original", "Don't keep original files") .option("--batch-size <size>", "Batch processing size", "10") .option("--parallel <count>", "Parallel processing count", "4") .option("--dry-run", "Preview optimization without saving") .option("--silent", "Suppress non-error output") .option("--verbose", "Show detailed output") .addHelpText("after", ` Examples: $ image-asset-manager optimize # Basic optimization $ image-asset-manager optimize -q 90 # Custom quality $ image-asset-manager optimize -o ./optimized # Custom output $ image-asset-manager optimize --dry-run # Preview only $ image-asset-manager optimize --parallel 8 # More parallel jobs `) .action(async (projectPath, options) => { const startTime = Date.now(); const spinner = new progress_1.SpinnerDisplay(); try { if (!options.silent) { spinner.start("Optimizing image assets..."); } const configManager = new config_1.ConfigManager(options.config); const cliOptions = configManager.toCLIOptions({ projectPath: projectPath || process.cwd(), watch: false, optimize: true, }); const manager = new ImageAssetManager_1.ImageAssetManager(configManager); if (!options.silent) { spinner.stop(); console.log(`โšก Optimizing images in: ${cliOptions.projectPath}`); if (options.output) { console.log(`๐Ÿ“ Output directory: ${options.output}`); } if (options.dryRun) { console.log(`๐Ÿ” Dry run mode - no files will be modified`); } console.log(""); } await manager.optimize(cliOptions, { outputDir: options.output, quality: parseInt(options.quality, 10), pngQuality: options.pngQuality ? parseInt(options.pngQuality, 10) : undefined, jpgQuality: options.jpgQuality ? parseInt(options.jpgQuality, 10) : undefined, webpQuality: options.webpQuality ? parseInt(options.webpQuality, 10) : undefined, progressive: options.progressive !== false, keepOriginal: options.keepOriginal !== false, batchSize: parseInt(options.batchSize, 10), parallel: parseInt(options.parallel, 10), dryRun: options.dryRun, silent: options.silent, verbose: options.verbose, }); if (!options.silent) { const duration = (0, progress_1.formatDuration)(Date.now() - startTime); console.log(`โœ… Optimization completed in ${duration}`); } } catch (error) { spinner.stop(); console.error("โŒ Error optimizing images:", error); if (options.verbose && error instanceof Error) { console.error("Stack trace:", error.stack); } process.exit(1); } }); // ็”Ÿๆˆๅ‘ฝไปค program .command("generate") .description("๐Ÿ”ง Generate type definitions and import files") .argument("[project-path]", "Path to the project directory", process.cwd()) .option("-c, --config <config>", "Path to configuration file") .option("-f, --framework <framework>", "Target framework (react|vue|angular|svelte)", "react") .option("-o, --output <dir>", "Output directory", "src/assets") .option("--typescript", "Generate TypeScript definitions") .option("--no-typescript", "Generate JavaScript only") .option("--component-prefix <prefix>", "Component name prefix", "Icon") .option("--barrel-file", "Generate barrel export file") .option("--watch", "Watch for changes and regenerate") .option("--silent", "Suppress non-error output") .option("--verbose", "Show detailed output") .addHelpText("after", ` Examples: $ image-asset-manager generate # Generate React components $ image-asset-manager generate -f vue # Generate Vue components $ image-asset-manager generate --typescript # Include TypeScript $ image-asset-manager generate --watch # Watch mode $ image-asset-manager generate --barrel-file # Create index file `) .action(async (projectPath, options) => { const startTime = Date.now(); const spinner = new progress_1.SpinnerDisplay(); try { if (!options.silent) { spinner.start("Generating code files..."); } const configManager = new config_1.ConfigManager(options.config); const cliOptions = configManager.toCLIOptions({ projectPath: projectPath || process.cwd(), watch: options.watch || false, optimize: false, }); const manager = new ImageAssetManager_1.ImageAssetManager(configManager); if (!options.silent) { spinner.stop(); console.log(`๐Ÿ”ง Generating ${options.framework} code for: ${cliOptions.projectPath}`); console.log(`๐Ÿ“ Output directory: ${options.output}`); console.log(`๐Ÿ“ TypeScript: ${options.typescript !== false ? "โœ…" : "โŒ"}`); if (options.watch) { console.log(`๐Ÿ‘€ Watch mode: โœ…`); } console.log(""); } await manager.generate(cliOptions, { framework: options.framework, outputDir: options.output, typescript: options.typescript !== false, componentPrefix: options.componentPrefix, barrelFile: options.barrelFile, watch: options.watch, silent: options.silent, verbose: options.verbose, }); if (!options.silent) { const duration = (0, progress_1.formatDuration)(Date.now() - startTime); console.log(`โœ… Code generation completed in ${duration}`); } } catch (error) { spinner.stop(); console.error("โŒ Error generating code:", error); if (options.verbose && error instanceof Error) { console.error("Stack trace:", error.stack); } process.exit(1); } }); // ๅˆๅง‹ๅŒ–้…็ฝฎๅ‘ฝไปค program .command("init") .description("๐Ÿ“ Initialize configuration file") .option("--js", "Generate JavaScript config file", false) .option("--json", "Generate JSON config file", false) .option("--package", "Add config to package.json", false) .option("--force", "Overwrite existing config file", false) .addHelpText("after", ` Examples: $ image-asset-manager init # Generate image-asset.config.js $ image-asset-manager init --json # Generate .image-asset.json $ image-asset-manager init --package # Add to package.json $ image-asset-manager init --force # Overwrite existing `) .action(async (options) => { try { let configPath; let configContent; if (options.package) { configPath = "package.json"; if ((0, fs_1.existsSync)(configPath) && !options.force) { const pkg = JSON.parse(require("fs").readFileSync(configPath, "utf-8")); if (pkg.imageAssetManager) { console.log("โš ๏ธ Configuration already exists in package.json"); console.log("Use --force to overwrite"); return; } pkg.imageAssetManager = JSON.parse(config_1.ConfigManager.generateExampleConfig().replace(/^\/\/ .*\n|module\.exports = |;$/gm, "")); configContent = JSON.stringify(pkg, null, 2); } else { console.error("โŒ package.json not found"); process.exit(1); } } else if (options.json) { configPath = ".image-asset.json"; configContent = config_1.ConfigManager.generateExampleConfig().replace(/^\/\/ .*\n|module\.exports = |;$/gm, ""); } else { configPath = "image-asset.config.js"; configContent = config_1.ConfigManager.generateExampleConfig(); } if ((0, fs_1.existsSync)(configPath) && !options.force && !options.package) { console.log(`โš ๏ธ Configuration file ${configPath} already exists`); console.log("Use --force to overwrite"); return; } (0, fs_1.writeFileSync)(configPath, configContent); console.log(`โœ… Configuration file created: ${configPath}`); console.log(""); console.log("Next steps:"); console.log("1. Edit the configuration file to match your project needs"); console.log("2. Run 'image-asset-manager scan' to test the configuration"); console.log("3. Run 'image-asset-manager serve' to start the web interface"); } catch (error) { console.error("โŒ Error creating configuration file:", error); process.exit(1); } }); // ๅ…จๅฑ€้”™่ฏฏๅค„็† process.on("uncaughtException", (error) => { console.error("โŒ Uncaught Exception:", error); process.exit(1); }); process.on("unhandledRejection", (reason, promise) => { console.error("โŒ Unhandled Rejection at:", promise, "reason:", reason); process.exit(1); }); program.parse(); //# sourceMappingURL=cli.js.map