in lib/Parser/JSParserImpl-flow.cpp [373:526]
Optional<ESTree::Node *> JSParserImpl::parseDeclareModuleFlow(SMLoc start) {
assert(check(moduleIdent_));
advance(JSLexer::GrammarContext::Type);
if (checkAndEat(TokenKind::period, JSLexer::GrammarContext::Type)) {
if (!checkAndEat(exportsIdent_, JSLexer::GrammarContext::Type)) {
error(tok_->getSourceRange(), "expected module.exports declaration");
return None;
}
SMLoc annotStart = tok_->getStartLoc();
if (!eat(
TokenKind::colon,
JSLexer::GrammarContext::Type,
"in module.exports declaration",
"start of declaration",
start))
return None;
auto optType = parseTypeAnnotationFlow(annotStart);
if (!optType)
return None;
eatSemi(true);
return setLocation(
start,
getPrevTokenEndLoc(),
new (context_) ESTree::DeclareModuleExportsNode(*optType));
}
// declare module Identifier {[opt]
// ^
ESTree::Node *id = nullptr;
if (check(TokenKind::string_literal)) {
id = setLocation(
tok_,
tok_,
new (context_) ESTree::StringLiteralNode(tok_->getStringLiteral()));
} else {
if (!need(
TokenKind::identifier,
"in module declaration",
"start of declaration",
start))
return None;
id = setLocation(
tok_,
tok_,
new (context_)
ESTree::IdentifierNode(tok_->getIdentifier(), nullptr, false));
}
advance(JSLexer::GrammarContext::Type);
// declare module Identifier {
// ^
SMLoc bodyStart = tok_->getStartLoc();
if (!eat(
TokenKind::l_brace,
JSLexer::GrammarContext::Type,
"in module declaration",
"start of declaration",
start))
return None;
UniqueString *kind = nullptr;
ESTree::NodeList declarations{};
while (!check(TokenKind::r_brace)) {
if (check(TokenKind::rw_import)) {
// 'import' can be bare without a 'declare' before it.
auto optImport = parseImportDeclaration();
if (!optImport)
return None;
ESTree::ImportDeclarationNode *import = *optImport;
if (import->_importKind == valueIdent_) {
error(
import->getSourceRange(),
"imports within a `declare module` body must always be "
"`import type` or `import typeof`");
}
declarations.push_back(*import);
continue;
}
if (!check(declareIdent_)) {
error(
tok_->getSourceRange(),
"expected 'declare' in module declaration body");
return None;
}
SMLoc declarationStart = advance(JSLexer::GrammarContext::Type).Start;
auto optDecl =
parseDeclareFLow(declarationStart, AllowDeclareExportType::Yes);
if (!optDecl)
return None;
ESTree::Node *decl = *optDecl;
switch (decl->getKind()) {
case ESTree::NodeKind::DeclareModuleExports:
if (kind != nullptr && kind != commonJSIdent_) {
error(
decl->getSourceRange(),
"cannot use CommonJS export in ES module");
}
kind = commonJSIdent_;
break;
case ESTree::NodeKind::DeclareExportDeclaration:
if (llvh::dyn_cast_or_null<ESTree::InterfaceDeclarationNode>(
llvh::cast<ESTree::DeclareExportDeclarationNode>(decl)
->_declaration)) {
// declare export interface can show up in either module kind.
// Ignore it.
break;
}
if (llvh::dyn_cast_or_null<ESTree::TypeAliasNode>(
llvh::cast<ESTree::DeclareExportDeclarationNode>(decl)
->_declaration)) {
// declare export type can show up in either module kind.
// Ignore it.
break;
}
if (kind != nullptr && kind != esIdent_) {
error(
decl->getSourceRange(),
"cannot use ESM export in CommonJS module");
}
kind = esIdent_;
break;
case ESTree::NodeKind::DeclareExportAllDeclaration:
if (kind != nullptr && kind != esIdent_) {
error(
decl->getSourceRange(),
"cannot use ESM export in CommonJS module");
}
kind = esIdent_;
break;
default:
break;
}
declarations.push_back(*decl);
}
SMLoc bodyEnd = advance(JSLexer::GrammarContext::Type).End;
ESTree::Node *body = setLocation(
bodyStart,
bodyEnd,
new (context_) ESTree::BlockStatementNode(std::move(declarations)));
if (kind == nullptr) {
// Default to CommonJS if we weren't able to figure it out based on
// declarations themselves.
kind = commonJSIdent_;
}
return setLocation(
start, body, new (context_) ESTree::DeclareModuleNode(id, body, kind));
}