diff --git a/backend/parsers/windmill-parser-ts/src/lib.rs b/backend/parsers/windmill-parser-ts/src/lib.rs index 399e13aa0e..04dd345b2f 100644 --- a/backend/parsers/windmill-parser-ts/src/lib.rs +++ b/backend/parsers/windmill-parser-ts/src/lib.rs @@ -255,6 +255,28 @@ pub fn parse_deno_signature( let mut symbol_table: HashMap = HashMap::new(); for item in ast { + // Check for named exports (e.g., export { preprocessor } from "./other") + if let ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(named_export)) = &item { + if !has_preprocessor { + for specifier in &named_export.specifiers { + if let swc_ecma_ast::ExportSpecifier::Named(spec) = specifier { + let export_name = match &spec.exported { + Some(swc_ecma_ast::ModuleExportName::Ident(ident)) => ident.sym.as_ref(), + Some(swc_ecma_ast::ModuleExportName::Str(s)) => s.value.as_ref(), + None => match &spec.orig { + swc_ecma_ast::ModuleExportName::Ident(ident) => ident.sym.as_ref(), + swc_ecma_ast::ModuleExportName::Str(s) => s.value.as_ref(), + }, + }; + if export_name == "preprocessor" { + has_preprocessor = true; + break; + } + } + } + } + } + if let ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl { decl, .. })) | ModuleItem::Stmt(Stmt::Decl(decl)) = item { diff --git a/backend/parsers/windmill-parser-ts/tests/tests.rs b/backend/parsers/windmill-parser-ts/tests/tests.rs index f5a3404df8..1d9fbda6ef 100644 --- a/backend/parsers/windmill-parser-ts/tests/tests.rs +++ b/backend/parsers/windmill-parser-ts/tests/tests.rs @@ -685,4 +685,76 @@ mod tests { } ); } + + #[test] + fn test_parse_with_preprocessor_reexport() { + // Test case for issue #6894: preprocessor re-export should be detected + let code = r#" + export { preprocessor } from "./extract_user_info_from_jwt_token"; + + export async function main(param: string) { + return param; + } + "#; + let sig = parse_deno_signature(code, false, false, None).unwrap(); + assert_eq!( + sig, + MainArgSignature { + star_args: false, + star_kwargs: false, + args: vec![Arg { + name: "param".to_string(), + otyp: None, + typ: Typ::Str(None), + default: None, + has_default: false, + oidx: None, + }], + no_main_func: Some(false), + has_preprocessor: Some(true), + } + ); + } + + #[test] + fn test_parse_with_preprocessor_reexport_renamed() { + // Test case for renamed re-exports + let code = r#" + export { preprocessor as preprocessor } from "./other"; + + export async function main(param: string) { + return param; + } + "#; + let sig = parse_deno_signature(code, false, false, None).unwrap(); + assert_eq!(sig.has_preprocessor, Some(true)); + } + + #[test] + fn test_parse_with_preprocessor_among_other_exports() { + // Test case where preprocessor is one of many exports + let code = r#" + export { foo, preprocessor, bar } from "./utils"; + + export async function main(param: string) { + return param; + } + "#; + let sig = parse_deno_signature(code, false, false, None).unwrap(); + assert_eq!(sig.has_preprocessor, Some(true)); + } + + #[test] + fn test_parse_without_preprocessor_other_exports() { + // Test case where there are exports but no preprocessor + let code = r#" + export { foo, bar } from "./utils"; + + export async function main(param: string) { + return param; + } + "#; + let sig = parse_deno_signature(code, false, false, None).unwrap(); + assert_eq!(sig.has_preprocessor, Some(false)); + } }