Skip to content

Commit

Permalink
feat: generate namespace decl
Browse files Browse the repository at this point in the history
  • Loading branch information
hyf0 committed Feb 6, 2024
1 parent d33e019 commit 62768fe
Show file tree
Hide file tree
Showing 153 changed files with 1,394 additions and 71 deletions.
8 changes: 4 additions & 4 deletions crates/rolldown/src/bundler/ast_scanner/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,10 @@ impl<'ast> AstScanner<'ast> {
let namespace_ref: SymbolRef =
(idx, symbol_table.create_symbol(name.into(), scope.root_scope_id())).into();
result.repr_name = repr_name;
// The first StmtInfo is to represent the namespace binding.
result
.stmt_infos
.add_stmt_info(StmtInfo { declared_symbols: vec![namespace_ref], ..Default::default() });

// The first `StmtInfo` is used to represent the namespace binding statement
result.stmt_infos.push(StmtInfo::default());

Self {
idx,
scope,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ impl<'ast, 'me: 'ast> VisitMut<'ast> for Finalizer<'me, 'ast> {

let old_body = program.body.take_in(self.alloc);

if matches!(self.ctx.module.exports_kind, ExportsKind::Esm) {
program.body.extend(self.generate_namespace_variable_declaration());
}

old_body.into_iter().for_each(|mut top_stmt| {
if let Some(import_decl) = top_stmt.as_import_declaration() {
let rec_id = self.ctx.module.imports[&import_decl.span];
Expand Down
64 changes: 64 additions & 0 deletions crates/rolldown/src/bundler/finalizer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,24 @@ where
None
}

fn generate_finalized_expr_for_symbol_ref(&self, symbol_ref: SymbolRef) -> ast::Expression<'ast> {
let canonical_ref = self.ctx.symbols.par_canonical_ref_for(symbol_ref);
let symbol = self.ctx.symbols.get(canonical_ref);

if let Some(ns_alias) = &symbol.namespace_alias {
let canonical_ns_name = self.canonical_name_for(ns_alias.namespace_ref);
let prop_name = &ns_alias.property_name;
let access_expr = self
.snippet
.literal_prop_access_member_expr_expr(canonical_ns_name.clone(), prop_name.clone());

access_expr
} else {
let canonical_name = self.canonical_name_for(canonical_ref);
self.snippet.id_ref_expr(canonical_name.clone())
}
}

fn convert_decl_to_assignment(
&self,
decl: &mut ast::Declaration<'ast>,
Expand Down Expand Up @@ -183,4 +201,50 @@ where
_ => unreachable!("TypeScript code should be preprocessed"),
}
}

fn generate_namespace_variable_declaration(&self) -> [ast::Statement<'ast>; 2] {
let ns_name = self.canonical_name_for(self.ctx.module.namespace_symbol);
// construct `var ns_name = {}`
let namespace_decl_stmt = self
.snippet
.var_decl_stmt(ns_name.clone(), ast::Expression::ObjectExpression(Dummy::dummy(self.alloc)));

// construct `__export(ns_name, { prop_name: () => returned, ... })`
let mut arg_obj_expr = ast::ObjectExpression::dummy(self.alloc);
arg_obj_expr
.properties
.reserve(self.ctx.linking_info.exclude_ambiguous_sorted_resolved_exports.len());
self.ctx.linking_info.sorted_exports().for_each(|(export, resolved_export)| {
// prop_name: () => returned
let prop_name = export;
let returned = self.generate_finalized_expr_for_symbol_ref(resolved_export.symbol_ref);
arg_obj_expr.properties.push(ast::ObjectPropertyKind::ObjectProperty(
ast::ObjectProperty {
key: ast::PropertyKey::Identifier(
self.snippet.id_name(prop_name.clone()).into_in(self.alloc),
),
value: self.snippet.only_return_arrow_expr(returned),
..Dummy::dummy(self.alloc)
}
.into_in(self.alloc),
));
});
let mut export_call_expr =
self.snippet.call_expr(self.canonical_name_for_runtime("__export").clone());
export_call_expr
.arguments
.push(ast::Argument::Expression(self.snippet.id_ref_expr(ns_name.clone())));
export_call_expr.arguments.push(ast::Argument::Expression(ast::Expression::ObjectExpression(
arg_obj_expr.into_in(self.alloc),
)));
let export_call_stmt = ast::Statement::ExpressionStatement(
ast::ExpressionStatement {
expression: ast::Expression::CallExpression(export_call_expr.into_in(self.alloc)),
..Dummy::dummy(self.alloc)
}
.into_in(self.alloc),
);

[namespace_decl_stmt, export_call_stmt]
}
}
25 changes: 24 additions & 1 deletion crates/rolldown/src/bundler/stages/link_stage.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::ptr::addr_of;

use index_vec::IndexVec;
use rolldown_common::{EntryPoint, ExportsKind, ImportKind, ModuleId, WrapKind};
use rolldown_common::{EntryPoint, ExportsKind, ImportKind, ModuleId, StmtInfo, WrapKind};
use rolldown_error::BuildError;
use rolldown_oxc::OxcProgram;
use rustc_hash::FxHashSet;
Expand Down Expand Up @@ -60,6 +60,28 @@ impl LinkStage {
}
}

fn create_exports_for_modules(&mut self) {
self.modules.iter_mut().for_each(|module| {
let Module::Normal(module) = module else {
return;
};

// Create a StmtInfo for the namespace statement
let namespace_stmt_info = StmtInfo {
stmt_idx: None,
declared_symbols: vec![module.namespace_symbol],
referenced_symbols: vec![self.runtime.resolve_symbol("__export")],
side_effect: false,
..Default::default()
};

let _namespace_stmt_id = module.stmt_infos.add_stmt_info(namespace_stmt_info);

// We don't create actual ast nodes for the namespace statement here. It will be deferred
// to the finalize stage.
});
}

#[tracing::instrument(skip_all)]
pub fn link(mut self) -> LinkStageOutput {
self.sort_modules();
Expand All @@ -70,6 +92,7 @@ impl LinkStage {
ImportExportLinker::new(&mut self).link(&mut linking_infos);
self.linking_infos = linking_infos;
tracing::debug!("linking modules {:#?}", self.linking_infos);
self.create_exports_for_modules();
self.reference_needed_symbols();
// FIXME: should move `linking_info.facade_stmt_infos` into a separate field
for (id, linking_info) in self.linking_infos.iter_mut_enumerated() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,39 @@ input_file: crates/rolldown/tests/esbuild/default/ambiguous_reexport_msg
## entry_js.mjs

```js
import { __export } from "./_rolldown_runtime.mjs";
// a.js
var a_ns = {};
__export(a_ns, {
a:() => a,
x:() => x$1
});
let a = 1, x$1 = 2;
// b.js
var b_ns = {};
__export(b_ns, {
b:() => b,
x:() => b
});
let b = 3;
// c.js
var c_ns = {};
__export(c_ns, {
c:() => c,
x:() => x
});
let c = 4, x = 5;
// entry.js
var entry_ns = {};
__export(entry_ns, {
a:() => a,
b:() => b,
c:() => c
});
export { a, b, c };
```
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ input_file: crates/rolldown/tests/esbuild/default/arrow_fn_scope
## entry_js.mjs

```js
import { __export } from "./_rolldown_runtime.mjs";
// entry.js
tests = {
0:(x$1=y$2 => x$1 + y$2, y$1) => x$1 + y$1,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ import "http://example.com/code.js";
import "https://example.com/code.js";
import "//example.com/code.js";
import "data:application/javascript;base64,ZXhwb3J0IGRlZmF1bHQgMTIz";
import { __export } from "./_rolldown_runtime.mjs";
// entry.js
var entry_ns = {};
__export(entry_ns, {});
```
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,14 @@ input_file: crates/rolldown/tests/esbuild/default/avoid_tdz
## entry_js.mjs

```js
import { __export } from "./_rolldown_runtime.mjs";
// entry.js
var entry_ns = {};
__export(entry_ns, {
Bar:() => Bar,
bar:() => bar
});
class Foo {
static foo=new Foo();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ input_file: crates/rolldown/tests/esbuild/default/await_import_inside_try
## entry_js.mjs

```js
import { __export } from "./_rolldown_runtime.mjs";
// entry.js
async function main(name) {
try{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,30 @@ input_file: crates/rolldown/tests/esbuild/default/common_js_from_es6
## entry_js.mjs

```js
import { __esm, __toCommonJS } from "./_rolldown_runtime.mjs";
import { __esm, __export, __toCommonJS } from "./_rolldown_runtime.mjs";
// foo.js
function foo$1() {
return 'foo';
}
var foo_ns;
var init_foo = __esm(() => {
foo_ns = {};
__export(foo_ns, {
foo:() => foo$1
});
});
// bar.js
function bar$1() {
return 'bar';
}
var bar_ns;
var init_bar = __esm(() => {
bar_ns = {};
__export(bar_ns, {
bar:() => bar$1
});
});
// entry.js
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ input_file: crates/rolldown/tests/esbuild/default/const_with_let
## entry_js.mjs

```js
import { __export } from "./_rolldown_runtime.mjs";
// entry.js
const a = 1;
console.log(a);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ input_file: crates/rolldown/tests/esbuild/default/duplicate_entry_point
## entry_js-3.mjs

```js
import { __export } from "./_rolldown_runtime.mjs";
// entry.js
console.log(123);
```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@ input_file: crates/rolldown/tests/esbuild/default/empty_export_clause_bundle_as_
## entry_js.mjs

```js
import { __esm, __toCommonJS } from "./_rolldown_runtime.mjs";
import { __esm, __export, __toCommonJS } from "./_rolldown_runtime.mjs";
// types.mjs
var types_ns;
var init_types = __esm(() => {
types_ns = {};
__export(types_ns, {});
});
// entry.js
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ input_file: crates/rolldown/tests/esbuild/default/es6_from_common_js
## entry_js.mjs

```js
import { __commonJS, __toESM } from "./_rolldown_runtime.mjs";
import { __commonJS, __export, __toESM } from "./_rolldown_runtime.mjs";
// foo.js
var require_foo = __commonJS((exports, module) => {
Expand All @@ -25,6 +25,8 @@ var require_bar = __commonJS((exports, module) => {
});
// entry.js
var entry_ns = {};
__export(entry_ns, {});
var import_foo = require_foo();
var import_bar = require_bar();
console.log((0,import_foo.foo)(), (0,import_bar.bar)());
Expand Down
14 changes: 14 additions & 0 deletions crates/rolldown/tests/esbuild/default/export_chain/artifacts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,26 @@ input_file: crates/rolldown/tests/esbuild/default/export_chain
## entry_js.mjs

```js
import { __export } from "./_rolldown_runtime.mjs";
// bar.js
var bar_ns = {};
__export(bar_ns, {
c:() => c
});
const c = 123;
// foo.js
var foo_ns = {};
__export(foo_ns, {
b:() => c
});
// entry.js
var entry_ns = {};
__export(entry_ns, {
a:() => c
});
export { c as a };
```
Loading

0 comments on commit 62768fe

Please sign in to comment.