postcard_bindgen/package/
npm_package.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
use core::borrow::Borrow;
use std::{
    fs::File,
    io::{self, Write},
    path::Path,
};

use postcard_bindgen_core::{
    code_gen::js::{generate, GenerationSettings},
    lang::js::Tokens,
    registry::ContainerCollection,
};

use super::{PackageInfo, Version};

/// Builds a npm package from created language binding strings.
///
/// # Example
/// ```
/// # use postcard_bindgen::{javascript::{build_package, GenerationSettings}, PackageInfo, PostcardBindings, generate_bindings};
/// # use serde::Serialize;
/// #[derive(Serialize, PostcardBindings)]
/// struct Test {
///     field: u8
/// }
///
/// # fn main() {
/// let parent_dir = std::env::current_dir().unwrap();
/// let package_info = PackageInfo {
///     name: "test-package".into(),
///     version: "0.1.0".try_into().unwrap()
/// };
///
/// build_package(parent_dir.as_path(), package_info, GenerationSettings::enable_all(), generate_bindings!(Test));
/// # }
/// ```
pub fn build_npm_package(
    parent_dir: &Path,
    package_info: PackageInfo,
    gen_settings: impl Borrow<GenerationSettings>,
    bindings: ContainerCollection,
) -> io::Result<()> {
    let mut dir = parent_dir.to_path_buf();
    dir.push(package_info.name.as_str());

    std::fs::create_dir_all(&dir)?;

    let (mut exports, export_meta) = generate(bindings, gen_settings);

    let package_json = package_file_src(
        package_info.name.as_str(),
        &package_info.version,
        exports.file("ts").is_some(),
        export_meta.esm_module,
    );

    let mut package_json_path = dir.to_owned();
    package_json_path.push("package.json");
    File::create(package_json_path.as_path())?.write_all(package_json.as_bytes())?;

    let js_export_path = dir.join("index.js");
    let js_tokens = [
        "util",
        "serializer",
        "deserializer",
        "runtime_checks",
        "ser",
        "des",
    ]
    .into_iter()
    .filter_map(|t| exports.pop_file(t))
    .fold(Tokens::new(), |mut current, content| {
        current.append(content.clone());
        current.line();
        current
    });

    File::create(js_export_path.as_path())?
        .write_all(js_tokens.to_file_string().unwrap().as_bytes())?;

    if let Some(file) = exports.file("ts") {
        let ts_export_path = dir.join("index.d.ts");
        File::create(ts_export_path.as_path())?
            .write_all(file.to_file_string().unwrap().as_bytes())?;
    }

    Ok(())
}

fn package_file_src(
    package_name: impl AsRef<str>,
    package_version: &Version,
    ts_types_enabled: bool,
    esm_module: bool,
) -> String {
    format!("\
{{
    \"name\": \"{}\",
    \"description\": \"Auto generated bindings for postcard format serializing and deserializing javascript to and from bytes.\",
    \"version\": \"{}\",
    \"main\": \"index.js\"{}{}
}}",
        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 { "" }
    )
}