@nimbus-sh/worker 0.12.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (198) hide show
  1. package/dist/esbuild-cli-artifact.generated.d.ts +1 -1
  2. package/dist/esbuild-cli-artifact.generated.js +4 -4
  3. package/dist/esbuild-wasm-bundle.generated.d.ts +11 -10
  4. package/dist/esbuild-wasm-bundle.generated.d.ts.map +1 -1
  5. package/dist/esbuild-wasm-bundle.generated.js +11 -10
  6. package/dist/facets/build-facet.d.ts +53 -0
  7. package/dist/facets/build-facet.d.ts.map +1 -0
  8. package/dist/facets/build-facet.js +346 -0
  9. package/dist/facets/cirrus-real.d.ts +3 -0
  10. package/dist/facets/cirrus-real.d.ts.map +1 -1
  11. package/dist/facets/cirrus-real.js +1 -2
  12. package/dist/facets/compose.d.ts +1 -0
  13. package/dist/facets/compose.d.ts.map +1 -1
  14. package/dist/facets/compose.js +3 -0
  15. package/dist/facets/data-plan.d.ts +14 -30
  16. package/dist/facets/data-plan.d.ts.map +1 -1
  17. package/dist/facets/data-plan.js +153 -13
  18. package/dist/facets/dev-stylesheet.d.ts +27 -0
  19. package/dist/facets/dev-stylesheet.d.ts.map +1 -0
  20. package/dist/facets/dev-stylesheet.js +65 -0
  21. package/dist/facets/esbuild-transform.d.ts +23 -18
  22. package/dist/facets/esbuild-transform.d.ts.map +1 -1
  23. package/dist/facets/esbuild-transform.js +63 -109
  24. package/dist/facets/manager.d.ts +49 -9
  25. package/dist/facets/manager.d.ts.map +1 -1
  26. package/dist/facets/manager.js +238 -69
  27. package/dist/facets/oxc-transform.d.ts +29 -0
  28. package/dist/facets/oxc-transform.d.ts.map +1 -0
  29. package/dist/facets/oxc-transform.js +198 -0
  30. package/dist/facets/prebundle-pool.d.ts +23 -0
  31. package/dist/facets/prebundle-pool.d.ts.map +1 -0
  32. package/dist/facets/prebundle-pool.js +55 -0
  33. package/dist/facets/process.d.ts +13 -6
  34. package/dist/facets/process.d.ts.map +1 -1
  35. package/dist/facets/process.js +37 -31
  36. package/dist/facets/transform-store.d.ts +4 -4
  37. package/dist/facets/transform-store.js +4 -4
  38. package/dist/facets/vite-dev-server.d.ts +89 -12
  39. package/dist/facets/vite-dev-server.d.ts.map +1 -1
  40. package/dist/facets/vite-dev-server.js +66 -43
  41. package/dist/hosted/commands.d.ts.map +1 -1
  42. package/dist/hosted/commands.js +20 -4
  43. package/dist/hosted/runtime.d.ts.map +1 -1
  44. package/dist/hosted/runtime.js +7 -2
  45. package/dist/hosted/services.d.ts +3 -3
  46. package/dist/hosted/services.d.ts.map +1 -1
  47. package/dist/hosted/services.js +102 -95
  48. package/dist/hosted/session.d.ts +1 -0
  49. package/dist/hosted/session.d.ts.map +1 -1
  50. package/dist/loaders/generated-workers.d.ts +3 -0
  51. package/dist/loaders/generated-workers.d.ts.map +1 -1
  52. package/dist/loaders/generated-workers.js +3 -0
  53. package/dist/napi-wasm-artifacts.generated.js +2 -2
  54. package/dist/node-shims-artifact.generated.d.ts +14 -1
  55. package/dist/node-shims-artifact.generated.d.ts.map +1 -1
  56. package/dist/node-shims-artifact.generated.js +23 -10
  57. package/dist/npm/bin-links.d.ts +7 -4
  58. package/dist/npm/bin-links.d.ts.map +1 -1
  59. package/dist/npm/bin-links.js +14 -55
  60. package/dist/npm/cache.d.ts +6 -0
  61. package/dist/npm/cache.d.ts.map +1 -1
  62. package/dist/npm/cache.js +26 -4
  63. package/dist/npm/installer.d.ts +1 -1
  64. package/dist/npm/installer.d.ts.map +1 -1
  65. package/dist/npm/installer.js +26 -52
  66. package/dist/npm/pre-bundle-facet.d.ts +15 -117
  67. package/dist/npm/pre-bundle-facet.d.ts.map +1 -1
  68. package/dist/npm/pre-bundle-facet.js +13 -511
  69. package/dist/oxc-facet-artifact.generated.d.ts +18 -0
  70. package/dist/oxc-facet-artifact.generated.d.ts.map +1 -0
  71. package/dist/oxc-facet-artifact.generated.js +17 -0
  72. package/dist/oxc-wasm-artifact.generated.d.ts +20 -0
  73. package/dist/oxc-wasm-artifact.generated.d.ts.map +1 -0
  74. package/dist/oxc-wasm-artifact.generated.js +19 -0
  75. package/dist/rolldown-facet-artifact.generated.d.ts +18 -0
  76. package/dist/rolldown-facet-artifact.generated.d.ts.map +1 -0
  77. package/dist/rolldown-facet-artifact.generated.js +17 -0
  78. package/dist/router/remote-api.d.ts.map +1 -1
  79. package/dist/router/remote-api.js +9 -0
  80. package/dist/runtime/bash-repl.d.ts.map +1 -1
  81. package/dist/runtime/bash-repl.js +1 -4
  82. package/dist/runtime/cpython-resident.d.ts.map +1 -1
  83. package/dist/runtime/cpython-resident.js +1 -0
  84. package/dist/runtime/esbuild-wasm-bytes.d.ts +25 -23
  85. package/dist/runtime/esbuild-wasm-bytes.d.ts.map +1 -1
  86. package/dist/runtime/esbuild-wasm-bytes.js +30 -25
  87. package/dist/runtime/facet-loader-host.d.ts +5 -4
  88. package/dist/runtime/facet-loader-host.d.ts.map +1 -1
  89. package/dist/runtime/facet-loader-host.js +5 -4
  90. package/dist/runtime/node-runner.d.ts +2 -0
  91. package/dist/runtime/node-runner.d.ts.map +1 -1
  92. package/dist/runtime/node-runner.js +1 -0
  93. package/dist/runtime/node-shims-artifact.d.ts +8 -1
  94. package/dist/runtime/node-shims-artifact.d.ts.map +1 -1
  95. package/dist/runtime/node-shims-artifact.js +32 -4
  96. package/dist/runtime/node-shims.d.ts.map +1 -1
  97. package/dist/runtime/node-shims.js +145 -109
  98. package/dist/runtime/opencode-facet-runner.d.ts.map +1 -1
  99. package/dist/runtime/opencode-facet-runner.js +6 -2
  100. package/dist/runtime/oxc-wasm-bytes.d.ts +19 -0
  101. package/dist/runtime/oxc-wasm-bytes.d.ts.map +1 -0
  102. package/dist/runtime/oxc-wasm-bytes.js +39 -0
  103. package/dist/runtime/package-manager.js +1 -1
  104. package/dist/runtime/process-logs-api.d.ts.map +1 -1
  105. package/dist/runtime/process-logs-api.js +2 -0
  106. package/dist/runtime/project-fs.d.ts +8 -1
  107. package/dist/runtime/project-fs.d.ts.map +1 -1
  108. package/dist/runtime/project-fs.js +15 -1
  109. package/dist/runtime/python-repl.d.ts +40 -1
  110. package/dist/runtime/python-repl.d.ts.map +1 -1
  111. package/dist/runtime/python-repl.js +19 -11
  112. package/dist/runtime/ruby-repl.d.ts +38 -0
  113. package/dist/runtime/ruby-repl.d.ts.map +1 -1
  114. package/dist/runtime/ruby-repl.js +24 -5
  115. package/dist/runtime/ruby-resident.d.ts.map +1 -1
  116. package/dist/runtime/ruby-resident.js +2 -0
  117. package/dist/session/nimbus-session.d.ts +13 -8
  118. package/dist/session/nimbus-session.d.ts.map +1 -1
  119. package/dist/session/nimbus-session.js +11 -5
  120. package/dist/session/programmatic.d.ts +25 -30
  121. package/dist/session/programmatic.d.ts.map +1 -1
  122. package/dist/session/programmatic.js +65 -93
  123. package/dist/session/routes.d.ts.map +1 -1
  124. package/dist/session/routes.js +23 -7
  125. package/dist/session/rpc.d.ts +16 -6
  126. package/dist/session/rpc.d.ts.map +1 -1
  127. package/dist/session/rpc.js +53 -13
  128. package/dist/session/start-real-vite.d.ts +24 -9
  129. package/dist/session/start-real-vite.d.ts.map +1 -1
  130. package/dist/session/start-real-vite.js +40 -4
  131. package/dist/session/supervisor-op.d.ts +14 -0
  132. package/dist/session/supervisor-op.d.ts.map +1 -1
  133. package/dist/session/supervisor-op.js +49 -0
  134. package/dist/session/supervisor-rpc.d.ts +11 -0
  135. package/dist/session/supervisor-rpc.d.ts.map +1 -1
  136. package/dist/session/supervisor-rpc.js +18 -0
  137. package/dist/session/vite-command.d.ts.map +1 -1
  138. package/dist/session/vite-command.js +23 -19
  139. package/dist/session/ws-relay.d.ts.map +1 -1
  140. package/dist/session/ws-relay.js +13 -1
  141. package/dist/shell/npm-bin-entrypoints.d.ts +3 -1
  142. package/dist/shell/npm-bin-entrypoints.d.ts.map +1 -1
  143. package/dist/shell/npm-bin-entrypoints.js +53 -25
  144. package/dist/vfs/facet-resident-store.d.ts.map +1 -1
  145. package/dist/vfs/facet-resident-store.js +11 -5
  146. package/dist/wrangler/nimbus-wrangler.d.ts +8 -0
  147. package/dist/wrangler/nimbus-wrangler.d.ts.map +1 -1
  148. package/dist/wrangler/nimbus-wrangler.js +54 -57
  149. package/package.json +6 -4
  150. package/public/_assets/esbuild-0.24.2.wasm +0 -0
  151. package/public/_assets/napi-wasm/loader/{99efae93dd1dcc2b → ab7e57fe9e8750c2}/napi-wasm-loader.mjs +4 -4
  152. package/public/_assets/napi-wasm/loader/{99efae93dd1dcc2b → ab7e57fe9e8750c2}/provenance.json +2 -2
  153. package/public/_assets/oxc/nimbus-oxc-1aa8c4c7057c6c28.provenance.json +72 -0
  154. package/public/_assets/oxc/nimbus-oxc-1aa8c4c7057c6c28.wasm +0 -0
  155. package/public/_assets/runtime/esbuild-cli-f13e6a112b03ac07.js +1143 -0
  156. package/public/_assets/runtime/js-interpreter-3c37c48024f0f651.js +23 -0
  157. package/public/_assets/runtime/js-interpreter-ops-2f4dfec6798e70fc.js +290 -0
  158. package/public/_assets/runtime/js-interpreter-primordials-e620a61b7e9800fa.js +1 -0
  159. package/public/_assets/runtime/{node-shims-f92f16c7d7c532e9.js → node-shims-e3adc4576da31e6e.js} +651 -103
  160. package/public/_assets/runtime/{esbuild-cli-b7aecffd4c6a36fe.js → oxc-facet-fd86fefcdf16bf9c.js} +217 -1047
  161. package/public/_assets/runtime/{resident-store-92386265e8b306dc.js → resident-store-009f39539ac989fc.js} +11 -5
  162. package/public/_assets/runtime/rolldown-facet-09983434e2dbe93e.js +15165 -0
  163. package/public/_assets/runtime/{vfs-write-ledger-d33ee0034446c3e0.js → vfs-write-ledger-9e9594591425a9b8.js} +4 -1
  164. package/scripts/acorn-primordials.mjs +637 -0
  165. package/scripts/bundle-esbuild-wasm.mjs +42 -50
  166. package/scripts/bundle-facet-workers.mjs +247 -18
  167. package/scripts/bundle-node-shims.mjs +29 -2
  168. package/scripts/bundle-oxc-wasm.mjs +105 -0
  169. package/scripts/interpreter-bundle.mjs +105 -0
  170. package/scripts/napi-wasm/build.mjs +4 -1
  171. package/scripts/napi-wasm/loader/napi-wasm-loader.ts +38 -3
  172. package/scripts/oxc-wasm/Cargo.lock +1246 -0
  173. package/scripts/oxc-wasm/Cargo.toml +30 -0
  174. package/scripts/oxc-wasm/build.mjs +249 -0
  175. package/scripts/oxc-wasm/examples/memory.rs +51 -0
  176. package/scripts/oxc-wasm/examples/transform.rs +20 -0
  177. package/scripts/oxc-wasm/inputs.mjs +32 -0
  178. package/scripts/oxc-wasm/rust-toolchain.toml +5 -0
  179. package/scripts/oxc-wasm/src/abi.rs +136 -0
  180. package/scripts/oxc-wasm/src/diagnostics.rs +49 -0
  181. package/scripts/oxc-wasm/src/helpers.rs +139 -0
  182. package/scripts/oxc-wasm/src/lib.rs +247 -0
  183. package/scripts/oxc-wasm/src/module.rs +978 -0
  184. package/scripts/oxc-wasm/src/names.rs +175 -0
  185. package/scripts/oxc-wasm/src/options.rs +154 -0
  186. package/scripts/parser-audit.mjs +492 -0
  187. package/scripts/rolldown-facet/entry.mjs +21 -0
  188. package/scripts/rolldown-facet/shims.mjs +64 -0
  189. package/dist/facets/esbuild-bundle-pool.d.ts +0 -43
  190. package/dist/facets/esbuild-bundle-pool.d.ts.map +0 -1
  191. package/dist/facets/esbuild-bundle-pool.js +0 -80
  192. package/dist/loaders/pre-bundle-preamble.d.ts +0 -44
  193. package/dist/loaders/pre-bundle-preamble.d.ts.map +0 -1
  194. package/dist/loaders/pre-bundle-preamble.js +0 -116
  195. package/dist/runtime/host-wasm.d.ts +0 -8
  196. package/dist/runtime/host-wasm.d.ts.map +0 -1
  197. package/dist/runtime/host-wasm.js +0 -33
  198. /package/public/_assets/napi-wasm/loader/{99efae93dd1dcc2b → ab7e57fe9e8750c2}/wasi-trampoline.wasm +0 -0
@@ -0,0 +1,978 @@
1
+ //! Module format conversion, after TypeScript, JSX and defines have run.
2
+ //!
3
+ //! `Format::Cjs` lowers ES module syntax to CommonJS the way esbuild 0.24's
4
+ //! transform API does, because that is the shape the rest of Nimbus was
5
+ //! written against (bundle-cell-transform.ts, server-launch.ts):
6
+ //!
7
+ //! ```js
8
+ //! // helpers (helpers.rs), only those used
9
+ //! var stdin_exports = {}; // a module with export syntax
10
+ //! __export(stdin_exports, { a: () => a, default: () => stdin_default });
11
+ //! module.exports = __toCommonJS(stdin_exports); // marks __esModule
12
+ //! var import_x = __toESM(require("x")); // every import, hoisted in order
13
+ //! __reExport(stdin_exports, require("y"), module.exports);
14
+ //! ...body, with each use of an imported binding read through its record
15
+ //! (`(0, import_x.f)()` for a call, so `this` stays undefined)
16
+ //! ```
17
+ //!
18
+ //! Live bindings come from the getters; `default` imports go through
19
+ //! `__toESM`, whose `__esModule` rule is Babel's (esbuild's), not Node's.
20
+ //! Every format also does what esbuild does to `import.meta` and `import()`
21
+ //! when the target lacks them, and replaces top-level `this` in an ES module
22
+ //! with `void 0`. `Format::Esm` wraps a CommonJS module (one that uses
23
+ //! `module`/`exports` and has no export syntax) as `__commonJS` and exports
24
+ //! its `module.exports` as `default`.
25
+
26
+ use rustc_hash::FxHashMap;
27
+
28
+ use oxc::allocator::{Allocator, Box as ArenaBox, GetAllocator, TakeIn, Vec as ArenaVec};
29
+ use oxc::ast::builder::AstBuilder;
30
+ use oxc::ast::ast::*;
31
+ use oxc::ast_visit::VisitMut;
32
+ use oxc::diagnostics::OxcDiagnostic;
33
+ use oxc::parser::Parser;
34
+ use oxc::semantic::{Scoping, SymbolId};
35
+ use oxc::span::{SPAN, SourceType, Span};
36
+ use oxc::str::Ident;
37
+ use oxc::syntax::identifier::is_identifier_name;
38
+ use oxc::syntax::number::NumberBase;
39
+ use oxc::syntax::operator::UnaryOperator;
40
+ use oxc_ecmascript::BoundNames;
41
+ use oxc_traverse::{Ancestor, Traverse, traverse_mut};
42
+
43
+ use crate::helpers::{Helper, Helpers};
44
+ use crate::names::{Names, ensure_valid_identifier, name_from_path};
45
+ use crate::options::Format;
46
+
47
+ type TraverseCtx<'a> = oxc_traverse::TraverseCtx<'a, ()>;
48
+
49
+ pub struct ModuleOptions {
50
+ pub format: Format,
51
+ pub dynamic_import: bool,
52
+ pub import_meta: bool,
53
+ /// The module is an ES module (lib.rs decides).
54
+ pub is_esm: bool,
55
+ pub has_export_syntax: bool,
56
+ pub has_import_meta: bool,
57
+ pub has_dynamic_import: bool,
58
+ }
59
+
60
+ /// A hoisted statement standing for an import, in source order.
61
+ enum Record {
62
+ /// `var <name> = require(<source>)`, through `__toESM` when a default or
63
+ /// namespace binding reads it.
64
+ Require { name: RecordName, source: String, to_esm: bool },
65
+ /// `export * from <source>`.
66
+ ReExport { source: String },
67
+ }
68
+
69
+ #[derive(Clone)]
70
+ enum RecordName {
71
+ Generated(String),
72
+ /// A namespace import keeps its own binding as the record.
73
+ Symbol(SymbolId),
74
+ }
75
+
76
+ /// What an export's getter returns.
77
+ enum ExportValue {
78
+ Symbol(SymbolId),
79
+ Generated(String),
80
+ Member(RecordName, String),
81
+ }
82
+
83
+ /// How a use of an imported binding reads.
84
+ #[derive(Clone)]
85
+ struct ImportBinding<'a> {
86
+ record: RecordName,
87
+ record_ident: Ident<'a>,
88
+ property: Ident<'a>,
89
+ }
90
+
91
+ pub struct ModulePass<'a> {
92
+ options: ModuleOptions,
93
+ /// ES module syntax is lowered to CommonJS.
94
+ to_cjs: bool,
95
+ /// The module is an ES module: its top-level `this` is undefined.
96
+ is_esm: bool,
97
+ wrap_commonjs: bool,
98
+ names: Option<Names>,
99
+ helpers: Helpers,
100
+ records: Vec<Record>,
101
+ exports: Vec<(String, ExportValue)>,
102
+ bindings: FxHashMap<SymbolId, ImportBinding<'a>>,
103
+ exports_name: Option<String>,
104
+ wrapper_name: Option<String>,
105
+ /// The wrapper's `exports` and `module` parameters: renamed where the
106
+ /// module declares its own.
107
+ wrapper_params: [String; 2],
108
+ import_meta_name: Option<Ident<'a>>,
109
+ function_depth: u32,
110
+ top_level_await: Option<Span>,
111
+ errors: Vec<OxcDiagnostic>,
112
+ warnings: Vec<OxcDiagnostic>,
113
+ }
114
+
115
+ impl<'a> ModulePass<'a> {
116
+ pub fn new(options: ModuleOptions) -> Self {
117
+ Self {
118
+ options,
119
+ to_cjs: false,
120
+ is_esm: false,
121
+ wrap_commonjs: false,
122
+ names: None,
123
+ helpers: Helpers::default(),
124
+ records: Vec::new(),
125
+ exports: Vec::new(),
126
+ bindings: FxHashMap::default(),
127
+ exports_name: None,
128
+ wrapper_name: None,
129
+ wrapper_params: ["exports".into(), "module".into()],
130
+ import_meta_name: None,
131
+ function_depth: 0,
132
+ top_level_await: None,
133
+ errors: Vec::new(),
134
+ warnings: Vec::new(),
135
+ }
136
+ }
137
+
138
+ /// Run the pass. The outcome is the warnings, or the errors that refuse the module.
139
+ pub fn run(
140
+ mut self,
141
+ allocator: &'a Allocator,
142
+ program: &mut Program<'a>,
143
+ mut scoping: Scoping,
144
+ ) -> (Scoping, Result<Vec<OxcDiagnostic>, Vec<OxcDiagnostic>>) {
145
+ // The TypeScript transform keeps a module whose imports and exports
146
+ // were all types a module with an `export {}` of its own; esbuild
147
+ // emits nothing for them, and what the source said decides the format.
148
+ program.body.retain(
149
+ |s| !matches!(s, Statement::ExportNamedDeclaration(e) if e.specifiers.is_empty() && e.span.is_unspanned()),
150
+ );
151
+ // Imports the transformer injected (the JSX runtime's) have no
152
+ // position; esbuild prints them ahead of the module's own.
153
+ let injected = |s: &Statement<'a>| matches!(s, Statement::ImportDeclaration(i) if i.span.is_unspanned());
154
+ if program.body.iter().any(injected) {
155
+ let (mut synthetic, own): (Vec<_>, Vec<_>) = program.body.take_in(&allocator).into_iter().partition(injected);
156
+ synthetic.extend(own);
157
+ program.body = ArenaVec::from_iter_in(synthetic, &allocator);
158
+ }
159
+ if self.options.format == Format::Esm {
160
+ Self::drop_empty_exports(program, allocator);
161
+ }
162
+ self.is_esm = self.options.is_esm;
163
+ self.to_cjs = self.options.format == Format::Cjs && self.is_esm;
164
+ // esbuild's rule: a module that reads `module` or `exports` and has no
165
+ // export syntax, `import.meta` or top-level await is CommonJS, even
166
+ // with imports (they stay in front of the wrapper).
167
+ self.wrap_commonjs = self.options.format == Format::Esm
168
+ && !self.options.has_export_syntax
169
+ && !self.options.has_import_meta
170
+ && ["module", "exports"].iter().any(|&name| reads_commonjs_name(&scoping, name));
171
+ // Top-level await makes it an ES module after all; known before the
172
+ // walk, which rewrites `this` by it.
173
+ self.wrap_commonjs = self.wrap_commonjs && !has_top_level_await(program);
174
+ let lowers_dynamic_import = !self.options.dynamic_import && self.options.has_dynamic_import;
175
+
176
+ if self.to_cjs || self.wrap_commonjs || lowers_dynamic_import {
177
+ let mut names = Names::new(&scoping);
178
+ if self.to_cjs {
179
+ self.plan_cjs(program, &mut scoping, &mut names, allocator);
180
+ }
181
+ // A wrap is decided after the traversal (top-level await makes a
182
+ // module ES), so its helper's name is claimed in case.
183
+ let mut claimed = self.helpers;
184
+ if self.wrap_commonjs {
185
+ claimed.add(Helper::CommonJs);
186
+ self.wrapper_name = Some(names.generate("require_stdin", &mut scoping, allocator));
187
+ // `var exports` and `function module() {}` redeclare the
188
+ // wrapper's parameter, as in Node's own wrapper; a lexical or
189
+ // imported binding of the name would clash with it.
190
+ for (param, name) in self.wrapper_params.iter_mut().zip(["exports", "module"]) {
191
+ if let Some(symbol) = scoping.get_root_binding(name.into()) {
192
+ let flags = scoping.symbol_flags(symbol);
193
+ if !flags.is_function_scoped_declaration() && !flags.is_function() {
194
+ *param = names.claim_fresh(name);
195
+ }
196
+ }
197
+ }
198
+ }
199
+ if lowers_dynamic_import {
200
+ self.helpers.add(Helper::ToEsm);
201
+ claimed.add(Helper::ToEsm);
202
+ }
203
+ for helper in claimed.iter() {
204
+ if scoping.root_unresolved_references().contains_key(helper.name()) {
205
+ self.errors.push(OxcDiagnostic::error(format!(
206
+ "This module refers to a global named \"{}\", which module conversion needs for its helper",
207
+ helper.name()
208
+ )));
209
+ }
210
+ names.reserve_global(helper.name(), &mut scoping, allocator);
211
+ }
212
+ if !claimed.is_empty() {
213
+ names.reserve_global("Object", &mut scoping, allocator);
214
+ }
215
+ if lowers_dynamic_import {
216
+ names.reserve_global("Promise", &mut scoping, allocator);
217
+ }
218
+ // CommonJS's own names, which the module's code now runs beside:
219
+ // esbuild renames a module's `require`, `module` and `exports`
220
+ // whenever it converts one, used or not.
221
+ if self.to_cjs {
222
+ for name in ["require", "module", "exports"] {
223
+ names.reserve_global(name, &mut scoping, allocator);
224
+ }
225
+ } else if lowers_dynamic_import {
226
+ names.reserve_global("require", &mut scoping, allocator);
227
+ }
228
+ self.names = Some(names);
229
+ if !self.errors.is_empty() {
230
+ return (scoping, Err(self.errors));
231
+ }
232
+ }
233
+
234
+ let scoping = traverse_mut(&mut self, allocator, program, scoping, ());
235
+ if !self.to_cjs && self.names.is_some() {
236
+ Self::alias_renamed_exports(program, &scoping, allocator);
237
+ }
238
+ if self.options.format == Format::Cjs
239
+ && let Some(span) = self.top_level_await
240
+ {
241
+ self.errors.push(OxcDiagnostic::error(crate::TOP_LEVEL_AWAIT_CJS).with_label(span));
242
+ }
243
+ if !self.errors.is_empty() {
244
+ return (scoping, Err(self.errors));
245
+ }
246
+ self.finish(allocator, program, &scoping);
247
+ (scoping, Ok(self.warnings))
248
+ }
249
+
250
+ /// `export const Promise = 1`, its binding renamed out of the way of a
251
+ /// global the output reads: `const Promise2 = 1; export { Promise2 as
252
+ /// Promise }`, so the module's exports keep their names.
253
+ fn alias_renamed_exports(program: &mut Program<'a>, scoping: &Scoping, allocator: &'a Allocator) {
254
+ // Every name the declaration binds, as (its spelling now, its export
255
+ // name), once any of them was renamed: the declaration loses `export`,
256
+ // so each of its names needs a specifier.
257
+ let renamed = |decl: &Declaration<'a>| {
258
+ let mut pairs = Vec::new();
259
+ let mut any = false;
260
+ decl.bound_names(&mut |ident: &BindingIdentifier<'a>| {
261
+ let local = ident.symbol_id.get().map_or(ident.name.as_str(), |symbol| scoping.symbol_name(symbol));
262
+ any |= local != ident.name.as_str();
263
+ pairs.push((Ident::from(local), ident.name));
264
+ });
265
+ if !any {
266
+ pairs.clear();
267
+ }
268
+ pairs
269
+ };
270
+ let needs = program.body.iter().any(|s| matches!(s, Statement::ExportDeclaration(e) if !renamed(&e.declaration).is_empty()));
271
+ if !needs {
272
+ return;
273
+ }
274
+ let ast = AstBuilder::new(allocator);
275
+ let body = program.body.take_in(&allocator);
276
+ let mut kept = ArenaVec::with_capacity_in(body.len() + 1, &allocator);
277
+ for statement in body {
278
+ let Statement::ExportDeclaration(export) = statement else {
279
+ kept.push(statement);
280
+ continue;
281
+ };
282
+ let pairs = renamed(&export.declaration);
283
+ if pairs.is_empty() {
284
+ kept.push(Statement::ExportDeclaration(export));
285
+ continue;
286
+ }
287
+ let ExportDeclaration { span, declaration, .. } = export.unbox();
288
+ let specifiers = ArenaVec::from_iter_in(
289
+ pairs.into_iter().map(|(local, exported)| {
290
+ let local = ModuleExportName::IdentifierReference(IdentifierReference::new(
291
+ SPAN,
292
+ Ident::from_str_in(&local, &allocator),
293
+ &ast,
294
+ ));
295
+ let exported = ModuleExportName::IdentifierName(IdentifierName::new(SPAN, exported, &ast));
296
+ ExportSpecifier::new(SPAN, local, exported, ImportOrExportKind::Value, &ast)
297
+ }),
298
+ &allocator,
299
+ );
300
+ kept.push(Statement::from(declaration));
301
+ kept.push(Statement::new_export_named_declaration(span, specifiers, ImportOrExportKind::Value, &ast));
302
+ }
303
+ program.body = kept;
304
+ }
305
+
306
+ /// An ES module printed as one has no empty export lists: `export {}` goes,
307
+ /// and `export {} from "x"` keeps only its import, as esbuild prints them.
308
+ fn drop_empty_exports(program: &mut Program<'a>, allocator: &'a Allocator) {
309
+ let ast = AstBuilder::new(allocator);
310
+ let body = program.body.take_in(&allocator);
311
+ let mut kept = ArenaVec::with_capacity_in(body.len(), &allocator);
312
+ for statement in body {
313
+ match statement {
314
+ Statement::ExportNamedDeclaration(e) if e.specifiers.is_empty() => {}
315
+ Statement::ExportFromDeclaration(e) if e.specifiers.is_empty() => {
316
+ let ExportFromDeclaration { span, source, with_clause, .. } = e.unbox();
317
+ kept.push(Statement::new_import_declaration(
318
+ span,
319
+ None,
320
+ source,
321
+ None,
322
+ with_clause,
323
+ ImportOrExportKind::Value,
324
+ &ast,
325
+ ));
326
+ }
327
+ statement => kept.push(statement),
328
+ }
329
+ }
330
+ program.body = kept;
331
+ }
332
+
333
+ /// Take the module declarations out of the body, recording what each
334
+ /// imports and exports.
335
+ fn plan_cjs(
336
+ &mut self,
337
+ program: &mut Program<'a>,
338
+ scoping: &mut Scoping,
339
+ names: &mut Names,
340
+ allocator: &'a Allocator,
341
+ ) {
342
+ let ast = AstBuilder::new(allocator);
343
+ if self.options.has_export_syntax {
344
+ self.exports_name = Some(names.generate("stdin_exports", scoping, allocator));
345
+ self.helpers.add(Helper::ToCommonJs);
346
+ }
347
+ let body = program.body.take_in(&allocator);
348
+ let mut kept = ArenaVec::with_capacity_in(body.len(), &allocator);
349
+ // Local exports name symbols that an import may bind; resolved once every import is known.
350
+ for statement in body {
351
+ match statement {
352
+ Statement::ImportDeclaration(decl) => {
353
+ let decl = decl.unbox();
354
+ self.plan_import(decl, scoping, names, allocator);
355
+ }
356
+ Statement::ExportAllDeclaration(decl) => {
357
+ let source = decl.source.value.to_string();
358
+ match &decl.exported {
359
+ None => {
360
+ self.helpers.add(Helper::ReExport);
361
+ self.records.push(Record::ReExport { source });
362
+ }
363
+ Some(exported) => {
364
+ let exported = exported.name().to_string();
365
+ let name = names.generate(&ensure_valid_identifier(&exported), scoping, allocator);
366
+ self.helpers.add(Helper::ToEsm);
367
+ self.records.push(Record::Require {
368
+ name: RecordName::Generated(name.clone()),
369
+ source,
370
+ to_esm: true,
371
+ });
372
+ self.exports.push((exported, ExportValue::Generated(name)));
373
+ }
374
+ }
375
+ }
376
+ Statement::ExportFromDeclaration(decl) => {
377
+ let to_esm = decl.specifiers.iter().any(|s| s.local.name() == "default");
378
+ let source = decl.source.value.to_string();
379
+ let name = names.generate(&format!("import_{}", name_from_path(&source)), scoping, allocator);
380
+ if to_esm {
381
+ self.helpers.add(Helper::ToEsm);
382
+ }
383
+ let record = RecordName::Generated(name);
384
+ self.records.push(Record::Require { name: record.clone(), source, to_esm });
385
+ for specifier in &decl.specifiers {
386
+ self.exports.push((
387
+ specifier.exported.name().to_string(),
388
+ ExportValue::Member(record.clone(), specifier.local.name().to_string()),
389
+ ));
390
+ }
391
+ }
392
+ Statement::ExportNamedDeclaration(decl) => {
393
+ for specifier in &decl.specifiers {
394
+ let exported = specifier.exported.name().to_string();
395
+ let ModuleExportName::IdentifierReference(local) = &specifier.local else {
396
+ continue;
397
+ };
398
+ let symbol = local.reference_id.get().and_then(|id| scoping.get_reference(id).symbol_id());
399
+ match symbol {
400
+ Some(symbol) => self.exports.push((exported, ExportValue::Symbol(symbol))),
401
+ None => self.errors.push(
402
+ OxcDiagnostic::error(format!("\"{}\" is not declared in this file", local.name))
403
+ .with_label(local.span),
404
+ ),
405
+ }
406
+ }
407
+ }
408
+ Statement::ExportDeclaration(decl) => {
409
+ let decl = decl.unbox();
410
+ let mut bound = Vec::new();
411
+ decl.declaration.bound_names(&mut |ident: &BindingIdentifier<'a>| {
412
+ if let Some(symbol) = ident.symbol_id.get() {
413
+ bound.push((ident.name.to_string(), symbol));
414
+ }
415
+ });
416
+ for (name, symbol) in bound {
417
+ self.exports.push((name, ExportValue::Symbol(symbol)));
418
+ }
419
+ kept.push(Statement::from(decl.declaration));
420
+ }
421
+ Statement::ExportDefaultDeclaration(decl) => {
422
+ let ExportDefaultDeclaration { span, declaration, .. } = decl.unbox();
423
+ match declaration {
424
+ ExportDefaultDeclarationKind::FunctionDeclaration(mut func) => {
425
+ let value = match func.id.as_ref().and_then(|id| id.symbol_id.get()) {
426
+ Some(symbol) => ExportValue::Symbol(symbol),
427
+ None => {
428
+ let name = names.generate("stdin_default", scoping, allocator);
429
+ func.id = Some(BindingIdentifier::new(SPAN, Ident::from_str_in(&name, &ast), &ast));
430
+ ExportValue::Generated(name)
431
+ }
432
+ };
433
+ self.exports.push(("default".into(), value));
434
+ kept.push(Statement::FunctionDeclaration(func));
435
+ }
436
+ ExportDefaultDeclarationKind::ClassDeclaration(mut class) => {
437
+ let value = match class.id.as_ref().and_then(|id| id.symbol_id.get()) {
438
+ Some(symbol) => ExportValue::Symbol(symbol),
439
+ None => {
440
+ let name = names.generate("stdin_default", scoping, allocator);
441
+ class.id = Some(BindingIdentifier::new(SPAN, Ident::from_str_in(&name, &ast), &ast));
442
+ ExportValue::Generated(name)
443
+ }
444
+ };
445
+ self.exports.push(("default".into(), value));
446
+ kept.push(Statement::ClassDeclaration(class));
447
+ }
448
+ ExportDefaultDeclarationKind::TSInterfaceDeclaration(_) => {}
449
+ declaration => {
450
+ let expression = declaration.into_expression();
451
+ let name = names.generate("stdin_default", scoping, allocator);
452
+ let id = BindingIdentifier::new(SPAN, Ident::from_str_in(&name, &ast), &ast);
453
+ let declarator = VariableDeclarator::new(
454
+ SPAN,
455
+ BindingPattern::BindingIdentifier(ArenaBox::new_in(id, &allocator)),
456
+ None,
457
+ Some(expression),
458
+ false,
459
+ &ast,
460
+ );
461
+ kept.push(Statement::from(Declaration::new_variable_declaration(
462
+ span,
463
+ VariableDeclarationKind::Var,
464
+ [declarator],
465
+ false,
466
+ &ast,
467
+ )));
468
+ self.exports.push(("default".into(), ExportValue::Generated(name)));
469
+ }
470
+ }
471
+ }
472
+ Statement::TSExportAssignment(_) | Statement::TSNamespaceExportDeclaration(_) => {}
473
+ statement => kept.push(statement),
474
+ }
475
+ }
476
+ if !self.exports.is_empty() {
477
+ self.helpers.add(Helper::Export);
478
+ }
479
+ program.body = kept;
480
+ }
481
+
482
+ fn plan_import(
483
+ &mut self,
484
+ decl: ImportDeclaration<'a>,
485
+ scoping: &mut Scoping,
486
+ names: &mut Names,
487
+ allocator: &'a Allocator,
488
+ ) {
489
+ let source = decl.source.value.to_string();
490
+ let specifiers = decl.specifiers.unwrap_or_else(|| ArenaVec::new_in(&allocator));
491
+ let namespace = specifiers.iter().find_map(|s| match s {
492
+ ImportDeclarationSpecifier::ImportNamespaceSpecifier(ns) => ns.local.symbol_id.get(),
493
+ _ => None,
494
+ });
495
+ let to_esm = namespace.is_some()
496
+ || specifiers.iter().any(|s| match s {
497
+ ImportDeclarationSpecifier::ImportDefaultSpecifier(_) => true,
498
+ ImportDeclarationSpecifier::ImportSpecifier(s) => s.imported.name() == "default",
499
+ ImportDeclarationSpecifier::ImportNamespaceSpecifier(_) => false,
500
+ });
501
+ let (record, record_ident) = match namespace {
502
+ Some(symbol) => (RecordName::Symbol(symbol), Ident::from_str_in(scoping.symbol_name(symbol), &allocator)),
503
+ None => {
504
+ let name = names.generate(&format!("import_{}", name_from_path(&source)), scoping, allocator);
505
+ let ident = Ident::from_str_in(&name, &allocator);
506
+ (RecordName::Generated(name), ident)
507
+ }
508
+ };
509
+ for specifier in &specifiers {
510
+ let (local, property) = match specifier {
511
+ ImportDeclarationSpecifier::ImportSpecifier(s) => (&s.local, s.imported.name().as_str()),
512
+ ImportDeclarationSpecifier::ImportDefaultSpecifier(s) => (&s.local, "default"),
513
+ ImportDeclarationSpecifier::ImportNamespaceSpecifier(_) => continue,
514
+ };
515
+ if let Some(symbol) = local.symbol_id.get() {
516
+ self.bindings.insert(
517
+ symbol,
518
+ ImportBinding {
519
+ record: record.clone(),
520
+ record_ident,
521
+ property: Ident::from_str_in(property, &allocator),
522
+ },
523
+ );
524
+ }
525
+ }
526
+ if to_esm {
527
+ self.helpers.add(Helper::ToEsm);
528
+ }
529
+ self.records.push(Record::Require { name: record, source, to_esm });
530
+ }
531
+
532
+ /// Put the generated statements in front of the body: helpers, then the
533
+ /// exports object, then the imports, then `import_meta`.
534
+ fn finish(&mut self, allocator: &'a Allocator, program: &mut Program<'a>, scoping: &Scoping) {
535
+ // A module with top-level await is an ES module, whatever else it reads.
536
+ let wrap = self.wrap_commonjs && self.top_level_await.is_none();
537
+ if wrap {
538
+ self.helpers.add(Helper::CommonJs);
539
+ }
540
+ let mut text = self.helpers.source();
541
+ let record_name = |name: &RecordName| match name {
542
+ RecordName::Generated(name) => name.clone(),
543
+ RecordName::Symbol(symbol) => scoping.symbol_name(*symbol).to_string(),
544
+ };
545
+ if let Some(exports) = &self.exports_name {
546
+ text.push_str(&format!("var {exports} = {{}};\n"));
547
+ if !self.exports.is_empty() {
548
+ self.exports.sort_by(|a, b| a.0.cmp(&b.0));
549
+ text.push_str(&format!("__export({exports}, {{\n"));
550
+ for (i, (exported, value)) in self.exports.iter().enumerate() {
551
+ let getter = match value {
552
+ ExportValue::Symbol(symbol) => match self.bindings.get(symbol) {
553
+ Some(binding) => member_text(&record_name(&binding.record), &binding.property),
554
+ None => scoping.symbol_name(*symbol).to_string(),
555
+ },
556
+ ExportValue::Generated(name) => name.clone(),
557
+ ExportValue::Member(record, property) => member_text(&record_name(record), property),
558
+ };
559
+ // `__proto__: ...` would set the getters object's prototype
560
+ // (esbuild prints it so, and loses the export).
561
+ let key = if exported == "__proto__" {
562
+ "[\"__proto__\"]".to_string()
563
+ } else if is_identifier_name(exported) {
564
+ exported.clone()
565
+ } else {
566
+ js_string(exported)
567
+ };
568
+ let comma = if i + 1 < self.exports.len() { "," } else { "" };
569
+ text.push_str(&format!(" {key}: () => {getter}{comma}\n"));
570
+ }
571
+ text.push_str("});\n");
572
+ }
573
+ text.push_str(&format!("module.exports = __toCommonJS({exports});\n"));
574
+ }
575
+ for record in &self.records {
576
+ match record {
577
+ Record::Require { name, source, to_esm } => {
578
+ let name = record_name(name);
579
+ let source = js_string(source);
580
+ if *to_esm {
581
+ text.push_str(&format!("var {name} = __toESM(require({source}));\n"));
582
+ } else {
583
+ text.push_str(&format!("var {name} = require({source});\n"));
584
+ }
585
+ }
586
+ Record::ReExport { source } => {
587
+ let exports = self.exports_name.as_deref().expect("export * has an exports object");
588
+ text.push_str(&format!("__reExport({exports}, require({}), module.exports);\n", js_string(source)));
589
+ }
590
+ }
591
+ }
592
+ if let Some(name) = self.import_meta_name {
593
+ text.push_str(&format!("const {name} = {{}};\n"));
594
+ }
595
+ if wrap {
596
+ self.wrap_commonjs_body(allocator, program, &text);
597
+ return;
598
+ }
599
+ if text.is_empty() {
600
+ return;
601
+ }
602
+ let prologue = parse_statements(allocator, text);
603
+ program.body.splice(0..0, prologue);
604
+ }
605
+
606
+ /// `var require_stdin = __commonJS({ "<stdin>"(exports, module) { body } }); export default require_stdin();`,
607
+ /// with the module's imports left in front.
608
+ fn wrap_commonjs_body(&mut self, allocator: &'a Allocator, program: &mut Program<'a>, prologue: &str) {
609
+ let (mut imports, mut body): (Vec<_>, Vec<_>) = program
610
+ .body
611
+ .take_in(&allocator)
612
+ .into_iter()
613
+ .partition(|s| matches!(s, Statement::ImportDeclaration(_)));
614
+ let mut text = prologue.to_string();
615
+ let name = self.wrapper_name.as_deref().expect("a wrapped module has a wrapper name");
616
+ let [exports, module] = &self.wrapper_params;
617
+ text.push_str(&format!(
618
+ "var {name} = __commonJS({{\n \"<stdin>\"({exports}, {module}) {{\n }}\n}});\nexport default {name}();\n"
619
+ ));
620
+ let mut generated = parse_statements(allocator, text);
621
+ // The wrapper's `var` is the second-to-last statement.
622
+ let wrapper = generated.len() - 2;
623
+ if let Statement::VariableDeclaration(var) = &mut generated[wrapper]
624
+ && let Some(Expression::CallExpression(call)) = &mut var.declarations[0].init
625
+ && let Some(Argument::ObjectExpression(object)) = call.arguments.first_mut()
626
+ && let Some(ObjectPropertyKind::ObjectProperty(property)) = object.properties.first_mut()
627
+ && let Expression::FunctionExpression(function) = &mut property.value
628
+ && let Some(function_body) = &mut function.body
629
+ {
630
+ function_body.statements.extend(body.drain(..));
631
+ }
632
+ let mut statements = ArenaVec::with_capacity_in(imports.len() + generated.len(), &allocator);
633
+ let helpers_len = generated.len() - 2;
634
+ let mut generated = generated.into_iter();
635
+ statements.extend(generated.by_ref().take(helpers_len));
636
+ statements.extend(imports.drain(..));
637
+ statements.extend(generated);
638
+ program.body = statements;
639
+ }
640
+
641
+ /// An assignment to an imported binding writes its record's property,
642
+ /// which throws as the assignment would have; esbuild warns, and so do we.
643
+ fn import_target(
644
+ &mut self,
645
+ ident: &IdentifierReference<'a>,
646
+ ctx: &mut TraverseCtx<'a>,
647
+ ) -> Option<SimpleAssignmentTarget<'a>> {
648
+ let binding = ident
649
+ .reference_id
650
+ .get()
651
+ .and_then(|id| ctx.scoping().get_reference(id).symbol_id())
652
+ .and_then(|symbol| self.bindings.get(&symbol))
653
+ .cloned()?;
654
+ self.warnings.push(
655
+ OxcDiagnostic::warn(format!("This assignment will throw because \"{}\" is an import", ident.name))
656
+ .with_label(ident.span),
657
+ );
658
+ match binding_member(ident.span, &binding, ctx) {
659
+ Expression::StaticMemberExpression(member) => Some(SimpleAssignmentTarget::StaticMemberExpression(member)),
660
+ Expression::ComputedMemberExpression(member) => Some(SimpleAssignmentTarget::ComputedMemberExpression(member)),
661
+ _ => None,
662
+ }
663
+ }
664
+
665
+ fn rewrite_identifier(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) {
666
+ let Expression::Identifier(ident) = expr else { return };
667
+ let Some(binding) = ident
668
+ .reference_id
669
+ .get()
670
+ .and_then(|id| ctx.scoping().get_reference(id).symbol_id())
671
+ .and_then(|symbol| self.bindings.get(&symbol))
672
+ else {
673
+ return;
674
+ };
675
+ let span = ident.span;
676
+ let member = binding_member(span, binding, ctx);
677
+ // Called as a function or a tag, the binding is read off its record
678
+ // without becoming the receiver: `this` stays undefined, as in ESM.
679
+ *expr = if matches!(ctx.parent(), Ancestor::CallExpressionCallee(_) | Ancestor::TaggedTemplateExpressionTag(_)) {
680
+ let zero = Expression::new_numeric_literal(SPAN, 0.0, None, NumberBase::Decimal, ctx);
681
+ Expression::new_sequence_expression(span, [zero, member], ctx)
682
+ } else {
683
+ member
684
+ };
685
+ }
686
+
687
+ fn import_meta(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) {
688
+ let Expression::ImportMeta(meta) = expr else { return };
689
+ if self.options.format != Format::Cjs && self.options.import_meta {
690
+ return;
691
+ }
692
+ let span = meta.span;
693
+ let name = match self.import_meta_name {
694
+ Some(name) => name,
695
+ None => {
696
+ let allocator = ctx.allocator();
697
+ let names = self.names.get_or_insert_with(|| Names::new(ctx.scoping()));
698
+ let name = names.generate("import_meta", ctx.scoping_mut(), allocator);
699
+ let ident = Ident::from_str_in(&name, ctx);
700
+ self.import_meta_name = Some(ident);
701
+ ident
702
+ }
703
+ };
704
+ self.warnings.push(
705
+ OxcDiagnostic::warn(if self.options.format == Format::Cjs {
706
+ "\"import.meta\" is not available with the \"cjs\" output format and will be empty"
707
+ } else {
708
+ "\"import.meta\" is not available in the configured target environment and will be empty"
709
+ })
710
+ .with_label(span),
711
+ );
712
+ *expr = Expression::new_identifier(span, name, ctx);
713
+ }
714
+
715
+ /// `import(x)` → `Promise.resolve().then(() => __toESM(require(x)))`.
716
+ fn lower_dynamic_import(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) {
717
+ if self.options.dynamic_import {
718
+ return;
719
+ }
720
+ let Expression::ImportExpression(import) = expr else { return };
721
+ let span = import.span;
722
+ let allocator = ctx.allocator();
723
+ let source = import.source.take_in(&allocator);
724
+ let mut lowered = parse_expression(allocator, "Promise.resolve().then(() => __toESM(require(0)))");
725
+ if let Expression::CallExpression(then) = &mut lowered
726
+ && let Some(Argument::ArrowFunctionExpression(arrow)) = then.arguments.first_mut()
727
+ && let ArrowFunctionBody::CallExpression(to_esm) = &mut arrow.body
728
+ && let Some(Argument::CallExpression(require)) = to_esm.arguments.first_mut()
729
+ && let Some(argument) = require.arguments.first_mut()
730
+ {
731
+ *argument = Argument::from(source);
732
+ }
733
+ if let Expression::CallExpression(then) = &mut lowered {
734
+ then.span = span;
735
+ }
736
+ *expr = lowered;
737
+ }
738
+ }
739
+
740
+ impl<'a> Traverse<'a, ()> for ModulePass<'a> {
741
+ fn enter_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) {
742
+ match expr {
743
+ Expression::Identifier(_) if !self.bindings.is_empty() => self.rewrite_identifier(expr, ctx),
744
+ Expression::ImportMeta(_) => self.import_meta(expr, ctx),
745
+ // A CommonJS module's `this` is its `exports`, imports or not; the
746
+ // wrapper is called without a receiver, so it says so (esbuild too).
747
+ Expression::ThisExpression(this) if self.wrap_commonjs && this_is_module_level(ctx) => {
748
+ let exports = Ident::from_str_in(&self.wrapper_params[0], ctx);
749
+ *expr = Expression::new_identifier(this.span, exports, ctx);
750
+ }
751
+ Expression::ThisExpression(this) if self.is_esm && this_is_module_level(ctx) => {
752
+ let span = this.span;
753
+ let zero = Expression::new_numeric_literal(SPAN, 0.0, None, NumberBase::Decimal, ctx);
754
+ *expr = Expression::new_unary_expression(span, UnaryOperator::Void, zero, ctx);
755
+ }
756
+ _ => {}
757
+ }
758
+ }
759
+
760
+ // On exit: the lowering's arrow function has no scope of its own to walk
761
+ // into, and the source it wraps has had its own uses rewritten.
762
+ fn exit_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) {
763
+ match expr {
764
+ Expression::ImportExpression(import) => {
765
+ // esbuild reads an import path written as a template with
766
+ // nothing substituted as the string it is, and prints it so;
767
+ // so does a CommonJS output's `require(`x`)`, below.
768
+ template_as_string(&mut import.source, ctx);
769
+ self.lower_dynamic_import(expr, ctx);
770
+ }
771
+ Expression::CallExpression(call)
772
+ if self.options.format == Format::Cjs
773
+ && call.arguments.len() == 1
774
+ && matches!(&call.callee, Expression::Identifier(id) if id.name == "require"
775
+ && id.reference_id.get().is_some_and(|r| ctx.scoping().get_reference(r).symbol_id().is_none())) =>
776
+ {
777
+ if let Some(argument) = call.arguments[0].as_expression_mut() {
778
+ template_as_string(argument, ctx);
779
+ }
780
+ }
781
+ _ => {}
782
+ }
783
+ }
784
+
785
+ fn enter_simple_assignment_target(
786
+ &mut self,
787
+ target: &mut SimpleAssignmentTarget<'a>,
788
+ ctx: &mut TraverseCtx<'a>,
789
+ ) {
790
+ let SimpleAssignmentTarget::AssignmentTargetIdentifier(ident) = target else { return };
791
+ if let Some(member) = self.import_target(ident, ctx) {
792
+ *target = member;
793
+ }
794
+ }
795
+
796
+ /// `({ a } = o)` with `a` imported: `({ a: import_x.a } = o)`.
797
+ fn enter_assignment_target_property(
798
+ &mut self,
799
+ property: &mut AssignmentTargetProperty<'a>,
800
+ ctx: &mut TraverseCtx<'a>,
801
+ ) {
802
+ let AssignmentTargetProperty::AssignmentTargetPropertyIdentifier(shorthand) = property else { return };
803
+ let Some(member) = self.import_target(&shorthand.binding, ctx) else { return };
804
+ let span = shorthand.span;
805
+ let name = PropertyKey::new_static_identifier(shorthand.binding.span, shorthand.binding.name, ctx);
806
+ let binding = match shorthand.init.take() {
807
+ Some(init) => AssignmentTargetMaybeDefault::new_assignment_target_with_default(span, member.into(), init, ctx),
808
+ None => member.into(),
809
+ };
810
+ *property = AssignmentTargetProperty::new_assignment_target_property_property(span, name, binding, false, ctx);
811
+ }
812
+
813
+ fn enter_function(&mut self, _: &mut Function<'a>, _: &mut TraverseCtx<'a>) {
814
+ self.function_depth += 1;
815
+ }
816
+
817
+ fn exit_function(&mut self, _: &mut Function<'a>, _: &mut TraverseCtx<'a>) {
818
+ self.function_depth -= 1;
819
+ }
820
+
821
+ fn enter_arrow_function_expression(&mut self, _: &mut ArrowFunctionExpression<'a>, _: &mut TraverseCtx<'a>) {
822
+ self.function_depth += 1;
823
+ }
824
+
825
+ fn exit_arrow_function_expression(&mut self, _: &mut ArrowFunctionExpression<'a>, _: &mut TraverseCtx<'a>) {
826
+ self.function_depth -= 1;
827
+ }
828
+
829
+ fn enter_await_expression(&mut self, expr: &mut AwaitExpression<'a>, _: &mut TraverseCtx<'a>) {
830
+ if self.function_depth == 0 && self.top_level_await.is_none() {
831
+ self.top_level_await = Some(expr.span);
832
+ }
833
+ }
834
+
835
+ fn enter_for_of_statement(&mut self, stmt: &mut ForOfStatement<'a>, _: &mut TraverseCtx<'a>) {
836
+ if stmt.r#await && self.function_depth == 0 && self.top_level_await.is_none() {
837
+ self.top_level_await = Some(Span::new(stmt.span.start + 4, stmt.span.start + 9));
838
+ }
839
+ }
840
+
841
+ fn enter_variable_declaration(&mut self, decl: &mut VariableDeclaration<'a>, _: &mut TraverseCtx<'a>) {
842
+ if decl.kind == VariableDeclarationKind::AwaitUsing && self.function_depth == 0 && self.top_level_await.is_none() {
843
+ self.top_level_await = Some(decl.span);
844
+ }
845
+ }
846
+ }
847
+
848
+ /// Whether the program awaits at its top level (outside every function).
849
+ pub fn has_top_level_await(program: &Program<'_>) -> bool {
850
+ struct Finder(bool);
851
+ impl<'a> oxc::ast_visit::Visit<'a> for Finder {
852
+ fn visit_function(&mut self, _: &Function<'a>, _: oxc::semantic::ScopeFlags) {}
853
+ fn visit_arrow_function_expression(&mut self, _: &ArrowFunctionExpression<'a>) {}
854
+ fn visit_await_expression(&mut self, _: &AwaitExpression<'a>) {
855
+ self.0 = true;
856
+ }
857
+ fn visit_for_of_statement(&mut self, it: &ForOfStatement<'a>) {
858
+ self.0 |= it.r#await;
859
+ oxc::ast_visit::walk::walk_for_of_statement(self, it);
860
+ }
861
+ fn visit_variable_declaration(&mut self, it: &VariableDeclaration<'a>) {
862
+ self.0 |= it.kind == VariableDeclarationKind::AwaitUsing;
863
+ oxc::ast_visit::walk::walk_variable_declaration(self, it);
864
+ }
865
+ }
866
+ let mut finder = Finder(false);
867
+ oxc::ast_visit::Visit::visit_program(&mut finder, program);
868
+ finder.0
869
+ }
870
+
871
+ /// Whether the module uses CommonJS's `name` (`module` or `exports`): reads
872
+ /// it as a global, or uses a top-level `var`/`function` of that name, which
873
+ /// in a CommonJS module is the wrapper's parameter (a `let` is not).
874
+ fn reads_commonjs_name(scoping: &Scoping, name: &str) -> bool {
875
+ if scoping.root_unresolved_references().contains_key(name) {
876
+ return true;
877
+ }
878
+ scoping.get_root_binding(name.into()).is_some_and(|symbol| {
879
+ let flags = scoping.symbol_flags(symbol);
880
+ (flags.is_function_scoped_declaration() || flags.is_function())
881
+ && !scoping.get_resolved_reference_ids(symbol).is_empty()
882
+ })
883
+ }
884
+
885
+ /// Whether `this` here is the module's: no function, class field
886
+ /// initializer or static block lies between it and the top level (a class's
887
+ /// computed keys, `extends` and decorators evaluate outside the class).
888
+ fn this_is_module_level(ctx: &TraverseCtx<'_>) -> bool {
889
+ !ctx.ancestors().any(|ancestor| {
890
+ matches!(
891
+ ancestor,
892
+ Ancestor::FunctionParams(_)
893
+ | Ancestor::FunctionBody(_)
894
+ | Ancestor::PropertyDefinitionValue(_)
895
+ | Ancestor::AccessorPropertyValue(_)
896
+ | Ancestor::StaticBlockBody(_)
897
+ )
898
+ })
899
+ }
900
+
901
+ /// A template with nothing substituted, as the string literal it evaluates to.
902
+ fn template_as_string<'a>(expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) {
903
+ if let Expression::TemplateLiteral(template) = expr
904
+ && template.expressions.is_empty()
905
+ && !template.quasis[0].lone_surrogates
906
+ && let Some(cooked) = template.quasis[0].value.cooked
907
+ {
908
+ *expr = Expression::new_string_literal(template.span, cooked, None, ctx);
909
+ }
910
+ }
911
+
912
+ /// `record.property`, or `record["property"]` for a name that is not an identifier.
913
+ fn binding_member<'a>(span: Span, binding: &ImportBinding<'a>, ctx: &mut TraverseCtx<'a>) -> Expression<'a> {
914
+ let object = match binding.record {
915
+ RecordName::Symbol(symbol) => {
916
+ ctx.create_bound_ident_expr(SPAN, binding.record_ident, symbol, oxc::semantic::ReferenceFlags::Read)
917
+ }
918
+ RecordName::Generated(_) => Expression::new_identifier(SPAN, binding.record_ident, ctx),
919
+ };
920
+ if is_identifier_name(&binding.property) {
921
+ let property = IdentifierName::new(SPAN, binding.property, ctx);
922
+ Expression::new_static_member_expression(span, object, property, false, ctx)
923
+ } else {
924
+ let key = Expression::new_string_literal(SPAN, binding.property.as_arena_str(), None, ctx);
925
+ Expression::new_computed_member_expression(span, object, key, false, ctx)
926
+ }
927
+ }
928
+
929
+ fn member_text(object: &str, property: &str) -> String {
930
+ if is_identifier_name(property) { format!("{object}.{property}") } else { format!("{object}[{}]", js_string(property)) }
931
+ }
932
+
933
+ /// A double-quoted JavaScript string literal.
934
+ fn js_string(value: &str) -> String {
935
+ let mut out = String::with_capacity(value.len() + 2);
936
+ out.push('"');
937
+ for c in value.chars() {
938
+ match c {
939
+ '"' => out.push_str("\\\""),
940
+ '\\' => out.push_str("\\\\"),
941
+ '\n' => out.push_str("\\n"),
942
+ '\r' => out.push_str("\\r"),
943
+ '\u{2028}' => out.push_str("\\u2028"),
944
+ '\u{2029}' => out.push_str("\\u2029"),
945
+ c if (c as u32) < 0x20 => out.push_str(&format!("\\x{:02X}", c as u32)),
946
+ c => out.push(c),
947
+ }
948
+ }
949
+ out.push('"');
950
+ out
951
+ }
952
+
953
+ /// Parse generated statements into the module's arena, without positions:
954
+ /// they have no place in the source, so neither comments nor source maps may
955
+ /// attach to them.
956
+ fn parse_statements<'a>(allocator: &'a Allocator, text: String) -> ArenaVec<'a, Statement<'a>> {
957
+ let text = allocator.alloc_str(&text);
958
+ let mut parsed = Parser::new(allocator, text, SourceType::mjs()).parse();
959
+ debug_assert!(parsed.diagnostics.is_empty(), "generated code parses: {text}");
960
+ ZeroSpans.visit_program(&mut parsed.program);
961
+ parsed.program.body
962
+ }
963
+
964
+ fn parse_expression<'a>(allocator: &'a Allocator, text: &'static str) -> Expression<'a> {
965
+ let mut statements = parse_statements(allocator, text.to_string());
966
+ match statements.pop() {
967
+ Some(Statement::ExpressionStatement(statement)) => statement.unbox().expression,
968
+ _ => unreachable!("an expression statement"),
969
+ }
970
+ }
971
+
972
+ struct ZeroSpans;
973
+
974
+ impl<'a> VisitMut<'a> for ZeroSpans {
975
+ fn visit_span(&mut self, span: &mut Span) {
976
+ *span = SPAN;
977
+ }
978
+ }