mirror of
https://github.com/danbulant/oxc
synced 2026-05-25 04:42:10 +00:00
Fold constant addition expressions. Handles string concatenation and addition, both with implicit casting. For example, ```ts let x = 1 + 1 let y = "hello " + "world" ``` now becomes ```ts let x = 2 let y = "hello world" ``` ## Extra Goodies - test(minifier): add `test_snapshot` helper to perform snapshot tests with `insta` - up(hir): implement `std::ops::Add` for `NumericValue` - up(span): impl `TryFrom<Cow<'_, &str>>` for `Atom`
112 lines
2.6 KiB
Rust
112 lines
2.6 KiB
Rust
use std::{
|
|
borrow::{Borrow, Cow},
|
|
fmt,
|
|
ops::Deref,
|
|
};
|
|
|
|
use compact_str::CompactString;
|
|
#[cfg(feature = "serde")]
|
|
use serde::Serialize;
|
|
|
|
/// Newtype for [`CompactString`]
|
|
#[derive(Clone, Eq, Hash)]
|
|
#[cfg_attr(feature = "serde", derive(Serialize))]
|
|
pub struct Atom(CompactString);
|
|
|
|
const BASE54_CHARS: &[u8; 64] = b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_0123456789";
|
|
|
|
impl Atom {
|
|
pub const fn new_inline(s: &str) -> Self {
|
|
Self(CompactString::new_inline(s))
|
|
}
|
|
|
|
#[inline]
|
|
pub fn as_str(&self) -> &str {
|
|
self.0.as_str()
|
|
}
|
|
|
|
/// Get the shortest mangled name for a given n.
|
|
/// Code adapted from [terser](https://github.com/terser/terser/blob/8b966d687395ab493d2c6286cc9dd38650324c11/lib/scope.js#L1041-L1051)
|
|
pub fn base54(n: usize) -> Self {
|
|
let mut num = n;
|
|
// Base 54 at first because these are the usable first characters in JavaScript identifiers
|
|
// <https://tc39.es/ecma262/#prod-IdentifierStart>
|
|
let base = 54usize;
|
|
let mut ret = CompactString::default();
|
|
ret.push(BASE54_CHARS[num % base] as char);
|
|
num /= base;
|
|
// Base 64 for the rest because after the first character we can also use 0-9 too
|
|
// <https://tc39.es/ecma262/#prod-IdentifierPart>
|
|
let base = 64usize;
|
|
while num > 0 {
|
|
num -= 1;
|
|
ret.push(BASE54_CHARS[num % base] as char);
|
|
num /= base;
|
|
}
|
|
Self(ret)
|
|
}
|
|
}
|
|
|
|
impl Deref for Atom {
|
|
type Target = str;
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
self.0.as_str()
|
|
}
|
|
}
|
|
|
|
impl<'a> From<&'a str> for Atom {
|
|
fn from(s: &'a str) -> Self {
|
|
Self(s.into())
|
|
}
|
|
}
|
|
|
|
impl From<String> for Atom {
|
|
fn from(s: String) -> Self {
|
|
Self(s.into())
|
|
}
|
|
}
|
|
|
|
impl From<Cow<'_, str>> for Atom {
|
|
fn from(s: Cow<'_, str>) -> Self {
|
|
Self(s.into())
|
|
}
|
|
}
|
|
|
|
impl AsRef<str> for Atom {
|
|
#[inline]
|
|
fn as_ref(&self) -> &str {
|
|
self.0.as_str()
|
|
}
|
|
}
|
|
|
|
impl Borrow<str> for Atom {
|
|
#[inline]
|
|
fn borrow(&self) -> &str {
|
|
self.0.as_str()
|
|
}
|
|
}
|
|
|
|
impl<T: AsRef<str>> PartialEq<T> for Atom {
|
|
fn eq(&self, other: &T) -> bool {
|
|
self.0.as_str() == other.as_ref()
|
|
}
|
|
}
|
|
|
|
impl PartialEq<Atom> for &str {
|
|
fn eq(&self, other: &Atom) -> bool {
|
|
*self == other.0.as_str()
|
|
}
|
|
}
|
|
|
|
impl fmt::Debug for Atom {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
fmt::Debug::fmt(self.0.as_str(), f)
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for Atom {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
fmt::Display::fmt(self.0.as_str(), f)
|
|
}
|
|
}
|