Skip to content

Commit

Permalink
perf(transformer): parse options from comments only once (#6152)
Browse files Browse the repository at this point in the history
Both React and TypeScript transforms were repeating the same work - iterating through comments to find `@jsx` pragmas.

Instead, perform this search only once, using the optimized pragma search introduced in #6151.
  • Loading branch information
overlookmotel committed Oct 1, 2024
1 parent 54c1c53 commit 788e444
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 53 deletions.
6 changes: 4 additions & 2 deletions crates/oxc_transformer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,16 +87,18 @@ impl<'a> Transformer<'a> {
}

pub fn build_with_symbols_and_scopes(
self,
mut self,
symbols: SymbolTable,
scopes: ScopeTree,
program: &mut Program<'a>,
) -> TransformerReturn {
let allocator = self.allocator;
let ast_builder = AstBuilder::new(allocator);

react::update_options_with_comments(&mut self.options, &self.ctx);

let mut transformer = TransformerImpl {
x0_typescript: TypeScript::new(self.options.typescript, &self.ctx),
x0_typescript: TypeScript::new(&self.options.typescript, &self.ctx),
x1_react: React::new(self.options.react, ast_builder, &self.ctx),
x2_es2021: ES2021::new(self.options.es2021, &self.ctx),
x2_es2020: ES2020::new(self.options.es2020, &self.ctx),
Expand Down
30 changes: 23 additions & 7 deletions crates/oxc_transformer/src/react/comments.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use std::borrow::Cow;

use oxc_ast::{Comment, CommentKind};
use oxc_syntax::identifier::is_irregular_whitespace;

use crate::{JsxOptions, JsxRuntime, TransformCtx};
use crate::{JsxRuntime, TransformCtx, TransformOptions};

/// Scan through all comments and find the following pragmas:
///
Expand All @@ -14,35 +16,49 @@ use crate::{JsxOptions, JsxRuntime, TransformCtx};
/// otherwise `JSDoc` could be used instead.
///
/// This behavior is aligned with Babel.
pub(crate) fn update_options_with_comments(options: &mut JsxOptions, ctx: &TransformCtx) {
pub(crate) fn update_options_with_comments(options: &mut TransformOptions, ctx: &TransformCtx) {
for comment in ctx.trivias.comments() {
update_options_with_comment(options, comment, ctx.source_text);
}
}

fn update_options_with_comment(options: &mut JsxOptions, comment: &Comment, source_text: &str) {
fn update_options_with_comment(
options: &mut TransformOptions,
comment: &Comment,
source_text: &str,
) {
let Some((keyword, remainder)) = find_jsx_pragma(comment, source_text) else { return };

match keyword {
// @jsx
"" => {
options.pragma = Some(remainder.to_string());
// Don't set React option unless React transform is enabled
// otherwise can cause error in `ReactJsx::new`
if options.react.jsx_plugin || options.react.development {
options.react.pragma = Some(remainder.to_string());
}
options.typescript.jsx_pragma = Cow::from(remainder.to_string());
}
// @jsxRuntime
"Runtime" => {
options.runtime = match remainder {
options.react.runtime = match remainder {
"classic" => JsxRuntime::Classic,
"automatic" => JsxRuntime::Automatic,
_ => return,
};
}
// @jsxImportSource
"ImportSource" => {
options.import_source = Some(remainder.to_string());
options.react.import_source = Some(remainder.to_string());
}
// @jsxFrag
"Frag" => {
options.pragma_frag = Some(remainder.to_string());
// Don't set React option unless React transform is enabled
// otherwise can cause error in `ReactJsx::new`
if options.react.jsx_plugin || options.react.development {
options.react.pragma_frag = Some(remainder.to_string());
}
options.typescript.jsx_pragma_frag = Cow::from(remainder.to_string());
}
_ => {}
}
Expand Down
3 changes: 1 addition & 2 deletions crates/oxc_transformer/src/react/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ pub use self::{
};
use crate::TransformCtx;

use comments::update_options_with_comments;
pub(crate) use comments::update_options_with_comments;

/// [Preset React](https://babel.dev/docs/babel-preset-react)
///
Expand All @@ -45,7 +45,6 @@ pub struct React<'a, 'ctx> {
impl<'a, 'ctx> React<'a, 'ctx> {
pub fn new(mut options: JsxOptions, ast: AstBuilder<'a>, ctx: &'ctx TransformCtx<'a>) -> Self {
if options.jsx_plugin || options.development {
update_options_with_comments(&mut options, ctx);
options.conform();
}
let JsxOptions {
Expand Down
9 changes: 4 additions & 5 deletions crates/oxc_transformer/src/typescript/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,14 @@ pub struct TypeScript<'a, 'ctx> {
}

impl<'a, 'ctx> TypeScript<'a, 'ctx> {
pub fn new(mut options: TypeScriptOptions, ctx: &'ctx TransformCtx<'a>) -> Self {
options.update_with_comments(ctx);
pub fn new(options: &TypeScriptOptions, ctx: &'ctx TransformCtx<'a>) -> Self {
Self {
ctx,
annotations: TypeScriptAnnotations::new(&options, ctx),
annotations: TypeScriptAnnotations::new(options, ctx),
r#enum: TypeScriptEnum::new(),
namespace: TypeScriptNamespace::new(&options, ctx),
namespace: TypeScriptNamespace::new(options, ctx),
module: TypeScriptModule::new(ctx),
rewrite_extensions: TypeScriptRewriteExtensions::new(&options),
rewrite_extensions: TypeScriptRewriteExtensions::new(options),
}
}
}
Expand Down
37 changes: 0 additions & 37 deletions crates/oxc_transformer/src/typescript/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ use serde::{
Deserialize, Deserializer,
};

use crate::context::TransformCtx;

fn default_for_jsx_pragma() -> Cow<'static, str> {
Cow::Borrowed("React.createElement")
}
Expand Down Expand Up @@ -60,41 +58,6 @@ pub struct TypeScriptOptions {
pub rewrite_import_extensions: Option<RewriteExtensionsMode>,
}

impl TypeScriptOptions {
/// Scan through all comments and find the following pragmas
///
/// * @jsx React.createElement
/// * @jsxFrag React.Fragment
///
/// The comment does not need to be a jsdoc,
/// otherwise `JSDoc` could be used instead.
///
/// This behavior is aligned with babel.
pub(crate) fn update_with_comments(&mut self, ctx: &TransformCtx) {
for comment in ctx.trivias.comments() {
let mut comment = comment.span.source_text(ctx.source_text).trim_start();
// strip leading jsdoc comment `*` and then whitespaces
while let Some(cur_comment) = comment.strip_prefix('*') {
comment = cur_comment.trim_start();
}
// strip leading `@`
let Some(comment) = comment.strip_prefix('@') else { continue };

// read jsxFrag
if let Some(pragma_frag) = comment.strip_prefix("jsxFrag").map(str::trim) {
self.jsx_pragma_frag = Cow::from(pragma_frag.to_string());
continue;
}

// Put this condition at the end to avoid breaking @jsxXX
// read jsx
if let Some(pragma) = comment.strip_prefix("jsx").map(str::trim) {
self.jsx_pragma = Cow::from(pragma.to_string());
}
}
}
}

impl Default for TypeScriptOptions {
fn default() -> Self {
Self {
Expand Down

0 comments on commit 788e444

Please sign in to comment.