diff --git a/src/minifier.ts b/src/minifier.ts index bfaee76..b90d56e 100644 --- a/src/minifier.ts +++ b/src/minifier.ts @@ -14,7 +14,7 @@ export interface MinifyOptions { const isWord = RegExp.prototype.test.bind(/^\w/) const isSymbol = RegExp.prototype.test.bind(/[^\w\\]/) const isName = RegExp.prototype.test.bind(/^[_A-Za-z]/) -const isStorage = RegExp.prototype.test.bind(/^(uniform|in|out|attribute|varying)$/) +const isStorage = RegExp.prototype.test.bind(/^(@|layout|uniform|in|out|attribute|varying)$/) /** * Minifies a string of GLSL or WGSL code. @@ -28,18 +28,22 @@ export function minify( const tokens: Token[] = tokenize(code).filter((token) => token.type !== 'whitespace' && token.type !== 'comment') - let mangleIndex: number = 0 - let blockIndex: number | null = null + let mangleIndex: number = -1 + let lineIndex: number = -1 + let blockIndex: number = -1 let minified: string = '' for (let i = 0; i < tokens.length; i++) { const token = tokens[i] - // Pad alphanumeric tokens - if (isWord(token.value) && isWord(tokens[i - 1]?.value)) minified += ' ' + // Track newlines' offsets + if (/[;{}\\]|^fn$/.test(token.value)) lineIndex = i + 1 // Mark enter/leave block-scope if (token.value === '{' && isName(tokens[i - 1]?.value)) blockIndex = i - 1 - else if (token.value === '}') blockIndex = null + else if (token.value === '}') blockIndex = -1 + + // Pad alphanumeric tokens + if (isWord(token.value) && isWord(tokens[i - 1]?.value)) minified += ' ' // Pad symbols around #define and three.js #include (white-space sensitive) if ( @@ -53,11 +57,11 @@ export function minify( if ( token.type === 'identifier' && // Skip shader externals when disabled - (mangleExternals || (!isStorage(tokens[i - 1]?.value) && !isStorage(tokens[i - 2]?.value))) && + (mangleExternals || !isStorage(tokens[lineIndex]?.value) || isWord(tokens[i + 1]?.value)) && // Is reference, declaration, namespace, or comma-separated list (mangleMap.has(token.value) || // Skip struct properties - (blockIndex == null && + (blockIndex === -1 && (isName(tokens[i - 1]?.value) || // uniform Type { ... } name; (tokens[i - 1]?.value === '}' && tokens[i + 1]?.value === ';') || diff --git a/tests/__snapshots__/index.test.ts.snap b/tests/__snapshots__/index.test.ts.snap index 987c587..12f9bb3 100644 --- a/tests/__snapshots__/index.test.ts.snap +++ b/tests/__snapshots__/index.test.ts.snap @@ -26,22 +26,21 @@ Map { } `; -exports[`minify > can mangle WGSL 1`] = `"struct a{intensity:f32,position:vec3,one:f32,two:f32,};struct b{projectionMatrix:mat4x4,modelViewMatrix:mat4x4,normalMatrix:mat3x3,one:f32,two:f32,lights:array,};@binding(0)@group(0)varuniforms:b;@binding(1)@group(0)var sample:sampler;@binding(2)@group(0)var c:texture_2d;struct d{@location(0)position:vec4,@location(1)uv:vec2,};struct e{@builtin(position)position:vec4,@location(0)uv:vec2,};@vertex fn f(g:d)->e{var output:e;output.position=g.position;output.uv=g.uv;return output;}@fragment fn h(i:vec2)->vec4{var j=vec4(uniforms.lights[0].position*uniforms.lights[0].intensity,0.0);var k=uniforms.projectionMatrix*uniforms.modelViewMatrix*vec4(0.0,0.0,0.0,1.0);var l=textureSample(c,sample,i);l.a+=1.0;return l;}"`; +exports[`minify > can mangle WGSL 1`] = `"struct a{intensity:f32,position:vec3,one:f32,two:f32,};struct b{projectionMatrix:mat4x4,modelViewMatrix:mat4x4,normalMatrix:mat3x3,one:f32,two:f32,lights:array,};@binding(0)@group(0)varuniforms:Uniforms;@binding(1)@group(0)var sample:sampler;@binding(2)@group(0)var map:texture_2d;struct c{@location(0)position:vec4,@location(1)uv:vec2,};struct d{@builtin(position)position:vec4,@location(0)uv:vec2,};@vertex fn e(f:c)->d{var output:d;output.position=f.position;output.uv=f.uv;return output;}@fragment fn g(h:vec2)->vec4{var i=vec4(uniforms.lights[0].position*uniforms.lights[0].intensity,0.0);var j=uniforms.projectionMatrix*uniforms.modelViewMatrix*vec4(0.0,0.0,0.0,1.0);var k=textureSample(map,sample,h);k.a+=1.0;return k;}"`; exports[`minify > can mangle WGSL 2`] = ` Map { "LightData" => "a", "Uniforms" => "b", - "map" => "c", - "VertexIn" => "d", - "VertexOut" => "e", - "vert_main" => "f", - "input" => "g", - "frag_main" => "h", - "uv" => "i", - "lightNormal" => "j", - "clipPosition" => "k", - "color" => "l", + "VertexIn" => "c", + "VertexOut" => "d", + "vert_main" => "e", + "input" => "f", + "frag_main" => "g", + "uv" => "h", + "lightNormal" => "i", + "clipPosition" => "j", + "color" => "k", } `;