Summary
@ttsc/banner (and any SourcePreamblePlugin) corrupts emitted source maps: every mapping for real code points N lines too deep — onto blank lines past the end of the on-disk source — where N is the banner's line count. Both .js.map and .d.ts.map are affected. Debugging a banner'd project jumps to the wrong line.
Root cause
The banner is injected at the source level: sourcePreambleFS prepends the preamble to each source file before TypeScript-Go parses it (so it participates in comment emission, removeComments, JSDoc association and .d.ts emit). The side effect: every source coordinate the emitter records is shifted down by the preamble's line count, but the sources-referenced file on disk has no preamble. So a mapping that should say "source line 0" says "source line N".
Decoded example (4-line banner over a 5-line file): exports.first = 111 mapped to source line 9 (blank) instead of line 0. export declare const first in the .d.ts.map had the identical shift.
The existing banner test only asserted the banner text is absent from the map — it never decoded the mappings, so the line shift went unnoticed.
Fix
Post-emit, rewrite .js.map / .d.ts.map mappings: drop segments inside the preamble region (source line < N, i.e. the emitted banner comment, which has no real-source counterpart) and subtract N from every remaining segment's source line. Wired into the utility host's WriteFile so it runs for both maps, and even under removeComments (where the banner is stripped from output but the source is still preamble-shifted).
This keeps all other banner behavior (output text, .d.ts, removeComments, JSDoc) untouched — only the map's source axis is corrected. Covered by a Go unit test (VLQ round-trip on a real shifted map) and a banner e2e test that decodes both maps and asserts no mapping escapes the real source.
Summary
@ttsc/banner(and anySourcePreamblePlugin) corrupts emitted source maps: every mapping for real code pointsNlines too deep — onto blank lines past the end of the on-disk source — whereNis the banner's line count. Both.js.mapand.d.ts.mapare affected. Debugging a banner'd project jumps to the wrong line.Root cause
The banner is injected at the source level:
sourcePreambleFSprepends the preamble to each source file before TypeScript-Go parses it (so it participates in comment emission,removeComments, JSDoc association and.d.tsemit). The side effect: every source coordinate the emitter records is shifted down by the preamble's line count, but thesources-referenced file on disk has no preamble. So a mapping that should say "source line 0" says "source line N".Decoded example (4-line banner over a 5-line file):
exports.first = 111mapped to source line 9 (blank) instead of line 0.export declare const firstin the.d.ts.maphad the identical shift.The existing banner test only asserted the banner text is absent from the map — it never decoded the mappings, so the line shift went unnoticed.
Fix
Post-emit, rewrite
.js.map/.d.ts.mapmappings: drop segments inside the preamble region (source line < N, i.e. the emitted banner comment, which has no real-source counterpart) and subtract N from every remaining segment's source line. Wired into the utility host's WriteFile so it runs for both maps, and even underremoveComments(where the banner is stripped from output but the source is still preamble-shifted).This keeps all other banner behavior (output text,
.d.ts,removeComments, JSDoc) untouched — only the map's source axis is corrected. Covered by a Go unit test (VLQ round-trip on a real shifted map) and a banner e2e test that decodes both maps and asserts no mapping escapes the real source.