mirror of
https://github.com/danbulant/oxc
synced 2026-05-22 13:48:55 +00:00
refactor(traverse): function to get var name from node (#6317)
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.
This commit is contained in:
parent
7d93b25221
commit
c0e2fef0af
7 changed files with 95 additions and 74 deletions
|
|
@ -8,6 +8,28 @@
|
||||||
use oxc_ast::ast::*;
|
use oxc_ast::ast::*;
|
||||||
use oxc_ast::syntax_directed_operations::BoundNames;
|
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> {
|
pub trait GatherNodeParts<'a> {
|
||||||
fn gather<F: FnMut(&str)>(&self, f: &mut F);
|
fn gather<F: FnMut(&str)>(&self, f: &mut F);
|
||||||
}
|
}
|
||||||
62
crates/oxc_traverse/src/ast_operations/identifier.rs
Normal file
62
crates/oxc_traverse/src/ast_operations/identifier.rs
Normal file
|
|
@ -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
crates/oxc_traverse/src/ast_operations/mod.rs
Normal file
4
crates/oxc_traverse/src/ast_operations/mod.rs
Normal file
|
|
@ -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;
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
pub mod gather_node_parts;
|
|
||||||
pub use self::gather_node_parts::GatherNodeParts;
|
|
||||||
|
|
@ -1,58 +0,0 @@
|
||||||
use std::borrow::Cow;
|
|
||||||
|
|
||||||
use oxc_syntax::identifier::{is_identifier_name, is_identifier_part, is_identifier_start};
|
|
||||||
|
|
||||||
/// Convert a str to a valid identifier name.
|
|
||||||
///
|
|
||||||
/// Based on Babel's [`toIdentifier`](https://github.com/babel/babel/blob/3bcfee232506a4cebe410f02042fb0f0adeeb0b1/packages/babel-types/src/converters/toIdentifier.ts#L4-L26) function.
|
|
||||||
pub fn to_identifier(input: &str) -> Cow<str> {
|
|
||||||
if is_identifier_name(input) {
|
|
||||||
return Cow::Borrowed(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 Cow::Borrowed("_");
|
|
||||||
}
|
|
||||||
|
|
||||||
Cow::Owned(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test() {
|
|
||||||
assert_eq!(to_identifier("foo"), "foo");
|
|
||||||
assert_eq!(to_identifier("fooBar"), "fooBar");
|
|
||||||
assert_eq!(to_identifier("fooBar1"), "fooBar1");
|
|
||||||
|
|
||||||
assert_eq!(to_identifier("foo-bar"), "fooBar");
|
|
||||||
assert_eq!(to_identifier("foo bar"), "fooBar");
|
|
||||||
assert_eq!(to_identifier("foo-bar-1"), "fooBar1");
|
|
||||||
assert_eq!(to_identifier("1foo-bar"), "FooBar");
|
|
||||||
assert_eq!(to_identifier("1-foo-bar"), "FooBar");
|
|
||||||
assert_eq!(to_identifier("-- --"), "_");
|
|
||||||
|
|
||||||
assert_eq!(to_identifier("_output$headers$x-amzn-requestid"), "_output$headers$xAmznRequestid");
|
|
||||||
}
|
|
||||||
|
|
@ -11,17 +11,16 @@ use oxc_syntax::{
|
||||||
symbol::{SymbolFlags, SymbolId},
|
symbol::{SymbolFlags, SymbolId},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::ancestor::{Ancestor, AncestorType};
|
use crate::{
|
||||||
|
ancestor::{Ancestor, AncestorType},
|
||||||
|
ast_operations::get_var_name_from_node,
|
||||||
|
};
|
||||||
|
|
||||||
mod ancestry;
|
mod ancestry;
|
||||||
mod ast_operations;
|
|
||||||
use ast_operations::GatherNodeParts;
|
|
||||||
mod bound_identifier;
|
mod bound_identifier;
|
||||||
use ancestry::PopToken;
|
use ancestry::PopToken;
|
||||||
pub use ancestry::TraverseAncestry;
|
pub use ancestry::TraverseAncestry;
|
||||||
pub use bound_identifier::BoundIdentifier;
|
pub use bound_identifier::BoundIdentifier;
|
||||||
mod identifier;
|
|
||||||
use identifier::to_identifier;
|
|
||||||
mod scoping;
|
mod scoping;
|
||||||
pub use scoping::TraverseScoping;
|
pub use scoping::TraverseScoping;
|
||||||
|
|
||||||
|
|
@ -359,15 +358,8 @@ impl<'a> TraverseCtx<'a> {
|
||||||
scope_id: ScopeId,
|
scope_id: ScopeId,
|
||||||
flags: SymbolFlags,
|
flags: SymbolFlags,
|
||||||
) -> BoundIdentifier<'a> {
|
) -> BoundIdentifier<'a> {
|
||||||
let mut parts = String::new();
|
let name = get_var_name_from_node(node);
|
||||||
node.gather(&mut |part| {
|
self.generate_uid(&name, scope_id, flags)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate UID in current scope based on node.
|
/// Generate UID in current scope based on node.
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,7 @@ use oxc_allocator::Allocator;
|
||||||
use oxc_ast::ast::Program;
|
use oxc_ast::ast::Program;
|
||||||
use oxc_semantic::{ScopeTree, SymbolTable};
|
use oxc_semantic::{ScopeTree, SymbolTable};
|
||||||
|
|
||||||
|
pub mod ast_operations;
|
||||||
mod context;
|
mod context;
|
||||||
pub use context::{BoundIdentifier, TraverseAncestry, TraverseCtx, TraverseScoping};
|
pub use context::{BoundIdentifier, TraverseAncestry, TraverseCtx, TraverseScoping};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue