Skip to content

Commit 75006c2

Browse files
committed
feat: add remove comments option #2331
1 parent 4f52c49 commit 75006c2

2 files changed

Lines changed: 125 additions & 0 deletions

File tree

index.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,9 @@ <h2>Options</h2>
197197
<br>
198198
<input class="checkbox" type="checkbox" id="indent-empty-lines">
199199
<label for="indent-empty-lines">Keep indentation on empty lines?</label>
200+
<br>
201+
<input class="checkbox" type="checkbox" id="remove-comments">
202+
<label for="remove-comments">Remove comments?</label>
200203
<br><a href="?without-codemirror" class="turn-off-codemirror">Use a simple textarea for code input?</a>
201204
</div>
202205

web/common-function.js

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

9192
function 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+
269391
function mergeObjects(allOptions, additionalOptions) {
270392
var finalOpts = {};
271393
var name;

0 commit comments

Comments
 (0)