mirror of
https://github.com/danbulant/oxc
synced 2026-05-21 05:08:45 +00:00
feat(transformer): duplicate keys (#1649)
This commit is contained in:
parent
65c07728fc
commit
e331cc2677
7 changed files with 86 additions and 1 deletions
74
crates/oxc_transformer/src/es2015/duplicate_keys.rs
Normal file
74
crates/oxc_transformer/src/es2015/duplicate_keys.rs
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
#![allow(clippy::similar_names)]
|
||||
|
||||
use std::{collections::HashSet, rc::Rc};
|
||||
|
||||
use oxc_ast::{ast::*, AstBuilder};
|
||||
use oxc_span::{Atom, SPAN};
|
||||
|
||||
use crate::options::{TransformOptions, TransformTarget};
|
||||
|
||||
/// ES2015: Duplicate Keys
|
||||
///
|
||||
/// References:
|
||||
/// * <https://babeljs.io/docs/babel-plugin-transform-duplicate-keys>
|
||||
/// * <https://github.com/babel/babel/blob/main/packages/babel-plugin-transform-duplicate-keys>
|
||||
pub struct DuplicateKeys<'a> {
|
||||
ast: Rc<AstBuilder<'a>>,
|
||||
}
|
||||
|
||||
impl<'a> DuplicateKeys<'a> {
|
||||
pub fn new(ast: Rc<AstBuilder<'a>>, options: &TransformOptions) -> Option<Self> {
|
||||
(options.target < TransformTarget::ES2015 || options.duplicate_keys).then(|| Self { ast })
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
for property in obj_expr.properties.iter_mut() {
|
||||
let ObjectPropertyKind::ObjectProperty(obj_property) = property else {
|
||||
continue;
|
||||
};
|
||||
|
||||
if obj_property.computed {
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some(name) = &obj_property.key.static_name() {
|
||||
let mut is_duplicate = false;
|
||||
|
||||
match obj_property.kind {
|
||||
PropertyKind::Get => {
|
||||
if visited_data.contains(name) || visited_getters.contains(name) {
|
||||
is_duplicate = true;
|
||||
}
|
||||
visited_getters.insert(name.clone());
|
||||
}
|
||||
PropertyKind::Set => {
|
||||
if visited_data.contains(name) || visited_setters.contains(name) {
|
||||
is_duplicate = true;
|
||||
}
|
||||
visited_setters.insert(name.clone());
|
||||
}
|
||||
PropertyKind::Init => {
|
||||
if visited_data.contains(name)
|
||||
|| visited_setters.contains(name)
|
||||
|| visited_getters.contains(name)
|
||||
{
|
||||
is_duplicate = true;
|
||||
}
|
||||
visited_data.insert(name.clone());
|
||||
}
|
||||
}
|
||||
|
||||
if is_duplicate {
|
||||
obj_property.computed = true;
|
||||
let string_literal = StringLiteral::new(SPAN, name.as_str().into());
|
||||
let expr = self.ast.literal_string_expression(string_literal);
|
||||
obj_property.key = PropertyKey::Expression(expr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
mod duplicate_keys;
|
||||
mod function_name;
|
||||
mod shorthand_properties;
|
||||
mod template_literals;
|
||||
|
||||
pub use duplicate_keys::DuplicateKeys;
|
||||
pub use function_name::FunctionName;
|
||||
pub use shorthand_properties::ShorthandProperties;
|
||||
pub use template_literals::TemplateLiterals;
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ pub struct Transformer<'a> {
|
|||
es2015_function_name: Option<FunctionName<'a>>,
|
||||
es2015_shorthand_properties: Option<ShorthandProperties<'a>>,
|
||||
es2015_template_literals: Option<TemplateLiterals<'a>>,
|
||||
es2015_duplicate_keys: Option<DuplicateKeys<'a>>,
|
||||
es3_property_literal: Option<PropertyLiteral<'a>>,
|
||||
}
|
||||
|
||||
|
|
@ -101,6 +102,7 @@ impl<'a> Transformer<'a> {
|
|||
es2015_function_name: FunctionName::new(Rc::clone(&ast), ctx.clone(), &options),
|
||||
es2015_shorthand_properties: ShorthandProperties::new(Rc::clone(&ast), &options),
|
||||
es2015_template_literals: TemplateLiterals::new(Rc::clone(&ast), &options),
|
||||
es2015_duplicate_keys: DuplicateKeys::new(Rc::clone(&ast), &options),
|
||||
// other
|
||||
es3_property_literal: PropertyLiteral::new(Rc::clone(&ast), &options),
|
||||
react_jsx: ReactJsx::new(Rc::clone(&ast), ctx.clone(), options)
|
||||
|
|
@ -189,6 +191,7 @@ impl<'a> VisitMut<'a> for Transformer<'a> {
|
|||
|
||||
fn visit_object_expression(&mut self, expr: &mut ObjectExpression<'a>) {
|
||||
self.es2015_function_name.as_mut().map(|t| t.transform_object_expression(expr));
|
||||
self.es2015_duplicate_keys.as_mut().map(|t| t.transform_object_expression(expr));
|
||||
|
||||
for property in expr.properties.iter_mut() {
|
||||
self.visit_object_property_kind(property);
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ pub struct TransformOptions {
|
|||
// es2016
|
||||
pub exponentiation_operator: bool,
|
||||
// es2015
|
||||
pub duplicate_keys: bool,
|
||||
pub function_name: bool,
|
||||
pub shorthand_properties: bool,
|
||||
pub sticky_regex: bool,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
Passed: 270/1103
|
||||
Passed: 277/1111
|
||||
|
||||
# All Passed:
|
||||
* babel-plugin-transform-numeric-separator
|
||||
|
|
@ -772,6 +772,9 @@ Passed: 270/1103
|
|||
* loose/ignoreToPrimitiveHint/input.js
|
||||
* loose/mutableTemplateObject/input.js
|
||||
|
||||
# babel-plugin-transform-duplicate-keys (7/8)
|
||||
* combination/dupes/input.js
|
||||
|
||||
# babel-plugin-transform-typescript (66/158)
|
||||
* class/abstract-class-decorated/input.ts
|
||||
* class/abstract-class-decorated-method/input.ts
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ const CASES: &[&str] = &[
|
|||
"babel-plugin-transform-sticky-regex",
|
||||
"babel-plugin-transform-unicode-regex",
|
||||
"babel-plugin-transform-template-literals",
|
||||
"babel-plugin-transform-duplicate-keys",
|
||||
// ES3
|
||||
"babel-plugin-transform-property-literals",
|
||||
// TypeScript
|
||||
|
|
|
|||
|
|
@ -111,6 +111,7 @@ pub trait TestCase {
|
|||
sticky_regex: options.get_plugin("transform-sticky-regex").is_some(),
|
||||
template_literals: options.get_plugin("transform-template-literals").is_some(),
|
||||
property_literals: options.get_plugin("transform-property-literals").is_some(),
|
||||
duplicate_keys: options.get_plugin("transform-duplicate-keys").is_some(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue