mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 04:08:41 +00:00
perf(transformer): parse options from comments only once (#6152)
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.
This commit is contained in:
parent
54c1c53e69
commit
788e444c1f
5 changed files with 32 additions and 53 deletions
|
|
@ -87,7 +87,7 @@ impl<'a> Transformer<'a> {
|
|||
}
|
||||
|
||||
pub fn build_with_symbols_and_scopes(
|
||||
self,
|
||||
mut self,
|
||||
symbols: SymbolTable,
|
||||
scopes: ScopeTree,
|
||||
program: &mut Program<'a>,
|
||||
|
|
@ -95,8 +95,10 @@ impl<'a> Transformer<'a> {
|
|||
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),
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
///
|
||||
|
|
@ -14,23 +16,32 @@ 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,
|
||||
|
|
@ -38,11 +49,16 @@ fn update_options_with_comment(options: &mut JsxOptions, comment: &Comment, sour
|
|||
}
|
||||
// @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());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
///
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,8 +5,6 @@ use serde::{
|
|||
Deserialize, Deserializer,
|
||||
};
|
||||
|
||||
use crate::context::TransformCtx;
|
||||
|
||||
fn default_for_jsx_pragma() -> Cow<'static, str> {
|
||||
Cow::Borrowed("React.createElement")
|
||||
}
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Reference in a new issue