mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
feat(ecma): implement array join method (#6936)
This commit is contained in:
parent
9c9deaeffe
commit
24189f28ad
5 changed files with 91 additions and 6 deletions
66
crates/oxc_ecmascript/src/array_join.rs
Normal file
66
crates/oxc_ecmascript/src/array_join.rs
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
use crate::ToJsString;
|
||||
use oxc_ast::ast::*;
|
||||
|
||||
pub trait ArrayJoin<'a> {
|
||||
/// `Array.prototype.join ( separator )`
|
||||
/// <https://tc39.es/ecma262/#sec-array.prototype.join>
|
||||
fn array_join(&self, separator: Option<&str>) -> Option<String>;
|
||||
}
|
||||
|
||||
impl<'a> ArrayJoin<'a> for ArrayExpression<'a> {
|
||||
fn array_join(&self, separator: Option<&str>) -> Option<String> {
|
||||
let strings =
|
||||
self.elements.iter().map(ToJsString::to_js_string).collect::<Option<Vec<_>>>();
|
||||
strings
|
||||
.map(|v| v.iter().map(AsRef::as_ref).collect::<Vec<_>>().join(separator.unwrap_or(",")))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use oxc_allocator::{Allocator, CloneIn};
|
||||
use oxc_ast::AstBuilder;
|
||||
use oxc_span::SPAN;
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
let allocator = Allocator::default();
|
||||
let ast = AstBuilder::new(&allocator);
|
||||
let mut elements = ast.vec();
|
||||
elements.push(ast.array_expression_element_elision(SPAN));
|
||||
elements.push(ArrayExpressionElement::NullLiteral(ast.alloc(ast.null_literal(SPAN))));
|
||||
elements.push(ArrayExpressionElement::NumericLiteral(ast.alloc(ast.numeric_literal(
|
||||
SPAN,
|
||||
42f64,
|
||||
"42",
|
||||
NumberBase::Decimal,
|
||||
))));
|
||||
elements.push(ArrayExpressionElement::StringLiteral(
|
||||
ast.alloc(ast.string_literal(SPAN, "foo")),
|
||||
));
|
||||
elements.push(ArrayExpressionElement::BooleanLiteral(
|
||||
ast.alloc(ast.boolean_literal(SPAN, true)),
|
||||
));
|
||||
elements.push(ArrayExpressionElement::BigIntLiteral(ast.alloc(ast.big_int_literal(
|
||||
SPAN,
|
||||
"42n",
|
||||
BigintBase::Decimal,
|
||||
))));
|
||||
let array = ast.array_expression(SPAN, elements.clone_in(&allocator), None);
|
||||
let mut array2 = array.clone_in(&allocator);
|
||||
array2.elements.push(ArrayExpressionElement::ArrayExpression(ast.alloc(array)));
|
||||
array2.elements.push(ArrayExpressionElement::ObjectExpression(
|
||||
ast.alloc(ast.object_expression(SPAN, ast.vec(), None)),
|
||||
));
|
||||
let joined = array2.array_join(Some("_"));
|
||||
assert_eq!(joined, Some("__42_foo_true_42n_,,42,foo,true,42n_[object Object]".to_string()));
|
||||
|
||||
let joined2 = array2.array_join(None);
|
||||
// By default, in `Array.prototype.toString`, the separator is a comma. However, in `Array.prototype.join`, the separator is none if not given.
|
||||
assert_eq!(
|
||||
joined2,
|
||||
Some(",,42,foo,true,42n,,,42,foo,true,42n,[object Object]".to_string())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
mod is_litral_value;
|
||||
mod is_literal_value;
|
||||
mod value;
|
||||
mod value_type;
|
||||
|
||||
|
|
@ -11,7 +11,7 @@ use oxc_ast::ast::*;
|
|||
|
||||
use crate::{side_effects::MayHaveSideEffects, ToBigInt, ToBoolean, ToInt32, ToJsString, ToNumber};
|
||||
|
||||
pub use self::{is_litral_value::IsLiteralValue, value::ConstantValue, value_type::ValueType};
|
||||
pub use self::{is_literal_value::IsLiteralValue, value::ConstantValue, value_type::ValueType};
|
||||
|
||||
pub trait ConstantEvaluation<'a> {
|
||||
fn is_global_reference(&self, ident: &IdentifierReference<'a>) -> bool {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ mod private_bound_identifiers;
|
|||
mod prop_name;
|
||||
|
||||
// Abstract Operations
|
||||
mod array_join;
|
||||
mod string_char_at;
|
||||
mod string_char_code_at;
|
||||
mod string_index_of;
|
||||
|
|
@ -27,7 +28,8 @@ pub mod constant_evaluation;
|
|||
pub mod side_effects;
|
||||
|
||||
pub use self::{
|
||||
bound_names::BoundNames, is_simple_parameter_list::IsSimpleParameterList,
|
||||
array_join::ArrayJoin, bound_names::BoundNames,
|
||||
is_simple_parameter_list::IsSimpleParameterList,
|
||||
private_bound_identifiers::PrivateBoundIdentifiers, prop_name::PropName,
|
||||
string_char_at::StringCharAt, string_char_code_at::StringCharCodeAt,
|
||||
string_index_of::StringIndexOf, string_last_index_of::StringLastIndexOf,
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use crate::array_join::ArrayJoin;
|
||||
use crate::ToBoolean;
|
||||
use oxc_ast::ast::*;
|
||||
use oxc_syntax::operator::UnaryOperator;
|
||||
|
||||
use crate::ToBoolean;
|
||||
|
||||
/// `ToString`
|
||||
///
|
||||
/// <https://tc39.es/ecma262/#sec-tostring>
|
||||
|
|
@ -30,6 +30,23 @@ impl<'a> ToJsString<'a> for Expression<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> ToJsString<'a> for ArrayExpressionElement<'a> {
|
||||
fn to_js_string(&self) -> Option<Cow<'a, str>> {
|
||||
match self {
|
||||
ArrayExpressionElement::SpreadElement(_) => None,
|
||||
ArrayExpressionElement::Elision(_) | ArrayExpressionElement::NullLiteral(_) => {
|
||||
Some(Cow::Borrowed(""))
|
||||
}
|
||||
ArrayExpressionElement::Identifier(id) if id.name.as_str() == "undefined" => {
|
||||
Some(Cow::Borrowed(""))
|
||||
}
|
||||
expr @ match_expression!(ArrayExpressionElement) => {
|
||||
expr.as_expression().and_then(ToJsString::to_js_string)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToJsString<'a> for StringLiteral<'a> {
|
||||
fn to_js_string(&self) -> Option<Cow<'a, str>> {
|
||||
Some(Cow::Borrowed(self.value.as_str()))
|
||||
|
|
@ -101,7 +118,7 @@ impl<'a> ToJsString<'a> for UnaryExpression<'a> {
|
|||
impl<'a> ToJsString<'a> for ArrayExpression<'a> {
|
||||
fn to_js_string(&self) -> Option<Cow<'a, str>> {
|
||||
// TODO: https://github.com/google/closure-compiler/blob/e13f5cd0a5d3d35f2db1e6c03fdf67ef02946009/src/com/google/javascript/jscomp/NodeUtil.java#L302-L303
|
||||
None
|
||||
self.array_join(Some(",")).map(Cow::Owned)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue