mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 04:08:41 +00:00
feat(span): remove From<String> and From<Cow> API because they create memory leak (#2628)
closes #2621
This commit is contained in:
parent
240ff19675
commit
4f9dd98a97
17 changed files with 142 additions and 153 deletions
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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![]);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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("_"),
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(®ex.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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue