Skip to content

Commit

Permalink
refactor(traverse): function to get var name from node (#6317)
Browse files Browse the repository at this point in the history
Pure refactor. Separate out the logic for creating a var name from an AST node into its own function, so it can be used standalone, outside of `generate_uid_based_on_node`.

Apart from the new `get_var_name_from_node` function, and changing return type of `to_identifier` to `String`, the only other changes are moving files around.
  • Loading branch information
overlookmotel committed Oct 6, 2024
1 parent 7d93b25 commit c0e2fef
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 74 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,28 @@
use oxc_ast::ast::*;
use oxc_ast::syntax_directed_operations::BoundNames;

use super::to_identifier;

pub fn get_var_name_from_node<'a, N: GatherNodeParts<'a>>(node: &N) -> String {
let mut name = String::new();
node.gather(&mut |mut part| {
if name.is_empty() {
part = part.trim_start_matches('_');
} else {
name.push('$');
}
name.push_str(part);
});

if name.is_empty() {
name = "ref".to_string();
} else {
name.truncate(20);
}

to_identifier(name)
}

pub trait GatherNodeParts<'a> {
fn gather<F: FnMut(&str)>(&self, f: &mut F);
}
Expand Down
62 changes: 62 additions & 0 deletions crates/oxc_traverse/src/ast_operations/identifier.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use oxc_syntax::identifier::{is_identifier_name, is_identifier_part, is_identifier_start};

/// Convert a String to a valid identifier name.
///
/// Based on Babel's [`toIdentifier`] function.
///
/// [`toIdentifier`]: https://github.com/babel/babel/blob/3bcfee232506a4cebe410f02042fb0f0adeeb0b1/packages/babel-types/src/converters/toIdentifier.ts#L4-L26
pub fn to_identifier(input: String) -> String {
if is_identifier_name(&input) {
return input;
}

let mut name = String::with_capacity(input.len());

let mut capitalize_next = false;

let mut chars = input.chars();
if let Some(first) = chars.next() {
if is_identifier_start(first) {
name.push(first);
} else {
capitalize_next = true;
}
}

for c in chars {
if !is_identifier_part(c) {
capitalize_next = true;
} else if capitalize_next {
name.push(c.to_ascii_uppercase());
capitalize_next = false;
} else {
name.push(c);
}
}

if name.is_empty() {
return "_".to_string();
}

name
}

#[test]
fn test() {
let cases = &[
("foo", "foo"),
("fooBar", "fooBar"),
("fooBar1", "fooBar1"),
("foo-bar", "fooBar"),
("foo bar", "fooBar"),
("foo-bar-1", "fooBar1"),
("1foo-bar", "FooBar"),
("1-foo-bar", "FooBar"),
("-- --", "_"),
("_output$headers$x-amzn-requestid", "_output$headers$xAmznRequestid"),
];

for &(input, expected) in cases {
assert_eq!(to_identifier(input.to_string()), expected);
}
}
4 changes: 4 additions & 0 deletions crates/oxc_traverse/src/ast_operations/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
mod gather_node_parts;
pub use self::gather_node_parts::get_var_name_from_node;
mod identifier;
pub use identifier::to_identifier;
2 changes: 0 additions & 2 deletions crates/oxc_traverse/src/context/ast_operations/mod.rs

This file was deleted.

58 changes: 0 additions & 58 deletions crates/oxc_traverse/src/context/identifier.rs

This file was deleted.

20 changes: 6 additions & 14 deletions crates/oxc_traverse/src/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,16 @@ use oxc_syntax::{
symbol::{SymbolFlags, SymbolId},
};

use crate::ancestor::{Ancestor, AncestorType};
use crate::{
ancestor::{Ancestor, AncestorType},
ast_operations::get_var_name_from_node,
};

mod ancestry;
mod ast_operations;
use ast_operations::GatherNodeParts;
mod bound_identifier;
use ancestry::PopToken;
pub use ancestry::TraverseAncestry;
pub use bound_identifier::BoundIdentifier;
mod identifier;
use identifier::to_identifier;
mod scoping;
pub use scoping::TraverseScoping;

Expand Down Expand Up @@ -359,15 +358,8 @@ impl<'a> TraverseCtx<'a> {
scope_id: ScopeId,
flags: SymbolFlags,
) -> BoundIdentifier<'a> {
let mut parts = String::new();
node.gather(&mut |part| {
if !parts.is_empty() {
parts.push('$');
}
parts.push_str(part);
});
let name = if parts.is_empty() { "ref" } else { parts.trim_start_matches('_') };
self.generate_uid(&to_identifier(name.get(..20).unwrap_or(name)), scope_id, flags)
let name = get_var_name_from_node(node);
self.generate_uid(&name, scope_id, flags)
}

/// Generate UID in current scope based on node.
Expand Down
1 change: 1 addition & 0 deletions crates/oxc_traverse/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ use oxc_allocator::Allocator;
use oxc_ast::ast::Program;
use oxc_semantic::{ScopeTree, SymbolTable};

pub mod ast_operations;
mod context;
pub use context::{BoundIdentifier, TraverseAncestry, TraverseCtx, TraverseScoping};

Expand Down

0 comments on commit c0e2fef

Please sign in to comment.