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
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 });
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();
;