use oxc_ast::ast::{ImportDeclaration, ImportDeclarationSpecifier};
use super::error::EngineError;
pub const SPECIFIER: &str = "zeb/react";
pub const EXPORTS: &[&str] = &[
"h",
"createElement",
"Fragment",
"ErrorBoundary",
"jsx",
"jsxs",
"jsxDEV",
"render",
"hydrate",
"renderToString",
"createContext",
"createPortal",
"forwardRef",
"memo",
"useState",
"useReducer",
"useSyncExternalStore",
"useRef",
"useMemo",
"useCallback",
"useContext",
"useId",
"useEffect",
"useLayoutEffect",
"useImperativeHandle",
"usePageState",
"useRouter",
"usePathname",
"useSearchParams",
"Link",
"cx",
];
const PLATFORM_GLOBALS: &[&str] = &[
"usePageState",
"useRouter",
"usePathname",
"useSearchParams",
"Link",
"cx",
];
pub fn lower_import(import: &ImportDeclaration<'_>) -> Result<String, EngineError> {
if import.import_kind.is_type() {
return Ok(String::new());
}
let mut bindings = String::new();
if let Some(specifiers) = &import.specifiers {
for specifier in specifiers {
let local = specifier.local().name.as_str();
let value = match specifier {
ImportDeclarationSpecifier::ImportSpecifier(named) => {
if named.import_kind.is_type() {
continue;
}
let imported = named.imported.name();
let name = imported.as_str();
if name == "default" {
"globalThis.__zebReact".to_string()
} else {
if !EXPORTS.contains(&name) {
return Err(EngineError::new(
"RWE_REACT_EXPORT",
format!("'{name}' is not exported by zeb/react"),
));
}
if PLATFORM_GLOBALS.contains(&name) {
format!("globalThis.{name}")
} else {
format!("globalThis.__zebReact[\"{name}\"]")
}
}
}
ImportDeclarationSpecifier::ImportNamespaceSpecifier(_) => {
let helpers = PLATFORM_GLOBALS
.iter()
.map(|name| format!("\"{name}\": globalThis[\"{name}\"]"))
.collect::<Vec<_>>()
.join(", ");
format!(
"Object.freeze({{ ...globalThis.__zebReact, {helpers}, default: globalThis.__zebReact }})"
)
}
_ => "globalThis.__zebReact".to_string(),
};
bindings.push_str(&format!("const {local} = {value};\n"));
}
}
Ok(bindings)
}