Skip to content

Commit

Permalink
fix: should generate valid name for kebab case files
Browse files Browse the repository at this point in the history
  • Loading branch information
hyf0 committed Nov 16, 2023
1 parent 079c922 commit ad93546
Show file tree
Hide file tree
Showing 8 changed files with 65 additions and 26 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions crates/rolldown/src/bundler/module/external_module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,14 @@ impl ExternalModule {
Specifier::Star => {
self.namespace_ref = Some(symbols.create_symbol(
self.id,
Atom::from(format!("{}_ns", self.resource_id.expect_file().generate_unique_name())),
Atom::from(format!("{}_ns", self.resource_id.expect_file().representative_name())),
));
self.namespace_ref.unwrap()
}
Specifier::Literal(exported) => {
*self.exported_name_to_binding_ref.entry(exported.clone()).or_insert_with_key(|exported| {
let declared_name = if exported.as_ref() == "default" {
Atom::from(format!("{}_default", self.resource_id.expect_file().generate_unique_name()))
Atom::from(format!("{}_default", self.resource_id.expect_file().representative_name()))
} else {
exported.clone()
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,12 +159,12 @@ impl<'task, T: FileSystem + Default + 'static> NormalModuleTask<'task, T> {
let (mut symbol_table, scope) = semantic.into_symbol_table_and_scope_tree();
let ast_scope = AstScope::new(scope, std::mem::take(&mut symbol_table.references));
let mut symbol_for_module = AstSymbol::from_symbol_table(symbol_table);
let unique_name = self.path.generate_unique_name();
let unique_name = self.path.representative_name();
let mut scanner = scanner::Scanner::new(
self.module_id,
&ast_scope,
&mut symbol_for_module,
unique_name,
unique_name.into_owned(),
self.module_type,
);
scanner.visit_program(program.program());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
source: crates/rolldown/tests/common/case.rs
expression: content
input_file: crates/rolldown/tests/fixtures/misc/generate_valid_name_for_kebab_case_files
---
# Assets

## main.mjs

```js
import { __commonJS } from "./_rolldown_runtime.mjs";
// react-dom.js
var require_react_dom = __commonJS({
'react-dom.js'(exports, module) {
module.exports = 'react-dom'
}
});
export default require_react_dom();
```
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = 'react-dom'
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"input": {
"input": [
{
"name": "main",
"import": "./react-dom.js"
}
]
}
}
4 changes: 3 additions & 1 deletion crates/rolldown_common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ repository.workspace = true


[dependencies]
oxc = { workspace = true }
oxc = { workspace = true, features = ["semantic"] }
rustc-hash = { workspace = true }
index_vec = { workspace = true }
sugar_path = { workspace = true }
regex = { workspace = true }
once_cell = { workspace = true }
45 changes: 24 additions & 21 deletions crates/rolldown_common/src/file_path.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use std::{
borrow::Cow,
ffi::OsStr,
path::{Component, Path},
sync::Arc,
};

use regex::Regex;
use sugar_path::{AsPath, SugarPath};

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
Expand Down Expand Up @@ -61,39 +63,40 @@ impl FilePath {
name
}

pub fn generate_unique_name(&self) -> String {
// This doesn't ensure uniqueness, but should be valid as a JS identifier.
pub fn representative_name(&self) -> Cow<str> {
let path = Path::new(self.0.as_ref());
let unique_name =
path.file_stem().expect("should have file_stem").to_str().expect("should be valid utf8");
let mut unique_name = Cow::Borrowed(
path.file_stem().expect("should have file_stem").to_str().expect("should be valid utf8"),
);

if unique_name == "index" {
if let Some(unique_name_of_parent_dir) =
path.parent().and_then(Path::file_stem).and_then(OsStr::to_str)
{
return [unique_name_of_parent_dir, "_index"].concat();
unique_name = Cow::Owned([unique_name_of_parent_dir, "_index"].concat());
}
}

ensure_valid_identifier(unique_name)
}
}

fn ensure_valid_identifier(s: &str) -> String {
let mut ident = String::new();
let mut need_gap = false;
for i in s.chars() {
if i.is_ascii_alphabetic() || (i.is_ascii_digit() && !ident.is_empty()) {
if need_gap {
ident.push('_');
need_gap = false;
}
ident.push(i);
} else if !ident.is_empty() {
need_gap = true;
}
}
if ident.is_empty() {
ident.push('_');
static VALID_RE: once_cell::sync::Lazy<Regex> =
once_cell::sync::Lazy::new(|| Regex::new(r"[^a-zA-Z0-9_$]").unwrap());

fn ensure_valid_identifier(s: Cow<str>) -> Cow<str> {
match s {
Cow::Borrowed(str) => VALID_RE.replace_all(str, "_"),
Cow::Owned(owned_str) => VALID_RE.replace_all(&owned_str, "_").into_owned().into(),
}
ident
}

#[test]
fn test_ensure_valid_identifier() {
assert_eq!(ensure_valid_identifier("foo".into()), "foo");
assert_eq!(ensure_valid_identifier("$foo$".into()), "$foo$");
assert_eq!(ensure_valid_identifier("react-dom".into()), "react_dom");
}

#[test]
Expand Down

0 comments on commit ad93546

Please sign in to comment.