@@ -86,6 +86,7 @@ function read_settings_from_cookie() {
8686 $ ( '#e4x' ) . prop ( 'checked' , Cookies . get ( 'e4x' ) === 'on' ) ;
8787 $ ( '#language' ) . val ( any ( Cookies . get ( 'language' ) , 'js' ) ) ;
8888 $ ( '#indent-empty-lines' ) . prop ( 'checked' , Cookies . get ( 'indent-empty-lines' ) === 'on' ) ;
89+ $ ( '#remove-comments' ) . prop ( 'checked' , Cookies . get ( 'remove-comments' ) === 'on' ) ;
8990}
9091
9192function store_settings_to_cookie ( ) {
@@ -112,6 +113,7 @@ function store_settings_to_cookie() {
112113 Cookies . set ( 'e4x' , $ ( '#e4x' ) . prop ( 'checked' ) ? 'on' : 'off' , opts ) ;
113114 Cookies . set ( 'language' , $ ( '#language' ) . val ( ) , opts ) ;
114115 Cookies . set ( 'indent-empty-lines' , $ ( '#indent-empty-lines' ) . prop ( 'checked' ) ? 'on' : 'off' , opts ) ;
116+ Cookies . set ( 'remove-comments' , $ ( '#remove-comments' ) . prop ( 'checked' ) ? 'on' : 'off' , opts ) ;
115117
116118}
117119
@@ -251,6 +253,10 @@ function beautify() {
251253 output = the . beautifier . js ( source , opts ) ;
252254 }
253255
256+ if ( $ ( '#remove-comments' ) . prop ( 'checked' ) ) {
257+ output = remove_comments ( output , language ) ;
258+ }
259+
254260 if ( the . editor ) {
255261 the . editor . setValue ( output ) ;
256262 } else {
@@ -266,6 +272,122 @@ function beautify() {
266272 the . beautify_in_progress = false ;
267273}
268274
275+ function remove_comments ( source , language ) {
276+ if ( language === 'html' ) {
277+ // Scan character-by-character to find <!-- ... --> comment markers.
278+ // This correctly handles multiline comments, inline comments, and CRLF line endings.
279+ var htmlResult = '' ;
280+ var hi = 0 ;
281+ var hlen = source . length ;
282+
283+ while ( hi < hlen ) {
284+ // Detect comment open: <!--
285+ if ( source [ hi ] === '<' && hi + 3 < hlen &&
286+ source [ hi + 1 ] === '!' && source [ hi + 2 ] === '-' && source [ hi + 3 ] === '-' ) {
287+ var hend = source . indexOf ( '-->' , hi + 4 ) ;
288+ if ( hend === - 1 ) {
289+ hi = hlen ; // unterminated comment — drop the rest
290+ } else {
291+ hi = hend + 3 ; // skip past '-->'
292+ }
293+ continue ;
294+ }
295+ htmlResult += source [ hi ] ;
296+ hi ++ ;
297+ }
298+
299+ // Remove lines that are blank or whitespace-only after comment removal.
300+ // Also trim trailing whitespace left on lines where an inline comment was removed.
301+ // Handle both LF (\n) and CRLF (\r\n) line endings.
302+ return htmlResult
303+ . replace ( / [ \t ] + ( \r ? \n ) / g, '$1' ) // strip trailing whitespace before line endings
304+ . replace ( / ^ [ \t ] * \r ? \n / gm, '' ) ; // remove now-blank lines
305+ }
306+
307+ // For JS and CSS: strip /* ... */ block comments and (JS-only) // line comments
308+ // while preserving string literals and regex literals.
309+ var result = '' ;
310+ var i = 0 ;
311+ var len = source . length ;
312+
313+ while ( i < len ) {
314+ var ch = source [ i ] ;
315+
316+ // Single-quoted string
317+ if ( ch === "'" ) {
318+ var j = i + 1 ;
319+ while ( j < len ) {
320+ if ( source [ j ] === '\\' ) { j += 2 ; continue ; }
321+ if ( source [ j ] === "'" ) { j ++ ; break ; }
322+ j ++ ;
323+ }
324+ result += source . slice ( i , j ) ;
325+ i = j ;
326+ continue ;
327+ }
328+
329+ // Double-quoted string
330+ if ( ch === '"' ) {
331+ var k = i + 1 ;
332+ while ( k < len ) {
333+ if ( source [ k ] === '\\' ) { k += 2 ; continue ; }
334+ if ( source [ k ] === '"' ) { k ++ ; break ; }
335+ k ++ ;
336+ }
337+ result += source . slice ( i , k ) ;
338+ i = k ;
339+ continue ;
340+ }
341+
342+ // Template literal
343+ if ( ch === '`' ) {
344+ var m = i + 1 ;
345+ while ( m < len ) {
346+ if ( source [ m ] === '\\' ) { m += 2 ; continue ; }
347+ if ( source [ m ] === '`' ) { m ++ ; break ; }
348+ m ++ ;
349+ }
350+ result += source . slice ( i , m ) ;
351+ i = m ;
352+ continue ;
353+ }
354+
355+ // Possible comment start
356+ if ( ch === '/' && i + 1 < len ) {
357+ var next = source [ i + 1 ] ;
358+
359+ // Block comment /* ... */
360+ if ( next === '*' ) {
361+ var end = source . indexOf ( '*/' , i + 2 ) ;
362+ if ( end === - 1 ) {
363+ // Unterminated block comment — drop the rest
364+ i = len ;
365+ } else {
366+ i = end + 2 ;
367+ }
368+ continue ;
369+ }
370+
371+ // Line comment // ... (JS only, not CSS)
372+ if ( next === '/' && language !== 'css' ) {
373+ var nl = source . indexOf ( '\n' , i + 2 ) ;
374+ if ( nl === - 1 ) {
375+ i = len ;
376+ } else {
377+ i = nl ; // keep the newline itself
378+ }
379+ continue ;
380+ }
381+ }
382+
383+ result += ch ;
384+ i ++ ;
385+ }
386+
387+ // Remove lines that are now blank (only whitespace) after comment removal
388+ return result . replace ( / ^ [ \t ] * \n / gm, '' ) ;
389+ }
390+
269391function mergeObjects ( allOptions , additionalOptions ) {
270392 var finalOpts = { } ;
271393 var name ;
0 commit comments