Skip to main content

wasm_js_bridge/
lib.rs

1//! Build tool for packaging Rust crates as npm WASM packages with TypeScript and Flow types.
2//!
3//! Produces `.js`, `.d.ts`, and `.js.flow` output files from Rust-defined descriptors,
4//! one set per source file stem. Feature-gated: `ts` for TypeScript/JavaScript, `flow` for Flow.
5
6mod 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
16/// Convert a `file!()` path to a camelCase output file stem.
17///
18/// The stem is derived purely from the source filename — no special cases.
19/// `"src/foo_bar.rs"` → `"fooBar"`, `"src/wasm.rs"` → `"wasm"`, `"src/lib.rs"` → `"lib"`.
20/// For `mod.rs`, the parent directory name is used instead.
21pub 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        // mod.rs → use parent directory name
30        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}