<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Saurabh Choudhary</title>
    <description>The latest articles on DEV Community by Saurabh Choudhary (@saurabhzaiswal).</description>
    <link>https://dev.to/saurabhzaiswal</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3965731%2F92f14392-09df-4c4f-8e72-e770c5ed2397.jpg</url>
      <title>DEV Community: Saurabh Choudhary</title>
      <link>https://dev.to/saurabhzaiswal</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/saurabhzaiswal"/>
    <language>en</language>
    <item>
      <title>Built Log Stripper: A VS Code Extension to Remove Debug Logs Across 23+ Languages</title>
      <dc:creator>Saurabh Choudhary</dc:creator>
      <pubDate>Wed, 03 Jun 2026 07:36:42 +0000</pubDate>
      <link>https://dev.to/saurabhzaiswal/built-log-stripper-a-vs-code-extension-to-remove-debug-logs-across-23-languages-g9h</link>
      <guid>https://dev.to/saurabhzaiswal/built-log-stripper-a-vs-code-extension-to-remove-debug-logs-across-23-languages-g9h</guid>
      <description>&lt;p&gt;Every developer has a version of this story.&lt;/p&gt;

&lt;p&gt;You're about to open a pull request. The code works. The tests pass. Everything looks good.&lt;/p&gt;

&lt;p&gt;Then you do one final scan and find this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;HERE&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;final:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then, before the PR:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Search → Delete. Search → Delete. Search → Delete.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I got tired of it. So I built a tool to automate it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Log Stripper?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Log Stripper&lt;/strong&gt; is a VS Code extension that removes debug, log, and print statements from &lt;strong&gt;23+ programming languages&lt;/strong&gt; - with a preview so you always see what will be deleted before anything changes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcboyc43q1b3yqlllnv9i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcboyc43q1b3yqlllnv9i.png" alt="Log Stripper Icon" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🔗 &lt;a href="https://marketplace.visualstudio.com/items?itemName=saurabhchoudhary.log-stripper" rel="noopener noreferrer"&gt;VS Code Marketplace&lt;/a&gt;&lt;br&gt;
🔗 &lt;a href="https://github.com/saurabhzaiswal/Log-Stripper-VS-Code" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The Features
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;🔍 Preview mode&lt;/strong&gt; - &lt;code&gt;Ctrl+Shift+D&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Shows every line that will be removed. You confirm. Only then does anything change.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🎨 Highlight mode&lt;/strong&gt; - &lt;code&gt;Ctrl+Shift+H&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Marks debug lines in red. No file modification. Review first, strip later.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🌍  23+ languages&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;JS, TS, Python, Java, Go, Rust, C#, Swift, Kotlin, Dart, Ruby, PHP, C, C++, Shell, Lua, Scala, Elixir, Haskell, R, Vue, Svelte, JSX/TSX&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🏢 Workspace cleanup&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Strip debug statements from an entire project in one command.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why not just use grep/sed?
&lt;/h2&gt;

&lt;p&gt;You could. But:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No preview&lt;/li&gt;
&lt;li&gt;No multiline support&lt;/li&gt;
&lt;li&gt;No VS Code integration&lt;/li&gt;
&lt;li&gt;No safety rules&lt;/li&gt;
&lt;li&gt;Works differently on Windows vs Mac vs Linux
Log Stripper handles all of this inside VS Code with a consistent UX.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  The Interesting Technical Part: Multiline Removal
&lt;/h2&gt;

&lt;p&gt;Removing a single-line &lt;code&gt;console.log("x")&lt;/code&gt; is trivial. The interesting case is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;role:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;role&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To remove this correctly, you need to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Find the opening &lt;code&gt;(&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Track paren depth across lines&lt;/li&gt;
&lt;li&gt;Handle parens inside strings (don't count those)&lt;/li&gt;
&lt;li&gt;Find the exact closing &lt;code&gt;)&lt;/code&gt; and optional &lt;code&gt;;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Remove the entire block without touching surrounding code
Here's the core of &lt;code&gt;skipParenBlock&lt;/code&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;skipParenBlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;startLine&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;openIdx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;startLine&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;bal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;li&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;startLine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ci&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;openIdx&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;inStr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;li&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;li&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ci&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;ci&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;inStr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ci&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;inStr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;inStr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;"&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;'&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;inStr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;bal&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;bal&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bal&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;ci&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;ci&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;ci&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;endLine&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;li&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;endCol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ci&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;ci&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;li&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;ci&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Architecture Decision
&lt;/h2&gt;

&lt;p&gt;I separated the core logic from the VS Code layer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/
├── extension.ts   ← VS Code commands, UI, workspace
└── stripper.ts    ← Pure logic, zero VS Code deps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why? Because &lt;code&gt;stripper.ts&lt;/code&gt; can be tested without launching a VS Code host:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node &lt;span class="nt"&gt;--test&lt;/span&gt; out-test/test/stripper.test.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;151 tests. Fast. No mocking needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Safety Rules
&lt;/h2&gt;

&lt;p&gt;The extension will &lt;strong&gt;never&lt;/strong&gt; remove:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// console.log("commented") ← comment line, always kept&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;       &lt;span class="err"&gt;←&lt;/span&gt; &lt;span class="nx"&gt;inline&lt;/span&gt; &lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;always&lt;/span&gt; &lt;span class="nx"&gt;kept&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;doThing&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fallback&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="err"&gt;←&lt;/span&gt; &lt;span class="nx"&gt;inline&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;kept&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Only whole-statement debug calls that are the entire line (after indentation) are removed.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Languages Covered
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Language&lt;/th&gt;
&lt;th&gt;Examples&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;JS/TS&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;console.log&lt;/code&gt;, &lt;code&gt;debugger&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Python&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;print()&lt;/code&gt;, &lt;code&gt;logging.debug()&lt;/code&gt;, &lt;code&gt;breakpoint()&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Java&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;System.out.println&lt;/code&gt;, &lt;code&gt;logger.debug()&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Go&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;fmt.Println&lt;/code&gt;, &lt;code&gt;log.Fatal&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rust&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;println!&lt;/code&gt;, &lt;code&gt;dbg!&lt;/code&gt;, &lt;code&gt;eprintln!&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C#&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Console.WriteLine&lt;/code&gt;, &lt;code&gt;Debug.Write&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Swift&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;print()&lt;/code&gt;, &lt;code&gt;NSLog()&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ruby&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;puts&lt;/code&gt;, &lt;code&gt;binding.pry&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PHP&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;var_dump()&lt;/code&gt;, &lt;code&gt;dd()&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shell&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;echo&lt;/code&gt;, &lt;code&gt;printf&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;...13 more&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Try It
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install from Marketplace&lt;/span&gt;
code &lt;span class="nt"&gt;--install-extension&lt;/span&gt; saurabhchoudhary.log-stripper
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or search "Log Stripper" in the VS Code extensions panel.&lt;/p&gt;

&lt;p&gt;Open a file with debug statements → &lt;code&gt;Ctrl+Shift+D&lt;/code&gt; → see the preview → confirm.&lt;/p&gt;




&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;Toggle Debug Highlights | Highlight/unhighlight debug lines&lt;/code&gt;&lt;/strong&gt;
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhgrpgwbxhy3us1132fx5.png" alt="Toggle Debug Highlights | Highlight/unhighlight debug lines" width="800" height="410"&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;Preview &amp;amp; Strip Current File | Shows preview, then strips on confirm&lt;/code&gt;&lt;/strong&gt;
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvprhyo035tbopzpi6qp2.png" alt="Preview &amp;amp; Strip Current File | Shows preview, then strips on confirm" width="800" height="425"&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;Command Palette | Strip Entire Workspace | Clean whole project&lt;/code&gt;&lt;/strong&gt;
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5ulbtysszpopdgwx0qn5.png" alt="Command Palette | Strip Entire Workspace | Clean whole project" width="799" height="424"&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;Right-click → menu | Strip Current File | Strip without preview&lt;/code&gt;&lt;/strong&gt;
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr3n9kak7vn3m9eo6bogp.png" alt="Right-click → menu | Strip Current File | Strip without preview" width="800" height="450"&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;Editor toolbar icons (eye / eye-closed / trash)&lt;/code&gt;&lt;/strong&gt;
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkiai3594p78j7f12qpt9.png" alt="Editor toolbar icons (eye / eye-closed / trash)" width="800" height="425"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Built this because I couldn't find a tool that did all of this properly. Turned out to be one of the most satisfying weekend projects I've done.&lt;/p&gt;

&lt;p&gt;If you try it, I'd love feedback in the comments or as a GitHub issue. 🙌&lt;/p&gt;

&lt;p&gt;&lt;em&gt;By Saurabh Choudhary - Software Engineer&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Every developer has a version of this story.&lt;/p&gt;

&lt;p&gt;You're about to open a pull request. The code works. The tests pass. You're ready. Then you do one last scroll through the file and see it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;HERE&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user data:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userData&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;response&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three debug logs you forgot to remove. You delete them, re-run the linter, and open the PR.&lt;/p&gt;

&lt;p&gt;Two weeks later, someone reports that production logs are noisy with debug output. A developer on your team had left a &lt;code&gt;logger.debug()&lt;/code&gt; in a hot path. Nobody caught it in review.&lt;/p&gt;

&lt;p&gt;This isn't a rare occurrence. It's a pattern that plays out in every team, on every codebase, in every programming language.&lt;/p&gt;

&lt;p&gt;I've experienced it across JavaScript, TypeScript, PHP, Go, Python, Vue.js, NestJS, Laravel, and Angular projects. Different languages, different ecosystems - same repetitive problem.&lt;/p&gt;

&lt;p&gt;Eventually I stopped accepting it as "just part of the workflow" and decided to build a proper solution.&lt;/p&gt;

&lt;p&gt;That solution is &lt;strong&gt;Log Stripper&lt;/strong&gt; - a VS Code extension that removes debug, log, and print statements from 23+ programming languages with a safety-first, preview-driven approach.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;The problem has two dimensions that are easy to underestimate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;First: it's repetitive.&lt;/strong&gt; Before every commit, before every PR, before every release, developers go through the same manual process of searching for and deleting debug statements. On large codebases with dozens of files touched in a single feature branch, this becomes genuinely time-consuming.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Second: it's error-prone.&lt;/strong&gt; Humans miss things. A &lt;code&gt;console.log&lt;/code&gt; inside a nested callback, a &lt;code&gt;print()&lt;/code&gt; inside a conditional branch, a &lt;code&gt;System.out.println&lt;/code&gt; buried in a Java service - these are easy to overlook when scanning files manually. And when they slip through, they end up in production.&lt;/p&gt;

&lt;p&gt;There's also a subtler issue: developers working under time pressure will rush the cleanup. The more pressure, the more likely something gets missed.&lt;/p&gt;

&lt;p&gt;This is exactly the kind of task that should be automated. It is deterministic, repetitive, and rule-based. A computer should do it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Existing Workflows Were Frustrating
&lt;/h2&gt;

&lt;p&gt;Before building Log Stripper, I searched for existing solutions.&lt;/p&gt;

&lt;p&gt;I found a few extensions that handled &lt;code&gt;console.log&lt;/code&gt; removal for JavaScript. Some worked well for that specific case. But they had significant limitations:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Language coverage was narrow.&lt;/strong&gt; Most extensions focused exclusively on JavaScript. If you wrote Python, Go, Java, or Rust, you were on your own.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No preview mode.&lt;/strong&gt; Several extensions deleted statements immediately without showing you what would be removed. That's unsafe. A developer who accidentally removes a legitimate logger call in production code will stop trusting the tool immediately.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No highlight mode.&lt;/strong&gt; Sometimes I want to &lt;em&gt;see&lt;/em&gt; the debug statements in a file without removing anything yet. I want to review them, understand them, decide manually. None of the tools I found offered non-destructive inspection.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No workspace cleanup.&lt;/strong&gt; File-by-file cleanup doesn't scale. Before a major release, I want to scan an entire project and clean everything in one pass.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Unreliable multiline handling.&lt;/strong&gt; A &lt;code&gt;console.log&lt;/code&gt; that spans multiple lines is common:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;processing user:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Many tools would only remove the first line and leave the rest, creating syntax errors.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why I Built Log Stripper
&lt;/h2&gt;

&lt;p&gt;The decision to build rather than adapt came down to one realization: the problem deserved a proper solution, not a workaround.&lt;/p&gt;

&lt;p&gt;I wanted an extension that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Worked across every major language I use day-to-day&lt;/li&gt;
&lt;li&gt;Showed a preview before making any changes&lt;/li&gt;
&lt;li&gt;Could highlight debug lines without modifying files&lt;/li&gt;
&lt;li&gt;Could clean an entire workspace safely&lt;/li&gt;
&lt;li&gt;Was smart enough to never break code it shouldn't touch&lt;/li&gt;
&lt;li&gt;Was backed by automated tests
None of those requirements are unreasonable. Together, they're the minimum bar for a tool I'd actually trust.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The weekend I started building it, I intended it to be a one-day project. It grew into something more substantial as I realized the edge cases, the safety requirements, and the value of doing it properly.&lt;/p&gt;




&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;

&lt;p&gt;The most important architectural decision I made was separating the core logic from the VS Code integration layer.&lt;/p&gt;

&lt;p&gt;The repository has two source files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/
├── extension.ts    ← VS Code commands, UI, workspace operations
└── stripper.ts     ← Core strip logic (zero VS Code dependencies)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;stripper.ts&lt;/code&gt; has no awareness of VS Code. It takes a string of text and a language ID, and returns a new string with debug statements removed plus metadata about what was changed. That's it.&lt;/p&gt;

&lt;p&gt;This separation has two major benefits:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Testability.&lt;/strong&gt; I can test the core logic without launching a VS Code Extension Development Host. The 151 automated tests run with a plain &lt;code&gt;node --test&lt;/code&gt; command. Fast, simple, reliable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Maintainability.&lt;/strong&gt; If VS Code changes its API, or if I want to port the logic to a CLI tool or a git pre-commit hook, the core logic doesn't need to change.&lt;/p&gt;

&lt;p&gt;The VS Code layer handles everything user-facing: commands, keybindings, settings, decorations, progress notifications, and workspace file scanning.&lt;/p&gt;




&lt;h2&gt;
  
  
  Multi-Language Support
&lt;/h2&gt;

&lt;p&gt;Supporting 23 languages sounds ambitious. The implementation is actually straightforward once you have the right architecture.&lt;/p&gt;

&lt;p&gt;Each language is a key in the &lt;code&gt;LANGUAGE_PATTERNS&lt;/code&gt; object, and its value is an array of regular expressions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;LANGUAGE_PATTERNS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;RegExp&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;javascript&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="sr"&gt;/^&lt;/span&gt;&lt;span class="se"&gt;(\s&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;console&lt;/span&gt;&lt;span class="se"&gt;\.(&lt;/span&gt;&lt;span class="sr"&gt;log|debug|info|warn|error|trace|...&lt;/span&gt;&lt;span class="se"&gt;)\s&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sr"&gt;/^&lt;/span&gt;&lt;span class="se"&gt;(\s&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;debugger&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;*;&lt;/span&gt;&lt;span class="se"&gt;?&lt;/span&gt;&lt;span class="sr"&gt;$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;python&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="sr"&gt;/^&lt;/span&gt;&lt;span class="se"&gt;(\s&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;print&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sr"&gt;/^&lt;/span&gt;&lt;span class="se"&gt;(\s&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;logging&lt;/span&gt;&lt;span class="se"&gt;\.(&lt;/span&gt;&lt;span class="sr"&gt;debug|info|warning|error|critical&lt;/span&gt;&lt;span class="se"&gt;)\s&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sr"&gt;/^&lt;/span&gt;&lt;span class="se"&gt;(\s&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt;breakpoint&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;\(\s&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt;&lt;span class="se"&gt;\)&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="c1"&gt;// ... 21 more languages&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Language aliases handle cases where VS Code's language ID differs from the pattern group:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;LANG_ALIASES&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;svelte&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;javascript&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vue-html&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;typescriptreact&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;typescript&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the extension receives a file, it looks up the language ID, finds the pattern list, and applies each pattern against every line. If no patterns are found for a language, the file is returned unchanged.&lt;/p&gt;

&lt;p&gt;Adding a new language is a matter of adding one entry to &lt;code&gt;LANGUAGE_PATTERNS&lt;/code&gt; and a set of test cases to &lt;code&gt;stripper.test.ts&lt;/code&gt;. The infrastructure handles the rest.&lt;/p&gt;




&lt;h2&gt;
  
  
  Preview Mode
&lt;/h2&gt;

&lt;p&gt;The preview mode was the feature I was most deliberate about designing.&lt;/p&gt;

&lt;p&gt;When a developer triggers "Preview &amp;amp; Strip" with &lt;code&gt;Ctrl+Shift+D&lt;/code&gt;, the extension:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Runs the stripping logic internally (without modifying the file)&lt;/li&gt;
&lt;li&gt;Collects the list of lines that would be removed&lt;/li&gt;
&lt;li&gt;Shows a modal dialog listing those lines with their line numbers&lt;/li&gt;
&lt;li&gt;Waits for explicit confirmation before making any changes
This turns a potentially destructive operation into a fully transparent, opt-in action. The developer sees exactly what will happen and retains full control.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The modal includes the first 20 matching lines and appends "...and N more" if there are additional matches. This keeps the dialog readable on files with heavy debug coverage.&lt;/p&gt;

&lt;p&gt;If the developer cancels, nothing changes. Not a single character in the file is modified.&lt;/p&gt;




&lt;h2&gt;
  
  
  Highlight Mode
&lt;/h2&gt;

&lt;p&gt;Highlight mode solves a different need: &lt;em&gt;I want to see the debug statements but I'm not ready to remove them yet.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When the developer presses &lt;code&gt;Ctrl+Shift+H&lt;/code&gt;, the extension:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Finds all lines matching debug patterns using &lt;code&gt;findDebugLineIndices()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Applies a VS Code text decoration that highlights those lines in red&lt;/li&gt;
&lt;li&gt;Adds an inline annotation "← debug" at the end of each line
The file is not modified. This is purely a visual overlay.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Pressing &lt;code&gt;Ctrl+Shift+H&lt;/code&gt; again (or clicking the eye-closed icon in the toolbar) removes the highlights.&lt;/p&gt;

&lt;p&gt;The highlight controller also handles three lifecycle events automatically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When you &lt;strong&gt;strip the file&lt;/strong&gt;, highlights are cleared (no red lines on lines that no longer exist)&lt;/li&gt;
&lt;li&gt;When you &lt;strong&gt;edit the file&lt;/strong&gt; and &lt;code&gt;refreshHighlightsOnEdit&lt;/code&gt; is enabled, highlights recompute after a 120ms debounce&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  - When you &lt;strong&gt;switch tabs&lt;/strong&gt; and &lt;code&gt;clearHighlightsOnTabChange&lt;/code&gt; is enabled, highlights are cleared automatically
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Workspace Cleanup
&lt;/h2&gt;

&lt;p&gt;The workspace strip command scans every file in the project matching the supported language extensions and strips debug statements from each one.&lt;/p&gt;

&lt;p&gt;The implementation uses VS Code's &lt;code&gt;workspace.findFiles()&lt;/code&gt; API with exclusion patterns to skip &lt;code&gt;node_modules&lt;/code&gt;, &lt;code&gt;dist&lt;/code&gt;, &lt;code&gt;.git&lt;/code&gt;, &lt;code&gt;vendor&lt;/code&gt;, &lt;code&gt;build&lt;/code&gt;, and &lt;code&gt;out&lt;/code&gt; by default. All exclusion patterns are configurable in settings.&lt;/p&gt;

&lt;p&gt;The operation runs with a progress notification showing the current file being processed and a cancellation option. After completion, a summary shows how many statements were removed across how many files.&lt;/p&gt;

&lt;p&gt;Because this modifies files on disk, the documentation explicitly recommends using version control. A git diff after the workspace strip is always informative.&lt;/p&gt;




&lt;h2&gt;
  
  
  Safety Design
&lt;/h2&gt;

&lt;p&gt;Safety was a first-class concern throughout the design.&lt;/p&gt;

&lt;p&gt;The extension enforces several rules to avoid breaking code it shouldn't touch:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rule 1: Whole-line only.&lt;/strong&gt; A debug call is only removed if it is the entire statement on the line (after indentation). This prevents removal of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;         &lt;span class="c1"&gt;// kept - inline with return&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;doWork&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fallback&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// kept - chained&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Rule 2: Comments are never touched.&lt;/strong&gt; Any line where the first non-whitespace characters form a comment prefix (&lt;code&gt;//&lt;/code&gt;, &lt;code&gt;#&lt;/code&gt;, &lt;code&gt;--&lt;/code&gt;, &lt;code&gt;/*&lt;/code&gt;, &lt;code&gt;*&lt;/code&gt;) is skipped entirely.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rule 3: Multiline paren balancing.&lt;/strong&gt; When a debug call spans multiple lines, the extension tracks open and close parentheses (accounting for parens inside strings) to identify the exact end of the statement. The closing &lt;code&gt;)&lt;/code&gt; and optional &lt;code&gt;;&lt;/code&gt; are consumed, and any remaining code on that final line is preserved.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rule 4: No modification on cancel.&lt;/strong&gt; Preview mode never touches the file unless the user explicitly confirms. The stripping logic runs on an in-memory copy of the text, and the result is only written back if the user says yes.&lt;/p&gt;




&lt;h2&gt;
  
  
  Testing Strategy
&lt;/h2&gt;

&lt;p&gt;I wanted the extension to be trustworthy. That required a proper test suite.&lt;/p&gt;

&lt;p&gt;The tests live in &lt;code&gt;test/stripper.test.ts&lt;/code&gt; and use Node's built-in test runner - no Jest, no Mocha, no additional dependencies. The test command is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;tsc &lt;span class="nt"&gt;-p&lt;/span&gt; tsconfig.test.json &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; node &lt;span class="nt"&gt;--test&lt;/span&gt; out-test/test/stripper.test.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The 151 test cases cover:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every language in &lt;code&gt;LANGUAGE_PATTERNS&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Simple single-line removal&lt;/li&gt;
&lt;li&gt;Multiline call removal with paren balancing&lt;/li&gt;
&lt;li&gt;Comment preservation&lt;/li&gt;
&lt;li&gt;Inline code preservation&lt;/li&gt;
&lt;li&gt;Real-world code samples (NestJS controllers, Python classes, Go functions)&lt;/li&gt;
&lt;li&gt;Language aliases (Vue, Svelte, JSX, TSX)&lt;/li&gt;
&lt;li&gt;Unknown languages (should be a no-op)&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;findDebugLineIndices()&lt;/code&gt; function (used by highlight mode)
Each test specifies the input code, the expected output, and the expected removal count. Any test that would cause the extension to modify code it shouldn't - or fail to modify code it should - is a failing test.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Writing tests before polishing features was the right decision. It caught several edge cases during development and gave me confidence when refactoring the paren-balancing logic.&lt;/p&gt;




&lt;h2&gt;
  
  
  Publishing to the VS Code Marketplace
&lt;/h2&gt;

&lt;p&gt;The Marketplace publishing process is simpler than I expected.&lt;/p&gt;

&lt;p&gt;The key steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a publisher account at &lt;code&gt;marketplace.visualstudio.com&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Generate a Personal Access Token from Azure DevOps with Marketplace → Manage scope&lt;/li&gt;
&lt;li&gt;Install &lt;code&gt;@vscode/vsce&lt;/code&gt; globally: &lt;code&gt;npm install -g @vscode/vsce&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;vsce package&lt;/code&gt; to create the &lt;code&gt;.vsix&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;vsce publish --pat TOKEN&lt;/code&gt; or upload the &lt;code&gt;.vsix&lt;/code&gt; manually via the publisher portal
The &lt;code&gt;.vscodeignore&lt;/code&gt; file controls what goes into the package. I excluded &lt;code&gt;src/&lt;/code&gt;, &lt;code&gt;test/&lt;/code&gt;, and &lt;code&gt;node_modules/&lt;/code&gt; - only the compiled &lt;code&gt;out/&lt;/code&gt; directory ships. This keeps the extension lightweight.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One thing I'd emphasize: set the &lt;code&gt;repository.url&lt;/code&gt; in &lt;code&gt;package.json&lt;/code&gt; before publishing. It shows up prominently on the Marketplace listing and signals to users that the extension is open source and maintainable.&lt;/p&gt;




&lt;h2&gt;
  
  
  Lessons Learned
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Separate your core logic from your integration layer.&lt;/strong&gt; This applies far beyond VS Code extensions. Any time you can isolate the testable business logic from the framework or platform code, do it. It makes everything easier.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Safety features build trust.&lt;/strong&gt; The preview mode and the "never remove inline code" rule weren't technically necessary for the extension to work. But they're what make a developer comfortable trusting the tool with real production code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test the edge cases first.&lt;/strong&gt; Multiline calls, strings containing parens, empty files, unsupported languages - these were the cases most likely to cause silent failures. Writing tests for them before the happy path forced me to build robust logic from the start.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ship before it's perfect.&lt;/strong&gt; The first version didn't have highlight mode. The workspace strip was added later. Shipping v1 with the core feature - preview and strip - got real feedback faster than spending another two weeks on features users might not need.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Small tools have real value.&lt;/strong&gt; This isn't a SaaS platform. It's not an AI product. It's a focused tool that does one thing well. Developer tools like this get used quietly but consistently. That's enough.&lt;/p&gt;




&lt;h2&gt;
  
  
  Future Improvements
&lt;/h2&gt;

&lt;p&gt;Several improvements are on the roadmap:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Custom pattern rules.&lt;/strong&gt; Allow developers to define their own patterns to remove. For teams using custom logging frameworks, this would make Log Stripper work with any codebase.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pre-commit hook integration.&lt;/strong&gt; A script or CLI wrapper that can run as a git pre-commit hook, catching debug statements before they ever reach a commit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Team-wide configuration.&lt;/strong&gt; A &lt;code&gt;.logstripper.json&lt;/code&gt; configuration file that defines excluded patterns per project, shareable across a team through version control.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ignore comments.&lt;/strong&gt; A &lt;code&gt;// log-stripper-ignore&lt;/code&gt; annotation that tells the extension to skip a specific line or block.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;More language coverage.&lt;/strong&gt; Zig, Nim, OCaml, and Erlang are candidates for future additions.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Log Stripper is a small tool. It solves one problem, and it solves it well.&lt;/p&gt;

&lt;p&gt;But the process of building it taught me something more valuable than any individual feature: the instinct to look at a repetitive problem and ask "why am I doing this manually?" is one of the most productive instincts an engineer can develop.&lt;/p&gt;

&lt;p&gt;We accept small frictions as part of the job. We work around limitations instead of fixing them. We solve the same problem repeatedly instead of automating it once.&lt;/p&gt;

&lt;p&gt;Log Stripper exists because I stopped accepting one of those frictions.&lt;/p&gt;

&lt;p&gt;If you're reading this and you have something similar - a small repetitive task, an annoying workflow step, a gap in your tooling - build the solution. The process will teach you more than you expect, and the tool will serve you for years.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Try Log Stripper:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;VS Code Marketplace: &lt;a href="https://marketplace.visualstudio.com/items?itemName=saurabhchoudhary.log-stripper" rel="noopener noreferrer"&gt;https://marketplace.visualstudio.com/items?itemName=saurabhchoudhary.log-stripper&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/saurabhzaiswal/Log-Stripper-VS-Code" rel="noopener noreferrer"&gt;https://github.com/saurabhzaiswal/Log-Stripper-VS-Code&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'm actively improving Log Stripper, so real-world feedback is incredibly valuable.&lt;/p&gt;

&lt;p&gt;If Log Stripper helps keep a few forgotten debug statements out of production, then it has already paid for itself.&lt;/p&gt;




</description>
      <category>vscode</category>
      <category>opensource</category>
      <category>typescript</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
