Skip to content

node:module: implement stripTypeScriptTypes#32206

Open
robobun wants to merge 4 commits into
mainfrom
farm/ed35d672/node-module-strip-typescript-types
Open

node:module: implement stripTypeScriptTypes#32206
robobun wants to merge 4 commits into
mainfrom
farm/ed35d672/node-module-strip-typescript-types

Conversation

@robobun

@robobun robobun commented Jun 12, 2026

Copy link
Copy Markdown
Collaborator

Fixes #32196
Fixes #25058 (the docs listed stripTypeScriptTypes as supported; it now is)

Problem

node:module did not export or implement stripTypeScriptTypes (added in Node v22.13.0):

import { stripTypeScriptTypes } from 'node:module';
SyntaxError: Export named 'stripTypeScriptTypes' not found in module 'node:module'.

Fix

Implements module.stripTypeScriptTypes(code[, options]) backed by Bun's native transpiler, exported from node:module for both require and named ESM imports. The contract was verified empirically against Node v24.3.0:

  • Argument validation matches Node exactly, including error codes, classes, message text, and property read order: ERR_INVALID_ARG_TYPE for non-string code/sourceUrl and non-boolean sourceMap, ERR_INVALID_ARG_VALUE for bad mode and for sourceMap: true in strip mode.
  • mode: 'strip' (default) rejects TypeScript syntax with runtime semantics, with Node's exact messages and new error codes ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX / ERR_INVALID_TYPESCRIPT_SYNTAX (both SyntaxError): enums, instantiated namespaces, parameter properties, import x = require(...), export = .... Ambient constructs (declare enum, declare namespace, declare module "x", type-only namespaces, import type x = require(...)) are stripped as erasable. The identifier-named module N {} keyword is rejected in both modes, like amaro.
  • mode: 'transform' lowers enums, namespaces, parameter properties, import = and export =.
  • sourceUrl appends \n\n//# sourceURL=...; sourceMap: true (transform mode only) appends an inline base64 map shaped like Node's: {"version":3,"sources":[<sourceUrl>],"names":[],"mappings":"..."}.
  • Parse errors throw ERR_INVALID_TYPESCRIPT_SYNTAX with Bun's parser message.
  • Value imports only used as types are kept (trim_unused_imports off), process.env.* is not inlined, no dead-code elimination, macros disabled.

To support the strip-mode rejections, the parser records the first non-ambient TS runtime-syntax construct (Ast::ts_runtime_syntax) and whether an identifier-named module declaration was used (Ast::uses_ts_module_keyword). Recording happens exactly where the parser materializes these constructs, so declare contexts (which return S::TypeScript earlier or never reach the visit pass) never set the flags.

Known divergences from Node

Node's amaro blanks types in place; Bun re-prints from the AST. So:

  • Original line/column positions are not preserved in strip mode (Node documents strip mode as position-preserving); output is re-printed JS.
  • Comments are dropped.
  • Decorators are lowered (Node passes them through as syntax).
  • Parse error message text comes from Bun's parser, not swc (same code and class).
  • Param props in ambient/overload-only positions (declare class C { constructor(public x); }) are stripped instead of throwing ERR_INVALID_TYPESCRIPT_SYNTAX (the input is invalid TS per tsc).

Verification

test/js/node/module/strip-typescript-types.test.ts (34 tests): the issue repro via named ESM import in a subprocess, CJS export, validation errors with exact Node messages, all strip-mode rejections and ambient allowances, transform-mode lowering verified by evaluating the output, sourceURL/sourceMap output shape including decoding the base64 map. All fail on the unfixed build with the error above.

Existing suites pass: test/bundler/transpiler/transpiler.test.js (188), test/bundler/esbuild/ts.test.ts (67), test/bundler/esbuild/importstar_ts.test.ts (23), test/bundler/bundler_edgecase.test.ts (119), decorator suites (78), test/js/node/module/ (98).

@robobun

robobun commented Jun 12, 2026

Copy link
Copy Markdown
Collaborator Author
Updated 1:48 AM PT - Jun 19th, 2026

@robobun, your commit 524b763 has 1 failures in Build #63478 (All Failures):


🧪   To try this PR locally:

bunx bun-pr 32206

That installs a local version of the PR into your bun-32206 executable, so you can run:

bun-32206 --bun

@github-actions

Copy link
Copy Markdown
Contributor

Found 1 issue this PR may fix:

  1. node:module stripTypeScriptTypes is documented but is not actually supported #25058 - Documents stripTypeScriptTypes as supported in node:module, but the function was never implemented; this PR adds the implementation

If this is helpful, copy the block below into the PR description to auto-close this issue on merge.

Fixes #25058

🤖 Generated with Claude Code

@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Implements node:module.stripTypeScriptTypes with parser/AST runtime-semantics tracking, new TypeScript SyntaxError codes, a Rust FFI + C++ host wrapper that validate options and forward to a one-shot Transpiler, and comprehensive tests including inline sourcemap emission.

Changes

TypeScript runtime semantics tracking and node:module stripTypeScriptTypes API

Layer / File(s) Summary
AST and parser runtime-semantics tracking
src/ast/ast_result.rs, src/ast/lib.rs, src/js_parser/p.rs, src/js_parser/parse/parse_stmt.rs, src/js_parser/parse/parse_typescript.rs, src/js_parser/visit/mod.rs
TsRuntimeSyntax enum is added; Ast<'a> and parser P gain ts_runtime_syntax: Option<TsRuntimeSyntax> and uses_ts_module_keyword: bool. record_ts_runtime_syntax records the first non-ambient runtime-bearing TS construct; parser paths record Namespace, Enum, ImportEquals, ExportAssignment, and ParameterProperty; state is wired into the final AST.
TypeScript syntax error codes
src/jsc/ErrorCode.rs, src/jsc/bindings/ErrorCode.ts
Adds INVALID_TYPESCRIPT_SYNTAX and UNSUPPORTED_TYPESCRIPT_SYNTAX ErrorCode discriminants and ERR_ aliases, updates ErrorCode::COUNT and CODE_STR, and maps both to SyntaxError in JS bindings.
stripTypeScriptTypes FFI and host function
src/jsc/NodeModuleModule.rs, src/jsc/modules/NodeModuleModule.cpp
Adds NodeModuleModule__stripTypeScriptTypes FFI wrapper and jsFunctionStripTypeScriptTypes host binding. Builds a one-shot Transpiler for strip/transform modes, maps parser failures to ERR_INVALID_TYPESCRIPT_SYNTAX, rejects module keyword and (in strip mode) runtime TS constructs with ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX, prints output with optional inline base64 sourcemap or //# sourceURL=, and enforces option validation (mode, sourceMap, sourceUrl).
stripTypeScriptTypes test coverage
test/js/node/module/strip-typescript-types.test.ts
Adds tests for ESM/CommonJS interop, type stripping and runtime behavior, import erasure rules, input and options validation, unsupported-syntax rejection and error codes, ambient/declare acceptance, transform-mode lowering (enums/namespaces/parameter-properties/import/export-equals), and inline sourcemap generation and contents.

Suggested reviewers

  • Jarred-Sumner
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'node:module: implement stripTypeScriptTypes' clearly and concisely summarizes the main objective of the changeset: implementing the stripTypeScriptTypes function in node:module.
Description check ✅ Passed The PR description fully covers both required template sections: detailed explanation of what the PR does (problem, fix, verification approach) and how the code was verified (test suite with 34 tests, existing suites passing).
Linked Issues check ✅ Passed The PR fully addresses the objectives from both linked issues: #32196 (export and implement stripTypeScriptTypes from node:module) and #25058 (provide documented functionality). Implementation includes matching Node semantics, validation, error handling, and comprehensive test coverage.
Out of Scope Changes check ✅ Passed All changes are directly within scope: adding stripTypeScriptTypes to node:module, supporting infrastructure (error codes, parser tracking, transpiler logic), and comprehensive test coverage. No unrelated modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/jsc/NodeModuleModule.rs`:
- Around line 334-363: The current logic only emits the sourceURL trailer in the
else-if branch so when source_map is true the sourceURL is skipped; modify the
block that handles source_map in NodeModuleModule.rs (the conditional using
source_map, json, source_url_utf8, out and map_vlq) to also append the `//#
sourceURL=` comment when source_url_utf8.slice() is non-empty—i.e., after
writing the inline base64 source map to out, check
source_url_utf8.slice().is_empty() and if not, extend out with "\n\n//#
sourceURL=" and the source_url_utf8 bytes (same semantics as the existing else
branch) so both sourceMappingURL and sourceURL are emitted for combined options.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: bb880893-e5b6-4bdf-b8c4-2a649f4dab9c

📥 Commits

Reviewing files that changed from the base of the PR and between ac312f0 and bf7c96a.

📒 Files selected for processing (11)
  • src/ast/ast_result.rs
  • src/ast/lib.rs
  • src/js_parser/p.rs
  • src/js_parser/parse/parse_stmt.rs
  • src/js_parser/parse/parse_typescript.rs
  • src/js_parser/visit/mod.rs
  • src/jsc/ErrorCode.rs
  • src/jsc/NodeModuleModule.rs
  • src/jsc/bindings/ErrorCode.ts
  • src/jsc/modules/NodeModuleModule.cpp
  • test/js/node/module/strip-typescript-types.test.ts

Comment thread src/jsc/NodeModuleModule.rs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/jsc/NodeModuleModule.rs (2)

225-231: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Preserve a leading hashbang in the returned source.

code_utf8 still contains the original bytes, but the function returns only the printer output plus trailers, so #!/usr/bin/env bun is dropped on every non-empty input. That turns executable TypeScript entrypoints into non-executable output and breaks the Node-compat contract this API is aiming for. Please carry the shebang through and add a regression case for it. Based on PR objectives, this API is intended to match Node's stripTypeScriptTypes behavior.

Also applies to: 301-331

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/jsc/NodeModuleModule.rs` around lines 225 - 231, The current code creates
code_utf8 and a bun_ast::Source but drops a leading shebang (#!...) when
returning printed output; update the logic around code_utf8 and the printer
output in NodeModuleModule.rs (the block using code_utf8, source, and the
printer) to detect and preserve a leading hashbang from code_utf8.slice() and
prepend it to the final returned string (or ensure the bun_ast::Source includes
it) so the output remains executable; apply the same fix in the similar block at
the other occurrence (around the 301-331 region) and add a regression test that
feeds input with a shebang (e.g. "#!/usr/bin/env bun\n...") and asserts the
returned string begins with the original shebang.

261-271: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Replace the banned String::from_utf8_lossy call.

Clippy is already failing on Line 271 for this exact method, so the PR cannot merge as-is. Please switch this parser-error formatting path to one of the repo-approved byte/string helpers instead of alloc::string::String::from_utf8_lossy.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/jsc/NodeModuleModule.rs` around lines 261 - 271, Replace the banned
alloc::string::String::from_utf8_lossy call in the NodeModuleModule.rs error
path: instead of String::from_utf8_lossy(text) use the repository's approved
byte→string helper (import it) to convert text: &[u8] into a safe String/&str
and pass that into the format_args! call; specifically modify the return
expression that builds jsc::ErrorCode::ERR_INVALID_TYPESCRIPT_SYNTAX.throw(...)
so it uses the approved helper (e.g. crate::util::decode_lossy_bytes(text) or
the project's equivalent) in place of String::from_utf8_lossy, and add the
necessary use/import for that helper.

Source: Pipeline failures

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/jsc/NodeModuleModule.rs`:
- Around line 225-231: The current code creates code_utf8 and a bun_ast::Source
but drops a leading shebang (#!...) when returning printed output; update the
logic around code_utf8 and the printer output in NodeModuleModule.rs (the block
using code_utf8, source, and the printer) to detect and preserve a leading
hashbang from code_utf8.slice() and prepend it to the final returned string (or
ensure the bun_ast::Source includes it) so the output remains executable; apply
the same fix in the similar block at the other occurrence (around the 301-331
region) and add a regression test that feeds input with a shebang (e.g.
"#!/usr/bin/env bun\n...") and asserts the returned string begins with the
original shebang.
- Around line 261-271: Replace the banned alloc::string::String::from_utf8_lossy
call in the NodeModuleModule.rs error path: instead of
String::from_utf8_lossy(text) use the repository's approved byte→string helper
(import it) to convert text: &[u8] into a safe String/&str and pass that into
the format_args! call; specifically modify the return expression that builds
jsc::ErrorCode::ERR_INVALID_TYPESCRIPT_SYNTAX.throw(...) so it uses the approved
helper (e.g. crate::util::decode_lossy_bytes(text) or the project's equivalent)
in place of String::from_utf8_lossy, and add the necessary use/import for that
helper.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 06eccc6a-97b4-439a-b16a-7a0978d9881a

📥 Commits

Reviewing files that changed from the base of the PR and between bf7c96a and aa95fc6.

📒 Files selected for processing (2)
  • src/jsc/NodeModuleModule.rs
  • test/js/node/module/strip-typescript-types.test.ts

Comment thread src/jsc/modules/NodeModuleModule.cpp

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for addressing the RELEASE_AND_RETURN nit. I didn't find further issues, but this is a substantial new public API touching parser internals, one-shot Transpiler setup with unsafe arena lifetime handling, and documented divergences from Node's behavior — worth a human look.

Extended reasoning...

Overview

This PR implements module.stripTypeScriptTypes for node:module, backed by Bun's native transpiler. It spans 11 files: new TsRuntimeSyntax tracking fields on Ast and the parser P struct; instrumentation in parse_stmt.rs, parse_typescript.rs, and visit/mod.rs to record non-ambient TS runtime constructs and the module keyword; two new ErrorCode discriminants (ERR_INVALID_TYPESCRIPT_SYNTAX, ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX); a ~200-line Rust FFI entrypoint in NodeModuleModule.rs that builds a one-shot Transpiler, parses, gates on the recorded flags, prints (optionally with a source map via a custom VlqCapture handler), and assembles the output with hashbang/sourceURL/sourceMappingURL handling; ~80 lines of C++ in NodeModuleModule.cpp for Node-style argument validation and the .lut.h table entry; and a 262-line test file with 34 tests.

Security risks

None identified. The API takes an in-memory string and returns a transformed string — no filesystem, network, auth, or privilege boundaries are involved. The unsafe block (bun_ptr::detach_lifetime_ref to launder the arena borrow to 'static for Transpiler<'static>) follows the same pattern documented as used by JSTranspiler / TransformTask, and the arena demonstrably outlives all uses within the function body.

Level of scrutiny

This warrants human review. It is a new public Node-compat API surface with explicitly documented behavioral divergences from Node (output is re-printed rather than blanked in place, so positions/comments are not preserved; decorators are lowered; ambient param-prop edge case differs) — those are design tradeoffs a maintainer should sign off on. The parser instrumentation, while additive and guarded to only record state, runs on every TypeScript file parsed by Bun, not just calls to this API. The Rust side configures ~15 transpiler option flags by hand, manages arena/AST-allocator scoping, a scopeguard for macro_context cleanup, and hand-builds the source-map JSON — all reasonable but non-trivial.

Other factors

My prior inline comment (wrap the throwing FFI tail call in RELEASE_AND_RETURN) was addressed in bc8ee08 and the thread is resolved. CodeRabbit's one finding was withdrawn after the author showed it matches Node's semantics. Test coverage is thorough (validation errors with exact Node messages, strip-mode rejections vs. ambient allowances, transform-mode lowering verified by evaluation, source-map shape including the hashbang line-shift). The initial CI run on 2b35529 showed failures, but a follow-up commit landed afterward; I can't see the current CI state from here.

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I didn't find any bugs, but this is a substantial new public API that threads tracking state through the core TS parser and ships with documented Node-compat divergences (re-printed output vs. blanking, comments/positions dropped), so it warrants a human look at those trade-offs and the parser instrumentation.

Extended reasoning...

Overview

This PR implements module.stripTypeScriptTypes from Node v22.13+. It adds ~280 lines of Rust in NodeModuleModule.rs (a one-shot Transpiler invocation with sourcemap assembly and hashbang handling), ~85 lines of C++ option validation in NodeModuleModule.cpp, two new ErrorCode discriminants kept index-aligned across Rust/TS/C++, and — most significantly — instruments the core parser (p.rs, parse_stmt.rs, parse_typescript.rs, visit/mod.rs) plus the Ast result struct to record the first non-ambient TS runtime-semantics construct and the module keyword. A 262-line test file with 34 tests covers validation, strip/transform behavior, ambient allowances, and sourcemap shape.

Security risks

None apparent. The function operates on caller-supplied source strings and returns a string; no filesystem, network, or privilege boundaries are crossed. The unsafe arena-lifetime laundering follows the established JSTranspiler/TransformTask pattern, and the new error codes are appended at the end of the table so existing discriminants are unchanged.

Level of scrutiny

High. The parser changes are additive (only recording state, not altering parse decisions) and look correctly placed — each record_ts_runtime_syntax call sits after the is_typescript_declare early-return so ambient constructs stay erasable, and the ParameterProperty recording in the visit pass relies on declare class never reaching visit. But these files are on the hot path for every JS/TS file Bun touches, so a maintainer should confirm the placement and that the two new Ast fields don't interact badly with any caching/serialization. The PR also documents intentional divergences from Node (output is re-printed from AST rather than blanked in place, so positions/comments aren't preserved and decorators are lowered) — those are user-visible API contract decisions that deserve explicit human sign-off rather than bot approval.

Other factors

Both prior inline review threads (CodeRabbit's sourceURL note and my RELEASE_AND_RETURN note) are resolved; the latter was addressed in bc8ee08. Test coverage is thorough and the existing transpiler/bundler suites are reported passing. No CODEOWNERS match the changed files.

@robobun

robobun commented Jun 13, 2026

Copy link
Copy Markdown
Collaborator Author

The diff is green. The only red check is the darwin-14-aarch64-test-bun lane (release-tier=previous), which has now gone red on two consecutive builds (62171, 62219) from infrastructure on that agent, not from this PR's code:

  • Build 62171: job reported "Expired" (timed out waiting for a macOS 14 aarch64 agent on the test-darwin queue).
  • Build 62219: job finally ran, reached --- End (all 2053 test entries executed), and every test passed, including the new node:module suite (36 pass, 0 fail). The job's status-2 came from the post-run teardown shell hook (the pkill -9 cleanup loop force-killing a lingering process), not a test assertion.

All other 285 jobs pass, and the new tests plus the transpiler/parser/module suites pass on every lane. No test failure is attributable to this PR.

Ready for a maintainer to merge (or re-run the darwin lane).

@robobun robobun force-pushed the farm/ed35d672/node-module-strip-typescript-types branch from bc4b14a to 5eb376d Compare June 16, 2026 23:09
@robobun

robobun commented Jun 16, 2026

Copy link
Copy Markdown
Collaborator Author

Rebased onto main to resolve merge conflicts. Both conflicts were in the index-aligned error-code table where main's #32414 (WebKit upgrade branch) had appended ERR_HTTP2_GOAWAY_SESSION:

  • src/jsc/bindings/ErrorCode.ts and src/jsc/ErrorCode.rs: kept ERR_HTTP2_GOAWAY_SESSION at discriminant 316 (as on main) and shifted this PR's ERR_INVALID_TYPESCRIPT_SYNTAX / ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX to 317 / 318, with COUNT = 319. Rust consts, ERR_-aliases, and the CODE_STR table are all re-aligned to that order.

Verified post-rebase: the new suite passes (36/0) and both TS codes throw SyntaxError with the correct .code, confirming the Rust mirror and C++ codegen agree on the new indices.

@robobun

robobun commented Jun 16, 2026

Copy link
Copy Markdown
Collaborator Author

Heads up on CI state after the rebase (sha 5eb376d):

  • GitHub Actions on this sha are green: Format, Lint JavaScript, and cargo clippy all pass (cargo miri still running).
  • The red buildkite/bun check (build 62978) is a Buildkite orchestration abort, not a code failure: the :pipeline: step passed (generated + uploaded a valid 76 KB ci.yml), then every build/test job was canceled within the same second. The build "failed" after 32s having compiled and tested nothing. This PR touches no .buildkite/ or CI config.

Locally on the rebased tip, bun bd test test/js/node/module/strip-typescript-types.test.ts passes 36/0, and both new error codes throw SyntaxError with the correct .code, confirming the ErrorCode re-indexing (HTTP2_GOAWAY_SESSION at 316, the two TS codes at 317/318, COUNT 319) is consistent between the Rust mirror and the C++ codegen.

A Buildkite "Rebuild" should clear the red check. Ready for a maintainer.

@robobun robobun force-pushed the farm/ed35d672/node-module-strip-typescript-types branch from 5eb376d to f458d89 Compare June 18, 2026 22:41
@robobun

robobun commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator Author

Rebased onto main again (now past #32494). Same conflict class as before: the index-aligned error-code table. Main has since appended ERR_TLS_ALPN_CALLBACK_INVALID_RESULT and ERR_PROXY_TUNNEL (and the table's base shifted, so MYSQL_CONNECTION_REFUSED is now 320).

Resolved by keeping all of main's new codes and placing this PR's two after them:

  • ERR_INVALID_TYPESCRIPT_SYNTAX → 324
  • ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX → 325
  • COUNT → 326

Rust consts, ERR_-aliases, and the CODE_STR table (326 entries, matches COUNT) are all re-aligned to that order. The other 8 files rebased cleanly.

Verified on the rebased tip (f458d89): the suite passes 36/0, the two TS codes throw SyntaxError with the correct .code, and a pre-existing code (ERR_INVALID_ARG_VALUE) still maps to TypeError, confirming the Rust mirror and C++ codegen agree on the re-indexed table.

@robobun

robobun commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator Author

CI status on the rebased tip (f458d89, build 63387): the diff is green; the only red is on the two darwin test lanes, both from environment-sensitive flake, not this PR.

  • 284 jobs pass (the build compiled on every target), and the new node:module suite passes on both darwin lanes (36/0, all 36 tests ran to completion). No individual test assertion failed on either darwin lane (0 N fail summaries).
  • :darwin: 14 aarch64 - test-bun (release-tier=previous): reached --- End, then exited status 2 from the post-run agent/teardown shell hook.
  • :darwin: 14 x64 - test-bun: two PTY tests timed out after 90s (creates subprocess with terminal attached, terminal option creates proper PTY for interactive programs) and the runner exited status 2. PTY/interactive-subprocess tests are a known flaky category on loaded agents.

The darwin lanes have now been the sole blocker across builds 62171, 62219, 63387 while the diff stayed green. None of the failures (flaky networking, teardown SIGKILL, PTY timeouts) touch this PR's surface (node:module / parser / ErrorCode).

Conflict resolution verified locally: bun bd test passes 36/0, and the two TS codes throw SyntaxError with the correct .code after the error-table re-index (HTTP2_GOAWAY_SESSION 321, TLS_ALPN_CALLBACK_INVALID_RESULT 322, PROXY_TUNNEL 323, TS codes 324/325, COUNT 326).

Ready for a maintainer to merge (or re-run the darwin lanes on healthy agents).

robobun and others added 4 commits June 19, 2026 08:02
Adds module.stripTypeScriptTypes(code, options) backed by Bun's native
transpiler, exported from node:module for both CJS and ESM.

- Validates arguments with Node's exact error codes and messages
  (ERR_INVALID_ARG_TYPE, ERR_INVALID_ARG_VALUE).
- strip mode rejects TypeScript syntax with runtime semantics (enums,
  instantiated namespaces, parameter properties, import =, export =)
  with ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX; ambient (declare) contexts
  are allowed. The identifier-named module keyword is rejected in both
  modes, matching Node's amaro behavior.
- transform mode lowers those constructs and optionally emits an inline
  base64 source map ({"version":3,"sources":[sourceUrl],...}).
- sourceUrl appends a //# sourceURL comment.
- Parse errors surface as ERR_INVALID_TYPESCRIPT_SYNTAX (SyntaxError).

The parser now records the first non-ambient TS runtime-syntax
construct (Ast::ts_runtime_syntax) and whether an identifier-named
module declaration was used (Ast::uses_ts_module_keyword) so strip
mode can reject them after parsing.

Unlike Node's amaro, output is re-printed from the AST rather than
blanked in place: original line/column positions are not preserved and
comments are dropped. Decorators are lowered rather than passed
through.

Fixes #32196
A leading #! line is consumed by the lexer and was dropped from the
re-printed output; carry it through like the bundler's entry-point
handling, and shift the inline source map down one generated line so
mappings stay aligned (matches Node's output byte for byte).

Replace the clippy-disallowed String::from_utf8_lossy with bstr::BStr
for displaying parser error text.
@robobun robobun force-pushed the farm/ed35d672/node-module-strip-typescript-types branch from f458d89 to 524b763 Compare June 19, 2026 08:08
@robobun

robobun commented Jun 19, 2026

Copy link
Copy Markdown
Collaborator Author

Rebased onto main again (now past #31830, which appended three ERR_FS_CP_* / ERR_DIR_CONCURRENT_OPERATION codes). Same conflict class as the prior rebases: the index-aligned error-code table.

Resolved by keeping main's new codes and placing this PR's two after them:

  • ERR_FS_CP_EEXIST 324, ERR_FS_CP_SYMLINK_TO_SUBDIRECTORY 325, ERR_DIR_CONCURRENT_OPERATION 326 (all from main)
  • ERR_INVALID_TYPESCRIPT_SYNTAX → 327
  • ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX → 328
  • COUNT → 329

Rust consts, ERR_-aliases, and the CODE_STR table (329 entries, matches COUNT) are all re-aligned. The other 8 files rebased cleanly.

Verified on the rebased tip (524b763): suite passes 36/0; the two TS codes throw SyntaxError with correct .code, and pre-existing codes (ERR_INVALID_ARG_VALUE, ERR_INVALID_ARG_TYPE) still map to TypeError, confirming the Rust mirror and C++ codegen agree on the re-indexed table.


CI on this tip (build 63478): 285 jobs pass; the sole red is :darwin: 26 aarch64 - test-bun, which exited status 2 from the post-run teardown hook after a proxy-tunnel networking timeout (ERR_PROXY_TUNNEL, 1000ms) with zero test-assertion failures (all 2448 entries ran). Same chronically-flaky darwin class that has been the only blocker across builds 62171, 62219, 63387, 63478 while the diff stays green. Notably the proxy-tunnel error fired with the correct code 323 and message, which independently confirms the error-table re-index is sound. Ready for a maintainer to merge (or re-run the darwin lane on a healthy agent).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

node:module does not export (or implement) stripTypeScriptTypes node:module stripTypeScriptTypes is documented but is not actually supported

1 participant