UNPKG

wgsl-plus

Version:

A WGSL preprocessor, prettifier, minifier, obfuscator, and compiler with C-style macros, conditional compilation, file linking, and multi-format output for WebGPU shaders.

160 lines (159 loc) 7.28 kB
#!/usr/bin/env node "use strict"; 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 }); const commander_1 = require("commander"); const fs = __importStar(require("fs")); const path = __importStar(require("path")); const prettify_1 = __importDefault(require("./tools/prettify")); const minify_1 = __importDefault(require("./tools/minify")); const obfuscate_1 = __importDefault(require("./tools/obfuscation/obfuscate")); const link_1 = __importDefault(require("./tools/link")); const generate_output_1 = __importDefault(require("./tools/generate-output")); const preprocess_wgsl_1 = __importDefault(require("./tools/preprocessing/preprocess-wgsl")); const VERSION = '1.0.1'; /** * Removes #binding directives from WGSL code. * @param code The WGSL source code as a string. * @returns The code with all #binding directives removed. */ function removeBindingDirectives(code) { // Split the code into lines const lines = code.split('\n'); // Filter out lines that match the #binding directive pattern const filteredLines = lines.filter(line => !/^\s*#binding\s+"[^"]+"\s*(\/\/.*)?$/.test(line) && !/^\s*#entrypoint\s+"[^"]+"\s*(\/\/.*)?$/.test(line)); // Rejoin the remaining lines return filteredLines.join('\n'); } // CLI setup commander_1.program .name('wgsl-plus') .description('A WGSL compiler with linking and multi-format output') .version(VERSION) .arguments('<importFiles...>') .requiredOption('-o, --output <path>', 'Specify the output file path') .option('-t, --export-type <type>', 'Export type for .js outputs (esm or commonjs)') .option('-b, --obfuscate', 'Obfuscate variable names in the output') .option('-m, --minify', 'Minify the output') .option('-p, --prettify', 'Prettify the output') .action((importFiles, options) => { try { let outputPath = ""; { // Validation // Validate import files for (const file of importFiles) { if (!fs.existsSync(file)) { throw new Error(`Import file not found: ${file}`); } if (path.extname(file) !== '.wgsl') { throw new Error(`Import file must be .wgsl: ${file}`); } } // Validate output file outputPath = path.resolve(options.output); const outputExt = path.extname(outputPath); const importPaths = importFiles.map(file => path.resolve(file)); if (importPaths.includes(outputPath)) { throw new Error(`Output file cannot be one of the import files: ${options.output}`); } if (!['.wgsl', '.js', '.ts'].includes(outputExt)) { throw new Error(`Output file must be .wgsl, .js, or .ts: ${options.output}`); } // Validate export-type flag if (outputExt === '.js') { if (!options.exportType) { // Default to ESM. options.exportType = 'esm'; } if (!['esm', 'commonjs'].includes(options.exportType)) { throw new Error(`Invalid export type: ${options.exportType}. Must be 'esm' or 'commonjs'`); } } else { if (options.exportType) { throw new Error('Export type should not be specified for non-js outputs'); } } // Make sure only one of --obfuscate, --minify, or --prettify is used const transformFlags = ['obfuscate', 'minify', 'prettify']; const usedTransformFlags = transformFlags.filter(flag => options[flag]); if (usedTransformFlags.length > 1) { throw new Error(`Only one of ${transformFlags.join(', ')} can be used`); } } let outputContent = ""; { // Process all import files outputContent = (0, link_1.default)(importFiles); // Handle define statements. outputContent = (0, preprocess_wgsl_1.default)(outputContent); // Remove the binding directives if obfuscate mode isn't being used. if (!options.obfuscate) outputContent = removeBindingDirectives(outputContent); if (options.prettify) outputContent = (0, prettify_1.default)(outputContent); else if (options.minify) outputContent = (0, minify_1.default)(outputContent); else if (options.obfuscate) outputContent = (0, obfuscate_1.default)(outputContent); } { // Generate and write output const finalOutput = (0, generate_output_1.default)(options.output, outputContent, options.exportType); const outputDir = path.dirname(outputPath); fs.mkdirSync(outputDir, { recursive: true }); fs.writeFileSync(outputPath, finalOutput); } } catch (error) { console.error(`Error: ${error.message}`); process.exit(1); } }); // Additional help text commander_1.program.on('--help', () => { console.log('\nExamples:'); console.log(' npx wgsl-plus input.wgsl -o output.wgsl'); console.log(' npx wgsl-plus a.wgsl b.wgsl -o output.js --export-type esm'); console.log(' npx wgsl-plus input.wgsl -o output.wgsl --obfuscate'); console.log('\nNotes:'); console.log(' • Input files must be .wgsl files.'); console.log(' • Output file must be .wgsl, .js, or .ts.'); console.log(' • --export-type is optional for .js outputs. Use commonjs or esm. Default is esm.'); console.log(' • Use one or none of --obfuscate, --prettify, or --minify to transform output.'); }); commander_1.program.parse();