diff --git a/crates/oxc_transformer/src/jsx/comments.rs b/crates/oxc_transformer/src/jsx/comments.rs index ad2f0f94fc399..769ebac99b013 100644 --- a/crates/oxc_transformer/src/jsx/comments.rs +++ b/crates/oxc_transformer/src/jsx/comments.rs @@ -6,17 +6,21 @@ use oxc_ast::Comment; use crate::{JsxOptions, JsxRuntime, TransformCtx, TypeScriptOptions}; -/// Scan through all comments and find the following pragmas: +/// Scan through leading comments and find the following pragmas: /// /// * @jsx Preact.h /// * @jsxRuntime classic / automatic /// * @jsxImportSource custom-jsx-library /// * @jsxFrag Preact.Fragment /// +/// The caller should only pass comments before the first statement, +/// since pragmas are file-level directives. This is aligned with TypeScript and SWC. +/// +/// /// The comment does not need to be a JSDoc comment, /// otherwise `JSDoc` could be used instead. /// -/// This behavior is aligned with ESBuild. +/// Multiple pragmas in a single comment are accepted (aligned with esbuild). /// Babel is less liberal - it doesn't accept multiple pragmas in a single line /// e.g. `/** @jsx h @jsxRuntime classic */` /// diff --git a/crates/oxc_transformer/src/lib.rs b/crates/oxc_transformer/src/lib.rs index 4c052cef99313..e872fc5268466 100644 --- a/crates/oxc_transformer/src/lib.rs +++ b/crates/oxc_transformer/src/lib.rs @@ -11,7 +11,7 @@ use oxc_allocator::{Allocator, TakeIn, Vec as ArenaVec}; use oxc_ast::{AstBuilder, ast::*}; use oxc_diagnostics::OxcDiagnostic; use oxc_semantic::Scoping; -use oxc_span::SPAN; +use oxc_span::{GetSpan, SPAN}; use oxc_traverse::{ReusableTraverseCtx, Traverse, traverse_mut_with_ctx}; // Core @@ -139,9 +139,15 @@ impl<'a> Transformer<'a> { self.state.source_type = program.source_type; self.state.source_text = program.source_text; - if program.source_type.is_jsx() { + if program.source_type.is_jsx() + && let Some(first_statement) = program.body.first() + { + // Only scan comments before the first statement for pragmas, + // since pragmas are file-level directives (aligned with TypeScript and SWC). + let leading_comments_end = + program.comments.partition_point(|c| c.span.start < first_statement.span().start); jsx::update_options_with_comments( - &program.comments, + &program.comments[..leading_comments_end], &mut self.typescript, &mut self.jsx, &self.state,