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.

77 lines (66 loc) 3.02 kB
import Token from "../tokenization/token"; import tokenizeWgsl from "../tokenization/tokenize-wgsl"; // Main minification function export default function minify(code: string): string { // Use the comprehensive tokenizer from the obfuscator const tokens = tokenizeWgsl(code).filter(token => token.type !== 'comment'); let output = ''; // First pass: identify struct definitions to remove trailing semicolons // Looking for pattern: struct [identifier] { ... }; const skipIndices = new Set(); // Find struct definitions and mark their trailing semicolons for removal for (let i = 0; i < tokens.length - 2; i++) { // Find struct keyword if (tokens[i].type === 'keyword' && tokens[i].value === 'struct') { // Look for the closing pattern: }; (closing brace followed by semicolon) for (let j = i + 3; j < tokens.length - 1; j++) { if (tokens[j].type === 'operator' && tokens[j].value === '}' && tokens[j+1].type === 'operator' && tokens[j+1].value === ';') { // Mark the semicolon for removal skipIndices.add(j+1); break; } } } } // Reconstruct the code, inserting spaces where necessary for (let i = 0; i < tokens.length; i++) { // Skip tokens marked for removal if (skipIndices.has(i)) { continue; } // Check if a space is needed before the current token if (i > 0) { const t1 = tokens[i - 1]; const t2 = tokens[i]; if (needsSpace(t1, t2)) { output += ' '; } } // Append the token's value output += tokens[i].value; } return output; } // Helper function to check if a token is identifier-like (identifier, keyword, or builtin) function isIdentifierLike(token: Token): boolean { return token.type === 'identifier' || token.type === 'keyword' || token.type === 'builtin'; } // Helper function to check if two tokens need a space between them function needsSpace(t1: Token, t2: Token): boolean { // Between identifier-like tokens or between identifier-like and number if ((isIdentifierLike(t1) && isIdentifierLike(t2)) || (isIdentifierLike(t1) && t2.type === 'number')) { return true; } // Special case for attributes: // Add space after standalone attributes (like @fragment) before keywords/identifiers // But don't add space after attributes with parameters (like @location(0)) if (t1.type === 'attribute' && isIdentifierLike(t2)) { // Check if the attribute has parameters (contains opening parenthesis) const hasParameters = t1.value.includes('('); // Only add space for standalone attributes without parameters return !hasParameters; } return false; }