feat(span): remove From<String> and From<Cow> API because they create memory leak (#2628)

closes #2621
This commit is contained in:
Boshen 2024-03-06 20:38:21 +08:00 committed by GitHub
parent 240ff19675
commit 4f9dd98a97
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 142 additions and 153 deletions

View file

@ -1,7 +1,7 @@
use std::{cell::Cell, fmt, hash::Hash};
use oxc_allocator::{Box, Vec};
use oxc_span::{Atom, SourceType, Span};
use oxc_span::{Atom, CompactStr, SourceType, Span};
use oxc_syntax::{
operator::{
AssignmentOperator, BinaryOperator, LogicalOperator, UnaryOperator, UpdateOperator,
@ -212,7 +212,7 @@ impl<'a> Expression<'a> {
}
}
pub fn is_specific_member_access(&'a self, object: &str, property: &str) -> bool {
pub fn is_specific_member_access(&self, object: &str, property: &str) -> bool {
match self.get_inner_expression() {
Expression::MemberExpression(expr) => expr.is_specific_member_access(object, property),
Expression::ChainExpression(chain) => {
@ -466,19 +466,22 @@ pub enum PropertyKey<'a> {
}
impl<'a> PropertyKey<'a> {
pub fn static_name(&self) -> Option<Atom<'a>> {
pub fn static_name(&self) -> Option<CompactStr> {
match self {
Self::Identifier(ident) => Some(ident.name.clone()),
Self::Identifier(ident) => Some(ident.name.to_compact_str()),
Self::PrivateIdentifier(_) => None,
Self::Expression(expr) => match expr {
Expression::StringLiteral(lit) => Some(lit.value.clone()),
Expression::RegExpLiteral(lit) => Some(Atom::from(lit.regex.to_string())),
Expression::NumericLiteral(lit) => Some(Atom::from(lit.value.to_string())),
Expression::BigintLiteral(lit) => Some(lit.raw.clone()),
Expression::StringLiteral(lit) => Some(lit.value.to_compact_str()),
Expression::RegExpLiteral(lit) => Some(lit.regex.to_string().into()),
Expression::NumericLiteral(lit) => Some(lit.value.to_string().into()),
Expression::BigintLiteral(lit) => Some(lit.raw.to_compact_str()),
Expression::NullLiteral(_) => Some("null".into()),
Expression::TemplateLiteral(lit) => {
lit.expressions.is_empty().then(|| lit.quasi()).flatten().cloned()
}
Expression::TemplateLiteral(lit) => lit
.expressions
.is_empty()
.then(|| lit.quasi())
.flatten()
.map(Atom::to_compact_str),
_ => None,
},
}
@ -496,16 +499,16 @@ impl<'a> PropertyKey<'a> {
matches!(self, Self::PrivateIdentifier(_))
}
pub fn private_name(&self) -> Option<Atom<'a>> {
pub fn private_name(&self) -> Option<&Atom<'a>> {
match self {
Self::PrivateIdentifier(ident) => Some(ident.name.clone()),
Self::PrivateIdentifier(ident) => Some(&ident.name),
_ => None,
}
}
pub fn name(&self) -> Option<Atom<'a>> {
pub fn name(&self) -> Option<CompactStr> {
if self.is_private_identifier() {
self.private_name()
self.private_name().map(Atom::to_compact_str)
} else {
self.static_name()
}
@ -758,7 +761,7 @@ impl<'a> CallExpression<'a> {
}
}
pub fn is_symbol_or_symbol_for_call(&'a self) -> bool {
pub fn is_symbol_or_symbol_for_call(&self) -> bool {
// TODO: is 'Symbol' reference to global object
match &self.callee {
Expression::Identifier(id) => id.name == "Symbol",
@ -2017,7 +2020,7 @@ impl<'a> ClassElement<'a> {
}
}
pub fn static_name(&self) -> Option<Atom> {
pub fn static_name(&self) -> Option<CompactStr> {
match self {
Self::TSIndexSignature(_) | Self::StaticBlock(_) => None,
Self::MethodDefinition(def) => def.key.static_name(),

View file

@ -130,7 +130,7 @@ impl GetMethod for ClassElement<'_> {
fn get_method(&self) -> Option<Method> {
match self {
ClassElement::MethodDefinition(def) => def.key.static_name().map(|name| Method {
name: name.to_compact_str(),
name,
r#static: def.r#static,
call_signature: false,
kind: get_kind_from_key(&def.key),
@ -145,7 +145,7 @@ impl GetMethod for TSSignature<'_> {
fn get_method(&self) -> Option<Method> {
match self {
TSSignature::TSMethodSignature(sig) => sig.key.static_name().map(|name| Method {
name: name.to_compact_str(),
name,
r#static: false,
call_signature: false,
kind: get_kind_from_key(&sig.key),

View file

@ -264,7 +264,7 @@ impl<'a> Compressor<'a> {
let right_string = get_string_value(right)?;
// let value = left_string.to_owned().
let value = left_string + right_string;
let string_literal = StringLiteral::new(span, Atom::from(value));
let string_literal = StringLiteral::new(span, self.ast.new_atom(&value));
Some(self.ast.literal_string_expression(string_literal))
},

View file

@ -1,12 +1,14 @@
//! Declare symbol for `BindingIdentifier`s
use std::borrow::Cow;
#[allow(clippy::wildcard_imports)]
use oxc_ast::ast::*;
use oxc_ast::{
syntax_directed_operations::{BoundNames, IsSimpleParameterList},
AstKind,
};
use oxc_span::{Atom, SourceType};
use oxc_span::SourceType;
use crate::{scope::ScopeFlags, symbol::SymbolFlags, SemanticBuilder};
@ -343,9 +345,9 @@ impl<'a> Binder for TSEnumMember<'a> {
return;
}
let name = match &self.id {
TSEnumMemberName::Identifier(id) => id.name.clone(),
TSEnumMemberName::StringLiteral(s) => s.value.clone(),
TSEnumMemberName::NumericLiteral(n) => Atom::from(n.value.to_string()),
TSEnumMemberName::Identifier(id) => Cow::Borrowed(id.name.as_str()),
TSEnumMemberName::StringLiteral(s) => Cow::Borrowed(s.value.as_str()),
TSEnumMemberName::NumericLiteral(n) => Cow::Owned(n.value.to_string()),
TSEnumMemberName::ComputedPropertyName(_) => panic!("TODO: implement"),
};
builder.declare_symbol(

View file

@ -5,7 +5,7 @@ use std::{cell::RefCell, path::PathBuf, rc::Rc, sync::Arc};
#[allow(clippy::wildcard_imports)]
use oxc_ast::{ast::*, AstKind, Trivias, TriviasMap, Visit};
use oxc_diagnostics::Error;
use oxc_span::{Atom, SourceType, Span};
use oxc_span::{CompactStr, SourceType, Span};
use oxc_syntax::{
module_record::{ExportLocalName, ModuleRecord},
operator::AssignmentOperator,
@ -231,7 +231,7 @@ impl<'a> SemanticBuilder<'a> {
pub fn declare_symbol_on_scope(
&mut self,
span: Span,
name: &Atom,
name: &str,
scope_id: ScopeId,
includes: SymbolFlags,
excludes: SymbolFlags,
@ -243,16 +243,16 @@ impl<'a> SemanticBuilder<'a> {
}
let includes = includes | self.current_symbol_flags;
let symbol_id = self.symbols.create_symbol(span, name.clone(), includes, scope_id);
let symbol_id = self.symbols.create_symbol(span, name, includes, scope_id);
self.symbols.add_declaration(self.current_node_id);
self.scope.add_binding(scope_id, name.to_compact_str(), symbol_id);
self.scope.add_binding(scope_id, CompactStr::from(name), symbol_id);
symbol_id
}
pub fn declare_symbol(
&mut self,
span: Span,
name: &Atom,
name: &str,
includes: SymbolFlags,
excludes: SymbolFlags,
) -> SymbolId {
@ -263,14 +263,14 @@ impl<'a> SemanticBuilder<'a> {
&mut self,
scope_id: ScopeId,
span: Span,
name: &Atom,
name: &str,
excludes: SymbolFlags,
report_error: bool,
) -> Option<SymbolId> {
let symbol_id = self.scope.get_binding(scope_id, name)?;
if report_error && self.symbols.get_flag(symbol_id).intersects(excludes) {
let symbol_span = self.symbols.get_span(symbol_id);
self.error(Redeclaration(name.to_compact_str(), symbol_span, span));
self.error(Redeclaration(CompactStr::from(name), symbol_span, span));
}
Some(symbol_id)
}
@ -285,16 +285,15 @@ impl<'a> SemanticBuilder<'a> {
/// Declares a `Symbol` for the node, shadowing previous declarations in the same scope.
pub fn declare_shadow_symbol(
&mut self,
name: &Atom,
name: &str,
span: Span,
scope_id: ScopeId,
includes: SymbolFlags,
) -> SymbolId {
let includes = includes | self.current_symbol_flags;
let symbol_id =
self.symbols.create_symbol(span, name.clone(), includes, self.current_scope_id);
let symbol_id = self.symbols.create_symbol(span, name, includes, self.current_scope_id);
self.symbols.add_declaration(self.current_node_id);
self.scope.get_bindings_mut(scope_id).insert(name.to_compact_str(), symbol_id);
self.scope.get_bindings_mut(scope_id).insert(CompactStr::from(name), symbol_id);
symbol_id
}

View file

@ -5,7 +5,7 @@ use oxc_ast::{
},
AstKind,
};
use oxc_span::GetSpan;
use oxc_span::{Atom, GetSpan};
use oxc_syntax::class::{ClassId, ElementKind};
use crate::{AstNodeId, AstNodes};
@ -57,15 +57,14 @@ impl ClassTableBuilder {
pub fn declare_class_accessor(&mut self, property: &AccessorProperty) {
let is_private = property.key.is_private_identifier();
let name =
if is_private { property.key.private_name() } else { property.key.static_name() };
let name = property.key.name();
if let Some(name) = name {
if let Some(class_id) = self.current_class_id {
self.classes.add_element(
class_id,
Element::new(
name.to_compact_str(),
name,
property.key.span(),
property.r#static,
is_private,
@ -78,15 +77,14 @@ impl ClassTableBuilder {
pub fn declare_class_property(&mut self, property: &PropertyDefinition) {
let is_private = property.key.is_private_identifier();
let name =
if is_private { property.key.private_name() } else { property.key.static_name() };
let name = property.key.name();
if let Some(name) = name {
if let Some(class_id) = self.current_class_id {
self.classes.add_element(
class_id,
Element::new(
name.to_compact_str(),
name,
property.key.span(),
property.r#static,
is_private,
@ -127,14 +125,18 @@ impl ClassTableBuilder {
return;
}
let is_private = method.key.is_private_identifier();
let name = if is_private { method.key.private_name() } else { method.key.static_name() };
let name = if is_private {
method.key.private_name().map(Atom::to_compact_str)
} else {
method.key.static_name()
};
if let Some(name) = name {
if let Some(class_id) = self.current_class_id {
self.classes.add_element(
class_id,
Element::new(
name.to_compact_str(),
name,
method.key.span(),
method.r#static,
is_private,

View file

@ -117,12 +117,12 @@ impl SymbolTable {
pub fn create_symbol(
&mut self,
span: Span,
name: Atom,
name: &str,
flag: SymbolFlags,
scope_id: ScopeId,
) -> SymbolId {
_ = self.spans.push(span);
_ = self.names.push(name.into_compact_str());
_ = self.names.push(CompactStr::from(name));
_ = self.flags.push(flag);
_ = self.scope_ids.push(scope_id);
_ = self.resolved_references.push(vec![]);

View file

@ -141,7 +141,7 @@ impl<'a> SymbolTester<'a> {
pub fn is_exported(mut self) -> Self {
self.test_result = match self.test_result {
Ok(symbol_id) => {
let binding = Atom::from(self.target_symbol_name.clone());
let binding = self.target_symbol_name.clone();
if self.semantic.module_record().exported_bindings.contains_key(binding.as_str())
&& self.semantic.scopes().get_root_binding(&binding) == Some(symbol_id)
{

View file

@ -1,8 +1,4 @@
use std::{
borrow::{Borrow, Cow},
fmt, hash,
ops::Deref,
};
use std::{borrow::Borrow, fmt, hash, ops::Deref};
#[cfg(feature = "serde")]
use serde::{Serialize, Serializer};
@ -82,18 +78,6 @@ impl<'a> From<&'a str> for Atom<'a> {
}
}
impl<'a> From<String> for Atom<'a> {
fn from(s: String) -> Self {
Self::Compact(CompactString::from(s))
}
}
impl<'a> From<Cow<'_, str>> for Atom<'a> {
fn from(s: Cow<'_, str>) -> Self {
Self::Compact(CompactString::from(s))
}
}
impl<'a> Deref for Atom<'a> {
type Target = str;

View file

@ -3,7 +3,7 @@
use std::{collections::HashSet, rc::Rc};
use oxc_ast::{ast::*, AstBuilder};
use oxc_span::{Atom, SPAN};
use oxc_span::{CompactStr, SPAN};
use crate::options::{TransformOptions, TransformTarget};
@ -22,9 +22,9 @@ impl<'a> DuplicateKeys<'a> {
}
pub fn transform_object_expression<'b>(&mut self, obj_expr: &'b mut ObjectExpression<'a>) {
let mut visited_data: HashSet<Atom> = HashSet::new();
let mut visited_getters: HashSet<Atom> = HashSet::new();
let mut visited_setters: HashSet<Atom> = HashSet::new();
let mut visited_data: HashSet<CompactStr> = HashSet::new();
let mut visited_getters: HashSet<CompactStr> = HashSet::new();
let mut visited_setters: HashSet<CompactStr> = HashSet::new();
for property in obj_expr.properties.iter_mut() {
let ObjectPropertyKind::ObjectProperty(obj_property) = property else {
@ -64,7 +64,7 @@ impl<'a> DuplicateKeys<'a> {
if is_duplicate {
obj_property.computed = true;
let string_literal = StringLiteral::new(SPAN, name.clone());
let string_literal = StringLiteral::new(SPAN, self.ast.new_atom(name));
let expr = self.ast.literal_string_expression(string_literal);
obj_property.key = PropertyKey::Expression(expr);
}

View file

@ -19,7 +19,7 @@ use crate::TransformTarget;
/// * <https://babel.dev/docs/babel-plugin-transform-function-name>
/// * <https://github.com/babel/babel/tree/main/packages/babel-plugin-transform-function-name>
pub struct FunctionName<'a> {
_ast: Rc<AstBuilder<'a>>,
ast: Rc<AstBuilder<'a>>,
ctx: TransformerCtx<'a>,
unicode_escapes: bool,
}
@ -31,7 +31,7 @@ impl<'a> FunctionName<'a> {
options: &TransformOptions,
) -> Option<Self> {
(options.target < TransformTarget::ES2015 || options.function_name).then_some(Self {
_ast: ast,
ast,
ctx,
// TODO hook up the plugin
unicode_escapes: true,
@ -45,7 +45,7 @@ impl<'a> FunctionName<'a> {
) = &expr.left
{
if let Some(id) =
create_valid_identifier(target.span, target.name.clone(), self.unicode_escapes)
self.create_valid_identifier(target.span, &target.name, self.unicode_escapes)
{
let scope_id = self.ctx.symbols().get_scope_id_from_span(&target.span);
@ -64,19 +64,11 @@ impl<'a> FunctionName<'a> {
let (id, scope_id) = match &property.key {
PropertyKey::Identifier(ident) => (
create_valid_identifier(
ident.span,
ident.name.clone(),
self.unicode_escapes,
),
self.create_valid_identifier(ident.span, &ident.name, self.unicode_escapes),
self.ctx.symbols().get_scope_id_from_span(&ident.span),
),
PropertyKey::PrivateIdentifier(ident) => (
create_valid_identifier(
ident.span,
ident.name.clone(),
self.unicode_escapes,
),
self.create_valid_identifier(ident.span, &ident.name, self.unicode_escapes),
self.ctx.symbols().get_scope_id_from_span(&ident.span),
),
PropertyKey::Expression(_) => continue,
@ -95,7 +87,7 @@ impl<'a> FunctionName<'a> {
if let BindingPatternKind::BindingIdentifier(ident) = &decl.id.kind {
// Create a new ID instead of cloning to avoid local binding/refs
if let Some(id) =
create_valid_identifier(ident.span, ident.name.clone(), self.unicode_escapes)
self.create_valid_identifier(ident.span, &ident.name, self.unicode_escapes)
{
let scope_id = match ident.symbol_id.get() {
Some(symbol_id) => Some(self.ctx.symbols().get_scope_id(symbol_id)),
@ -133,7 +125,7 @@ impl<'a> FunctionName<'a> {
// If we're shadowing, change the name
if count > 0 {
id.name = Atom::from(format!("{}{}", id.name, count));
id.name = self.ast.new_atom(&format!("{}{}", id.name, count));
}
if func.id.is_none() {
@ -141,37 +133,41 @@ impl<'a> FunctionName<'a> {
}
}
}
}
// https://github.com/babel/babel/blob/main/packages/babel-helper-function-name/src/index.ts
// https://github.com/babel/babel/blob/main/packages/babel-types/src/converters/toBindingIdentifierName.ts#L3
// https://github.com/babel/babel/blob/main/packages/babel-types/src/converters/toIdentifier.ts#L4
#[allow(clippy::unnecessary_wraps)]
fn create_valid_identifier(
span: Span,
atom: Atom,
_unicode_escapes: bool,
) -> Option<BindingIdentifier> {
// NOTE: this regex fails to compile on Rust
// lazy_static! {
// static ref UNICODE_NAME: Regex = Regex::new(r"(?u)[\u{D800}-\u{DFFF}]").unwrap();
// }
// if !unicode_escapes && UNICODE_NAME.is_match(atom.as_str()) {
// return None;
// }
let id = Atom::from(
atom.chars().map(|c| if is_identifier_part(c) { c } else { '_' }).collect::<String>(),
);
let id = if id == "" {
Atom::from("_")
} else if id == "eval" || id == "arguments" || id == "null" || !is_valid_identifier(&id, true) {
Atom::from(format!("_{id}"))
} else {
atom
};
Some(BindingIdentifier::new(span, id))
// https://github.com/babel/babel/blob/main/packages/babel-helper-function-name/src/index.ts
// https://github.com/babel/babel/blob/main/packages/babel-types/src/converters/toBindingIdentifierName.ts#L3
// https://github.com/babel/babel/blob/main/packages/babel-types/src/converters/toIdentifier.ts#L4
#[allow(clippy::unnecessary_wraps)]
fn create_valid_identifier(
&self,
span: Span,
atom: &Atom<'a>,
_unicode_escapes: bool,
) -> Option<BindingIdentifier<'a>> {
// NOTE: this regex fails to compile on Rust
// lazy_static! {
// static ref UNICODE_NAME: Regex = Regex::new(r"(?u)[\u{D800}-\u{DFFF}]").unwrap();
// }
// if !unicode_escapes && UNICODE_NAME.is_match(atom.as_str()) {
// return None;
// }
let id =
atom.chars().map(|c| if is_identifier_part(c) { c } else { '_' }).collect::<String>();
let id = if id.is_empty() {
self.ast.new_atom("_")
} else if id == "eval"
|| id == "arguments"
|| id == "null"
|| !is_valid_identifier(&id, true)
{
self.ast.new_atom(&format!("_{id}"))
} else {
atom.clone()
};
Some(BindingIdentifier::new(span, id))
}
}

View file

@ -1,4 +1,4 @@
use std::{collections::HashSet, rc::Rc};
use std::{borrow::Cow, collections::HashSet, rc::Rc};
use oxc_ast::{ast::*, AstBuilder};
use oxc_span::{Atom, SPAN};
@ -30,6 +30,7 @@ impl<'a> ClassStaticBlock<'a> {
.iter()
.filter_map(ClassElement::property_key)
.filter_map(PropertyKey::private_name)
.cloned()
.collect();
let mut i = 0;
@ -38,7 +39,7 @@ impl<'a> ClassStaticBlock<'a> {
continue;
};
let static_block_private_id = generate_uid(&private_names, &mut i);
let static_block_private_id = self.generate_uid(&private_names, &mut i);
let key =
PropertyKey::PrivateIdentifier(self.ast.alloc(PrivateIdentifier {
span: SPAN,
@ -107,16 +108,16 @@ impl<'a> ClassStaticBlock<'a> {
self.ast.class_property(r#type, SPAN, key, value, false, true, self.ast.new_vec());
}
}
}
fn generate_uid<'a>(deny_list: &HashSet<Atom<'a>>, i: &mut u32) -> Atom<'a> {
*i += 1;
let mut uid: Atom = if *i == 1 { "_".to_string() } else { format!("_{i}") }.into();
while deny_list.contains(&uid) {
fn generate_uid(&self, deny_list: &HashSet<Atom<'a>>, i: &mut u32) -> Atom<'a> {
*i += 1;
uid = format!("_{i}").into();
}
uid
let mut uid = if *i == 1 { Cow::Borrowed("_") } else { Cow::Owned(format!("_{i}")) };
while deny_list.iter().any(|id| id.as_str() == uid.as_ref()) {
*i += 1;
uid = format!("_{i}").into();
}
self.ast.new_atom(&uid)
}
}

View file

@ -547,9 +547,7 @@ impl<'a> Decorators<'a> {
if def.key.is_private_identifier() && !flag.is_static() {
private_in_expression =
Some(self.get_is_private_function(
def.key.private_name().unwrap().clone(),
));
Some(self.get_is_private_function(def.key.private_name().unwrap()));
}
name = self.get_unique_name(&if def.computed {
@ -846,9 +844,10 @@ impl<'a> Decorators<'a> {
)),
));
if let Some(name) = name {
decorator_elements.push(ArrayExpressionElement::Expression(
self.ast.literal_string_expression(StringLiteral::new(SPAN, name.clone())),
));
decorator_elements
.push(ArrayExpressionElement::Expression(self.ast.literal_string_expression(
StringLiteral::new(SPAN, self.ast.new_atom(&name)),
)));
if key.is_private_identifier() {
if let Some(value) = value {
@ -878,7 +877,7 @@ impl<'a> Decorators<'a> {
SPAN,
self.ast.new_atom("o"),
)),
PrivateIdentifier::new(SPAN, name),
PrivateIdentifier::new(SPAN, self.ast.new_atom(&name)),
false,
);
let params = self.ast.formal_parameters(
@ -969,7 +968,7 @@ impl<'a> Decorators<'a> {
}
// _ => #a in _;
fn get_is_private_function(&self, name: Atom<'a>) -> Expression<'a> {
fn get_is_private_function(&self, name: &Atom<'a>) -> Expression<'a> {
self.ast.arrow_function_expression(
SPAN,
true,
@ -1001,7 +1000,7 @@ impl<'a> Decorators<'a> {
SPAN,
self.ast.private_in_expression(
SPAN,
PrivateIdentifier::new(SPAN, name),
PrivateIdentifier::new(SPAN, name.clone()),
self.ast.identifier_reference_expression(IdentifierReference::new(
SPAN,
self.ast.new_atom("_"),

View file

@ -8,7 +8,7 @@ use oxc_diagnostics::{
miette::{self, Diagnostic},
thiserror::Error,
};
use oxc_span::{Atom, CompactStr, GetSpan, Span, SPAN};
use oxc_span::{CompactStr, GetSpan, Span, SPAN};
use oxc_syntax::{
identifier::{is_irregular_whitespace, is_line_terminator},
xml_entities::XML_ENTITIES,
@ -596,7 +596,7 @@ impl<'a> ReactJsx<'a> {
}
}
JSXAttributeName::NamespacedName(name) => {
let name = Atom::from(name.to_string());
let name = self.ast.new_atom(&name.to_string());
let expr = self.ast.literal_string_expression(StringLiteral::new(SPAN, name));
self.ast.property_key_expression(expr)
}
@ -623,7 +623,7 @@ impl<'a> ReactJsx<'a> {
self.ctx.error(NamespaceDoesNotSupport(name.span));
}
let string_literal = StringLiteral::new(SPAN, Atom::from(name.to_string()));
let string_literal = StringLiteral::new(SPAN, self.ast.new_atom(&name.to_string()));
self.ast.literal_string_expression(string_literal)
}
}
@ -665,7 +665,7 @@ impl<'a> ReactJsx<'a> {
match value {
Some(JSXAttributeValue::StringLiteral(s)) => {
let jsx_text = Self::decode_entities(s.value.as_str());
let literal = StringLiteral::new(s.span, jsx_text.into());
let literal = StringLiteral::new(s.span, self.ast.new_atom(&jsx_text));
self.ast.literal_string_expression(literal)
}
Some(JSXAttributeValue::Element(e)) => {
@ -718,7 +718,7 @@ impl<'a> ReactJsx<'a> {
fn transform_jsx_text(&self, text: &str) -> Option<Expression<'a>> {
Self::fixup_whitespace_and_decode_entities(text).map(|s| {
let s = StringLiteral::new(SPAN, s.into());
let s = StringLiteral::new(SPAN, self.ast.new_atom(&s));
self.ast.literal_string_expression(s)
})
}

View file

@ -60,7 +60,7 @@ impl<'a> RegexpFlags<'a> {
let ident = IdentifierReference::new(SPAN, Atom::from("RegExp"));
let callee = self.ast.identifier_reference_expression(ident);
let pattern = StringLiteral::new(SPAN, regex.pattern.clone());
let flags = StringLiteral::new(SPAN, Atom::from(regex.flags.to_string()));
let flags = StringLiteral::new(SPAN, self.ast.new_atom(&regex.flags.to_string()));
let pattern_literal = self.ast.literal_string_expression(pattern);
let flags_literal = self.ast.literal_string_expression(flags);
let mut arguments = self.ast.new_vec_with_capacity(2);

View file

@ -637,7 +637,10 @@ impl<'a> TypeScript<'a> {
fn get_namespace_arg_name(&mut self, name: &Atom<'a>) -> Atom<'a> {
let count = self.namespace_arg_names.entry(name.clone()).or_insert(0);
*count += 1;
format!("_{name}{}", if *count > 1 { count.to_string() } else { String::new() }).into()
self.ast.new_atom(&format!(
"_{name}{}",
if *count > 1 { count.to_string() } else { String::new() }
))
}
/// ```TypeScript

View file

@ -2,7 +2,7 @@ use std::mem;
use oxc_allocator::Vec;
use oxc_ast::ast::*;
use oxc_span::{Atom, Span};
use oxc_span::Span;
use oxc_syntax::identifier::is_identifier_name;
use crate::context::TransformerCtx;
@ -133,22 +133,22 @@ pub const KEYWORDS: phf::Set<&str> = phf::phf_set![
"delete",
];
pub fn is_valid_identifier(name: &Atom, reserved: bool) -> bool {
if reserved && (KEYWORDS.contains(name.as_str()) || is_strict_reserved_word(name, true)) {
pub fn is_valid_identifier(name: &str, reserved: bool) -> bool {
if reserved && (KEYWORDS.contains(name) || is_strict_reserved_word(name, true)) {
return false;
}
is_identifier_name(name)
}
pub fn is_strict_reserved_word(name: &Atom, in_module: bool) -> bool {
is_reserved_word(name, in_module) || RESERVED_WORD_STRICT.contains(name.as_str())
pub fn is_strict_reserved_word(name: &str, in_module: bool) -> bool {
is_reserved_word(name, in_module) || RESERVED_WORD_STRICT.contains(name)
}
pub fn is_reserved_word(name: &Atom, in_module: bool) -> bool {
(in_module && name.as_str() == "await") || name.as_str() == "enum"
pub fn is_reserved_word(name: &str, in_module: bool) -> bool {
(in_module && name == "await") || name == "enum"
}
/// https://github.com/babel/babel/blob/main/packages/babel-types/src/validators/isValidES3Identifier.ts#L35
pub fn is_valid_es3_identifier(name: &Atom) -> bool {
is_valid_identifier(name, true) && !RESERVED_WORDS_ES3_ONLY.contains(name.as_str())
pub fn is_valid_es3_identifier(name: &str) -> bool {
is_valid_identifier(name, true) && !RESERVED_WORDS_ES3_ONLY.contains(name)
}