Skip to content

Fix #4: strip configured labeled statements - #11

Merged
sam-parsons merged 3 commits into
mainfrom
feature/4-strip-labeled-statements
Apr 25, 2026
Merged

sam-parsons merged 3 commits into
mainfrom
feature/4-strip-labeled-statements

Conversation

@sam-parsons

Copy link
Copy Markdown
Owner

Summary

  • Added labels-based stripping support for labeled blocks and single labeled statements.
  • Kept behavior scoped to configured labels only; non-target labels are preserved.
  • Added tests covering block and non-block labeled statement removal.

Issues

How to test

  • npm run check
  • npm run build

Notes

  • This implementation is currently text-based and focused on issue scope; AST+map-oriented refinement remains for follow-up work.

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.ts uses findMatchingBrace() 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".

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.
Comment thread test/strip.test.ts Outdated
Comment on lines +77 to +78
"test: doThing();",
"prod: doNotRemove();",

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how is this feature actually useful? I've never written code like this, nor seen it - what is the utility?

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I somewhat understand, but is test: doThing(); is even valid code?

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.
Comment thread src/index.ts Outdated
Comment thread src/index.ts
Comment thread src/index.ts
Comment thread src/index.ts
Add JSDoc, clearer variable naming, and high-level loop comments in label stripping helpers to address review feedback on readability.
Comment thread src/index.ts
Comment on lines +90 to +91
blockPattern.lastIndex = matchStart;
blockMatch = blockPattern.exec(output);

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what do these do, how does the blockMatch work, and how does this progress through the matches if there are many?

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great callout. Quick breakdown:

  • blockPattern finds the start of a labeled block-like statement (e.g. foo: { or label: while (...) {).
  • blockMatch = blockPattern.exec(output) returns the next regex match object (or null when done).
  • Inside the while, we use that match to compute the opening { position, find its matching } via findMatchingBrace, and remove that entire labeled block slice from output.
  • After removal, we set blockPattern.lastIndex = matchStart and run exec again so matching continues from the edit point in the updated string (this avoids skipping adjacent matches after string length changes).
  • Loop exits when exec returns null (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.

@sam-parsons
sam-parsons merged commit 2325b73 into main Apr 25, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Issue D: Strip configured labeled statements

1 participant