fix(parser): add support for empty module declaration (#2834)

Should be merged after #2829, Tried a few times to get it done with
graphite stacking but found no success. I guess it either doesn't work
with forks or It is just a skill issue since I'm not familiar with it.

closes: #2829
closes: #2830

---------

Co-authored-by: Dmytro Maretskyi <maretskii@gmail.com>
This commit is contained in:
Ali Rezvani 2024-03-27 09:18:03 +03:30 committed by GitHub
parent f6391f9b43
commit b76b02d019
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 38 additions and 20 deletions

View file

@ -697,7 +697,7 @@ pub struct TSModuleDeclaration<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub id: TSModuleDeclarationName<'a>,
pub body: TSModuleDeclarationBody<'a>,
pub body: Option<TSModuleDeclarationBody<'a>>,
/// The keyword used to define this module declaration
/// ```text
/// namespace Foo {}

View file

@ -1273,7 +1273,7 @@ impl<'a> AstBuilder<'a> {
&self,
span: Span,
id: TSModuleDeclarationName<'a>,
body: TSModuleDeclarationBody<'a>,
body: Option<TSModuleDeclarationBody<'a>>,
kind: TSModuleDeclarationKind,
modifiers: Modifiers<'a>,
) -> Box<'a, TSModuleDeclaration<'a>> {

View file

@ -2493,10 +2493,13 @@ pub mod walk {
TSModuleDeclarationName::StringLiteral(lit) => visitor.visit_string_literal(lit),
}
match &decl.body {
TSModuleDeclarationBody::TSModuleDeclaration(decl) => {
Some(TSModuleDeclarationBody::TSModuleDeclaration(decl)) => {
visitor.visit_ts_module_declaration(decl);
}
TSModuleDeclarationBody::TSModuleBlock(block) => visitor.visit_ts_module_block(block),
Some(TSModuleDeclarationBody::TSModuleBlock(block)) => {
visitor.visit_ts_module_block(block);
}
None => {}
}
visitor.leave_node(kind);
}

View file

@ -2694,10 +2694,13 @@ pub mod walk_mut {
TSModuleDeclarationName::StringLiteral(lit) => visitor.visit_string_literal(lit),
}
match &mut decl.body {
TSModuleDeclarationBody::TSModuleDeclaration(decl) => {
Some(TSModuleDeclarationBody::TSModuleDeclaration(decl)) => {
visitor.visit_ts_module_declaration(decl);
}
TSModuleDeclarationBody::TSModuleBlock(block) => visitor.visit_ts_module_block(block),
Some(TSModuleDeclarationBody::TSModuleBlock(block)) => {
visitor.visit_ts_module_block(block);
}
None => {}
}
visitor.leave_node(kind);
}

View file

@ -539,12 +539,12 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for TSModuleDeclaration<'a> {
p.wrap_quote(name, |p, _| p.print_str(name.as_bytes()));
p.print_hard_space();
match &self.body {
TSModuleDeclarationBody::TSModuleDeclaration(body) => {
Some(TSModuleDeclarationBody::TSModuleDeclaration(body)) => {
p.print_block_start(body.span.start);
body.gen(p, ctx);
p.print_block_end(body.span.end);
}
TSModuleDeclarationBody::TSModuleBlock(body) => {
Some(TSModuleDeclarationBody::TSModuleBlock(body)) => {
p.print_block_start(body.span.start);
for item in &body.body {
p.print_semicolon_if_needed();
@ -553,6 +553,7 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for TSModuleDeclaration<'a> {
p.print_semicolon_if_needed();
p.print_block_end(body.span.end);
}
None => {}
}
if MINIFY {
p.print_semicolon();

View file

@ -406,8 +406,8 @@ impl<'a> ParserImpl<'a> {
#[cfg(test)]
mod test {
use oxc_ast::CommentKind;
use std::path::Path;
use super::*;
@ -436,6 +436,15 @@ mod test {
assert_eq!(ret.errors.first().unwrap().to_string(), "Flow is not supported");
}
#[test]
fn ts_module_declaration() {
let allocator = Allocator::default();
let source_type = SourceType::from_path(Path::new("module.ts")).unwrap();
let source = "declare module 'test'\n";
let ret = Parser::new(&allocator, source, source_type).parse();
assert_eq!(ret.errors.len(), 0);
}
#[test]
fn directives() {
let allocator = Allocator::default();

View file

@ -212,13 +212,11 @@ impl<'a> ParserImpl<'a> {
let mut statements = self.ast.new_vec();
if self.at(Kind::LCurly) {
self.expect(Kind::LCurly)?;
self.expect(Kind::LCurly)?;
while !self.eat(Kind::RCurly) && !self.at(Kind::Eof) {
let stmt = self.parse_ts_module_item()?;
statements.push(stmt);
}
while !self.eat(Kind::RCurly) && !self.at(Kind::Eof) {
let stmt = self.parse_ts_module_item()?;
statements.push(stmt);
}
Ok(self.ast.ts_module_block(self.end_span(span), statements))
@ -243,11 +241,14 @@ impl<'a> ParserImpl<'a> {
let span = self.start_span();
let decl =
self.parse_ts_namespace_or_module_declaration_body(span, kind, Modifiers::empty())?;
TSModuleDeclarationBody::TSModuleDeclaration(decl)
} else {
Some(TSModuleDeclarationBody::TSModuleDeclaration(decl))
} else if self.at(Kind::LCurly) {
let block = self.parse_ts_module_block()?;
self.asi()?;
TSModuleDeclarationBody::TSModuleBlock(block)
Some(TSModuleDeclarationBody::TSModuleBlock(block))
} else {
self.asi()?;
None
};
Ok(self.ast.ts_module_declaration(self.end_span(span), id, body, kind, modifiers))

View file

@ -661,13 +661,14 @@ impl<'a> TypeScript<'a> {
block: &mut Box<'a, TSModuleDeclaration<'a>>,
) -> Statement<'a> {
let body_statements = match &mut block.body {
TSModuleDeclarationBody::TSModuleDeclaration(decl) => {
Some(TSModuleDeclarationBody::TSModuleDeclaration(decl)) => {
let transformed_module_block = self.transform_ts_module_block(decl);
self.ctx.ast.new_vec_single(transformed_module_block)
}
TSModuleDeclarationBody::TSModuleBlock(ts_module_block) => {
Some(TSModuleDeclarationBody::TSModuleBlock(ts_module_block)) => {
self.ctx.ast.move_statement_vec(&mut ts_module_block.body)
}
None => self.ctx.ast.new_vec(),
};
let name = block.id.name();