1mod types;
7
8mod flow;
9mod ts;
10
11pub use flow::{generate_index_flow, OpaqueType};
12pub use ts::generate_index_dts;
13pub use types::{Interface, TypeAlias, WasmFn};
14pub use wasm_js_bridge_macros::{bundle, wasm_export, wasm_peers};
15
16pub fn file_to_stem(file: &str) -> String {
22 use std::path::Path;
23 let path = Path::new(file);
24 let stem = path
25 .file_stem()
26 .and_then(|s| s.to_str())
27 .unwrap_or("unknown");
28 let base = if stem == "mod" {
29 let parent = path
31 .parent()
32 .and_then(|p| p.file_name())
33 .and_then(|s| s.to_str())
34 .unwrap_or("mod");
35 if parent == "src" {
36 "mod"
37 } else {
38 parent
39 }
40 } else {
41 stem
42 };
43 snake_to_camel(base)
44}
45
46fn snake_to_camel(s: &str) -> String {
47 let mut result = String::new();
48 let mut capitalize_next = false;
49 for c in s.chars() {
50 if c == '_' {
51 capitalize_next = true;
52 } else if capitalize_next {
53 result.push(c.to_ascii_uppercase());
54 capitalize_next = false;
55 } else {
56 result.push(c);
57 }
58 }
59 result
60}
61
62#[cfg(test)]
63mod tests {
64 use super::*;
65
66 #[test]
67 fn file_to_stem_lib() {
68 assert_eq!(file_to_stem("src/lib.rs"), "lib", "lib.rs → lib");
69 }
70
71 #[test]
72 fn file_to_stem_index() {
73 assert_eq!(file_to_stem("src/index.rs"), "index", "index.rs → index");
74 }
75
76 #[test]
77 fn file_to_stem_snake_case() {
78 assert_eq!(
79 file_to_stem("src/foo_bar.rs"),
80 "fooBar",
81 "snake_case → camelCase"
82 );
83 }
84
85 #[test]
86 fn file_to_stem_mod_rs() {
87 assert_eq!(
88 file_to_stem("src/query/mod.rs"),
89 "query",
90 "mod.rs → parent dir"
91 );
92 }
93
94 #[test]
95 fn file_to_stem_root_mod_rs() {
96 assert_eq!(
97 file_to_stem("src/mod.rs"),
98 "mod",
99 "root mod.rs should not become src"
100 );
101 }
102
103 #[test]
104 fn file_to_stem_deep_path() {
105 assert_eq!(
106 file_to_stem("crates/wasm-js-bridge/src/query_options.rs"),
107 "queryOptions",
108 "deep path strips dirs and converts"
109 );
110 }
111}