penframe
Version:
A lightweight DSL-based wireframe and UI structure visualization tool.
99 lines (85 loc) • 3.87 kB
JavaScript
const fs = require('fs');
const path = require('path');
const parser = require('../dist/parser.js');
const astToSvg = require('./svg/astToSvg');
const { astToPngFile } = require('./svg/astToPng');
const main = async () => {
const args = process.argv.slice(2);
const filePath = args[0];
if (!filePath || args.includes('--help') || args.includes('-h')) {
console.log('PenFrame - DSL-based wireframe visualization tool');
console.log('');
console.log('Usage: penframe <input.pf> [options]');
console.log('');
console.log('Options:');
console.log(' --svg <output.svg> Generate SVG file');
console.log(' --png <output.png> Generate PNG file (using Puppeteer)');
console.log(' --width <number> PNG viewport width');
console.log(' --height <number> PNG viewport height');
console.log(' --scale <number> PNG device scale factor (default: 2)');
console.log(' --background <color> PNG background (default: white)');
console.log(' --json Output JSON AST only (default)');
console.log(' --help, -h Show this help');
console.log('');
console.log('Examples:');
console.log(' penframe input.pf # Output JSON AST');
console.log(' penframe input.pf --svg output.svg # Generate SVG');
console.log(' penframe input.pf --png output.png # Generate PNG');
console.log(' penframe input.pf --png output.png --width 800 --height 600 --scale 3');
process.exit(args.includes('--help') || args.includes('-h') ? 0 : 1);
}
const absolutePath = path.resolve(filePath);
if (!fs.existsSync(absolutePath)) {
console.error(`Error: File not found at ${absolutePath}`);
process.exit(1);
}
// Parse command line options
const svgIndex = args.indexOf('--svg');
const pngIndex = args.indexOf('--png');
const widthIndex = args.indexOf('--width');
const heightIndex = args.indexOf('--height');
const scaleIndex = args.indexOf('--scale');
const backgroundIndex = args.indexOf('--background');
const svgOutput = svgIndex >= 0 ? args[svgIndex + 1] : null;
const pngOutput = pngIndex >= 0 ? args[pngIndex + 1] : null;
const pngOptions = {};
if (widthIndex >= 0) pngOptions.width = parseInt(args[widthIndex + 1]);
if (heightIndex >= 0) pngOptions.height = parseInt(args[heightIndex + 1]);
if (scaleIndex >= 0) pngOptions.deviceScaleFactor = parseFloat(args[scaleIndex + 1]);
if (backgroundIndex >= 0) pngOptions.background = args[backgroundIndex + 1];
try {
const content = fs.readFileSync(absolutePath, 'utf8');
const ast = parser.parse(content);
// Generate outputs based on options
if (svgOutput) {
const svgContent = astToSvg(ast);
fs.writeFileSync(svgOutput, svgContent);
console.log(`✓ SVG saved to: ${svgOutput}`);
}
if (pngOutput) {
console.log(`Converting to PNG using Puppeteer...`);
await astToPngFile(ast, pngOutput, pngOptions);
console.log(`✓ PNG saved to: ${pngOutput}`);
const stats = fs.statSync(pngOutput);
console.log(`File size: ${(stats.size / 1024).toFixed(1)} KB`);
}
// Default: output JSON AST if no other output specified
if (!svgOutput && !pngOutput) {
console.log(JSON.stringify(ast, null, 2));
}
} catch (error) {
if (error.name === 'SyntaxError') {
console.error(`Syntax Error in ${absolutePath}:`);
console.error(`Line ${error.location.start.line}, Column ${error.location.start.column}`);
console.error(error.message);
} else {
console.error('An unexpected error occurred:', error.message);
}
process.exit(1);
}
};
main().catch(error => {
console.error('Unexpected error:', error);
process.exit(1);
});