Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 40 additions & 31 deletions src/js_parser/p.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3985,44 +3985,53 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool> P<'a, TYPESCRIPT, SCAN_O
stmt: &mut S::Import,
) -> Result<(), crate::Error> {
if let Some(loader) = path.loader {
self.import_records.items_mut()[stmt.import_record_index as usize].loader =
Some(loader);

if loader == options::Loader::Sqlite || loader == options::Loader::SqliteEmbedded {
// arena-owned `StoreSlice<ClauseItem>` valid for parser 'a.
for item in stmt.items.iter() {
// `ClauseItem.alias` is an arena-owned `StoreStr` valid for 'a.
let alias: &[u8] = item.alias.slice();
if !(alias == b"default" || alias == b"db") {
self.log().add_error(
Some(self.source),
item.name.loc,
b"sqlite imports only support the \"default\" or \"db\" imports",
);
break;
}
}
} else if loader == options::Loader::File || loader == options::Loader::Text {
// arena-owned `StoreSlice<ClauseItem>` valid for parser 'a.
for item in stmt.items.iter() {
// `ClauseItem.alias` is an arena-owned `StoreStr` valid for 'a.
if item.alias.slice() != b"default" {
self.log().add_error(
Some(self.source),
item.name.loc,
b"This loader type only supports the \"default\" import",
);
break;
}
}
}
// In an import clause, `ClauseItem.alias` is the name imported from the module.
self.set_import_record_loader(
stmt.import_record_index,
loader,
stmt.items
.iter()
.map(|item| (item.alias.slice(), item.name.loc)),
);
} else if path.import_tag == bun_ast::ImportRecordTag::BakeResolveToSsrGraph {
self.import_records.items_mut()[stmt.import_record_index as usize].tag =
path.import_tag;
}
Ok(())
}

/// Applies a `with { type: "..." }` attribute to the import record of an `import` or
/// `export ... from` statement. `imported_names` are the names the statement imports from
/// the module; loaders whose modules only have a fixed set of exports reject other names.
#[cold]
pub(crate) fn set_import_record_loader<'n>(
&mut self,
import_record_index: u32,
loader: options::Loader,
imported_names: impl Iterator<Item = (&'n [u8], bun_ast::Loc)>,
) {
self.import_records.items_mut()[import_record_index as usize].loader = Some(loader);

let (exported_names, error): (&[&[u8]], &[u8]) = match loader {
options::Loader::Sqlite | options::Loader::SqliteEmbedded => (
&[b"default", b"db"],
b"sqlite imports only support the \"default\" or \"db\" imports",
),
options::Loader::File | options::Loader::Text => (
&[b"default"],
b"This loader type only supports the \"default\" import",
),
_ => return,
};

for (name, loc) in imported_names {
if !exported_names.contains(&name) {
self.log().add_error(Some(self.source), loc, error);
break;
}
}
}

pub(crate) fn create_default_name(&mut self, loc: bun_ast::Loc) -> js_ast::LocRef {
let identifier: &'a [u8] = {
let s = format!("{}_default", self.source.path.name().fmt_identifier());
Expand Down
32 changes: 21 additions & 11 deletions src/js_parser/parse/parse_stmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1231,13 +1231,8 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool> P<'a, TYPESCRIPT, SCAN_O
namespace_ref = p.store_name_in_ref(name);
}

let import_record_index = p.add_import_record(
ImportKind::Stmt,
path.loc,
path.text,
// TODO: import assertions
// path.assertions
);
let import_record_index =
p.add_import_record(ImportKind::Stmt, path.loc, path.text);

if path.is_macro {
p.log().add_error(
Expand All @@ -1249,8 +1244,11 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool> P<'a, TYPESCRIPT, SCAN_O
p.log().add_error(
Some(p.source),
loc,
b"cannot use export statement with \"type\" attribute",
b"cannot use export statement with \"bunBakeGraph\" attribute",
);
} else if let Some(loader) = path.loader {
// `export *` imports no particular name, so there is nothing to validate.
p.set_import_record_loader(import_record_index, loader, core::iter::empty());
}

if Self::TRACK_SYMBOL_USAGE_DURING_PARSE_PASS {
Expand Down Expand Up @@ -1294,6 +1292,9 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool> P<'a, TYPESCRIPT, SCAN_O
}
}

let import_record_index =
p.add_import_record(ImportKind::Stmt, parsed_path.loc, parsed_path.text);

if parsed_path.is_macro {
p.log().add_error(
Some(p.source),
Expand All @@ -1304,12 +1305,21 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool> P<'a, TYPESCRIPT, SCAN_O
p.log().add_error(
Some(p.source),
loc,
b"export from cannot be used with \"type\" attribute",
b"export from cannot be used with \"bunBakeGraph\" attribute",
);
} else if let Some(loader) = parsed_path.loader {
// In `export { a as b } from "x"`, `original_name` ("a") is the name
// imported from the module; `alias` ("b") is the name re-exported.
p.set_import_record_loader(
import_record_index,
loader,
export_clause
.clauses
.iter()
.map(|item| (item.original_name.slice(), item.name.loc)),
);
}

let import_record_index =
p.add_import_record(ImportKind::Stmt, parsed_path.loc, parsed_path.text);
let path_name = fs::PathName::init(parsed_path.text);
let namespace_ref = {
use std::io::Write as _;
Expand Down
Loading
Loading