Repository navigation
Fix #4: strip configured labeled statements - #11
Conversation
Add support for removing configured labels for both labeled blocks and single labeled statements so dev/test tagged code paths can be dropped in builds.
| "test: doThing();", | ||
| "prod: doNotRemove();", |
There was a problem hiding this comment.
how is this feature actually useful? I've never written code like this, nor seen it - what is the utility?
There was a problem hiding this comment.
Great question. The utility is mainly for conditional debug instrumentation in apps/libraries that do not rely exclusively on env-based dead-code elimination. A common pattern is wrapping dev-only assertions/logging in labels, for example: dev: { invariant(...); console.log(...); }, so production builds can strip that block entirely with one rule while keeping source code readable in development. It is less common than if (process.env.NODE_ENV !== "production"), but it is explicit, build-tool-agnostic, and avoids runtime branching when stripped.
There was a problem hiding this comment.
I somewhat understand, but is test: doThing(); is even valid code?
There was a problem hiding this comment.
Yes — it is valid JavaScript syntax. A labeled statement is labelIdentifier: statement, so test: doThing(); is legal (and so is dev: { ... }). It is uncommon in day-to-day app code, which is why it looks odd, but parsers/bundlers support it as part of the language grammar.
There was a problem hiding this comment.
can you make the test cases more closely resemble the example found on MDN?> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/label
There was a problem hiding this comment.
Great suggestion — updated. I changed the tests to MDN-style labeled examples (foo: { ... break foo; ... } and labelCancelLoops: while (...) { ... }). While doing that, I found our matcher only handled label: { ... }, so I also fixed label-block detection to support labels preceding loop statements with braces on the same line. Pushed in 9352fcd.
Update label stripping tests to mirror MDN-style labeled block and labeled loop examples, and broaden block detection so labels preceding loop statements with braces are stripped correctly.
Add JSDoc, clearer variable naming, and high-level loop comments in label stripping helpers to address review feedback on readability.
| blockPattern.lastIndex = matchStart; | ||
| blockMatch = blockPattern.exec(output); |
There was a problem hiding this comment.
what do these do, how does the blockMatch work, and how does this progress through the matches if there are many?
There was a problem hiding this comment.
Great callout. Quick breakdown:
blockPatternfinds the start of a labeled block-like statement (e.g.foo: {orlabel: while (...) {).blockMatch = blockPattern.exec(output)returns the next regex match object (ornullwhen done).- Inside the
while, we use that match to compute the opening{position, find its matching}viafindMatchingBrace, and remove that entire labeled block slice fromoutput. - After removal, we set
blockPattern.lastIndex = matchStartand runexecagain so matching continues from the edit point in the updated string (this avoids skipping adjacent matches after string length changes). - Loop exits when
execreturnsnull(no more matches) or if braces are malformed (closeBraceIndex === -1).
So yes: this progresses through multiple matches one by one, mutating the string each pass and re-scanning from the last removal point.
Summary
labels-based stripping support for labeled blocks and single labeled statements.Issues
How to test
npm run checknpm run buildNotes
Learning notes
Small parser utility vs single regex tradeoff
What it is
When syntax can nest (like braces inside labeled blocks), a single regex is often brittle. A small stateful scanner can be a better local abstraction than forcing increasingly complex patterns.
Where it appears in this PR
src/index.tsusesfindMatchingBrace()with a depth counter to remove full labeled blocks safely, then uses a simpler regex for single-line labeled statements.Why it was the right call here
The alternative was one large regex for both block and non-block labels, which becomes fragile once nested braces appear. The scanner approach keeps the block case deterministic while still keeping implementation lightweight. The downside is a bit more custom logic, but it is easier to reason about and test incrementally.
If you want to go deeper
Search: "recursive structures and why regex is insufficient" and "state machines for lightweight parsing".