postcard_bindgen/package/
npm_package.rs

1use core::borrow::Borrow;
2use std::{
3    fs::File,
4    io::{self, Write},
5    path::Path,
6};
7
8use postcard_bindgen_core::{
9    code_gen::js::{generate, GenerationSettings},
10    lang::js::Tokens,
11    registry::ContainerCollection,
12};
13
14use super::{PackageInfo, Version};
15
16/// Builds a npm package from created language binding strings.
17///
18/// # Example
19/// ```
20/// # use postcard_bindgen::{javascript::{build_package, GenerationSettings}, PackageInfo, PostcardBindings, generate_bindings};
21/// # use serde::Serialize;
22/// #[derive(Serialize, PostcardBindings)]
23/// struct Test {
24///     field: u8
25/// }
26///
27/// # fn main() {
28/// let parent_dir = std::env::current_dir().unwrap();
29/// let package_info = PackageInfo {
30///     name: "test-package".into(),
31///     version: "0.1.0".try_into().unwrap()
32/// };
33///
34/// build_package(parent_dir.as_path(), package_info, GenerationSettings::enable_all(), generate_bindings!(Test));
35/// # }
36/// ```
37pub fn build_npm_package(
38    parent_dir: &Path,
39    package_info: PackageInfo,
40    gen_settings: impl Borrow<GenerationSettings>,
41    bindings: ContainerCollection,
42) -> io::Result<()> {
43    let mut dir = parent_dir.to_path_buf();
44    dir.push(package_info.name.as_str());
45
46    std::fs::create_dir_all(&dir)?;
47
48    let (mut exports, export_meta) = generate(bindings, gen_settings);
49
50    let package_json = package_file_src(
51        package_info.name.as_str(),
52        &package_info.version,
53        exports.file("ts").is_some(),
54        export_meta.esm_module,
55    );
56
57    let mut package_json_path = dir.to_owned();
58    package_json_path.push("package.json");
59    File::create(package_json_path.as_path())?.write_all(package_json.as_bytes())?;
60
61    let js_export_path = dir.join("index.js");
62    let js_tokens = [
63        "util",
64        "serializer",
65        "deserializer",
66        "runtime_checks",
67        "ser",
68        "des",
69    ]
70    .into_iter()
71    .filter_map(|t| exports.pop_file(t))
72    .fold(Tokens::new(), |mut current, content| {
73        current.append(content.clone());
74        current.line();
75        current
76    });
77
78    File::create(js_export_path.as_path())?
79        .write_all(js_tokens.to_file_string().unwrap().as_bytes())?;
80
81    if let Some(file) = exports.file("ts") {
82        let ts_export_path = dir.join("index.d.ts");
83        File::create(ts_export_path.as_path())?
84            .write_all(file.to_file_string().unwrap().as_bytes())?;
85    }
86
87    Ok(())
88}
89
90fn package_file_src(
91    package_name: impl AsRef<str>,
92    package_version: &Version,
93    ts_types_enabled: bool,
94    esm_module: bool,
95) -> String {
96    format!("\
97{{
98    \"name\": \"{}\",
99    \"description\": \"Auto generated bindings for postcard format serializing and deserializing javascript to and from bytes.\",
100    \"version\": \"{}\",
101    \"main\": \"index.js\"{}{}
102}}",
103        package_name.as_ref(), package_version, if ts_types_enabled { ",\n\t\"types\": \"index.d.ts\"" } else { "" }, if esm_module { ",\n\t\"type\": \"module\"" } else { "" }
104    )
105}