use std::collections::HashSet;
use oxc_allocator::Vec as ArenaVec;
use oxc_ast::ast::{JSXChild, Statement};
use oxc_span::SourceType;
use vue_compiler_core::{
parser::{ElemProp, Element},
util::{find_prop, prop_finder},
};
use crate::parser::{
ParserImpl, RetParse, RetParseExt, error, modules::Merge, parse::SourceLocatonSpan,
};
impl<'a> ParserImpl<'a> {
pub fn parse_script(&mut self, node: Element<'a>) -> RetParse<Option<JSXChild<'a>>> {
let mut source_types: HashSet<&str> = HashSet::new();
let lang = find_prop(&node, "lang")
.and_then(|p| match p.get_ref() {
ElemProp::Attr(p) => p.value.as_ref().map(|value| value.content.raw),
ElemProp::Dir(_) => None,
})
.unwrap_or("js");
source_types.insert(lang);
if source_types.len() > 1 {
error::multiple_script_tags(&mut self.errors, &source_types);
return RetParse::panic();
}
self.source_type = if lang.starts_with("js") {
SourceType::jsx()
} else if lang.starts_with("ts") {
SourceType::tsx()
} else {
error::unexpected_script_lang(&mut self.errors, lang);
return RetParse::panic();
};
if let Some(child) = node.children.first() {
let span = child.get_location().span();
let source = span.source_text(self.source_text);
let Some((mut body, module_record)) = self.oxc_parse(
source,
SourceType::from_extension(lang).unwrap(),
span.start as usize,
) else {
return Ok(None);
};
let is_setup = prop_finder(&node, "setup").allow_empty().find().is_some();
if is_setup {
self.module_record.merge_imports(module_record);
let mut imports: ArenaVec<Statement<'a>> = self.ast.vec();
let mut statements: ArenaVec<Statement<'a>> = self.ast.vec();
for statement in body {
match statement {
Statement::ImportDeclaration(_) => imports.push(statement),
_ => statements.push(statement),
}
}
imports.append(&mut self.statements);
self.statements = imports;
self.setup = statements;
} else {
self.module_record.merge(module_record);
self.statements.append(&mut body);
}
}
RetParse::success(Some(self.parse_element(node, Some(self.ast.vec())).0))
}
}