|
1 | 1 | use proc_macro2::{TokenStream, Span}; |
2 | | -use quote::quote; |
3 | 2 | use syn::{Ident, LitStr}; |
| 3 | +use quote::quote; |
4 | 4 |
|
5 | 5 | pub enum Binding { |
6 | 6 | Variable(String), |
@@ -58,100 +58,120 @@ impl Binding { |
58 | 58 | Self::DurableObject => from_env(quote! { durable_object(#name_str) }), |
59 | 59 | } |
60 | 60 | } |
| 61 | +} |
61 | 62 |
|
62 | | - pub fn collect_from_env(env: &toml::Table) -> Result<Vec<(Ident, Self)>, syn::Error> { |
63 | | - fn invalid_wrangler_toml() -> syn::Error { |
64 | | - syn::Error::new( |
65 | | - Span::call_site(), |
66 | | - "Invalid wrangler.toml: a binding doesn't have `binding = \"...\"`, or some unexpected structure" |
67 | | - ) |
68 | | - } |
69 | | - |
70 | | - fn invalid_name(name: &str) -> syn::Error { |
71 | | - syn::Error::new( |
72 | | - Span::call_site(), |
73 | | - format!("Can't bind binding `{name}` into Rust struct field") |
74 | | - ) |
75 | | - } |
76 | | - |
77 | | - /////////////////////////////////////////////////////////////////////////////////////////// |
| 63 | +#[derive(serde::Deserialize, Default)] |
| 64 | +struct EnvBindingCollection { |
| 65 | + vars: Option<std::collections::BTreeMap<String, String>>, |
| 66 | + ai: Option<BindingDeclare>, |
| 67 | + d1_databases: Option<Vec<BindingDeclare>>, |
| 68 | + kv_namespaces: Option<Vec<BindingDeclare>>, |
| 69 | + r2_buckets: Option<Vec<BindingDeclare>>, |
| 70 | + services: Option<Vec<BindingDeclare>>, |
| 71 | + queues: Option<QueueProducers>, |
| 72 | + durable_objects: Option<BindingsArray>, |
| 73 | + // #[serde(flatten)] |
| 74 | + // root: BindingCollection, |
| 75 | + #[serde(default)] |
| 76 | + env: std::collections::BTreeMap<String, EnvBindingCollection>, |
| 77 | +} |
78 | 78 |
|
79 | | - fn get_field_as_ident(t: &toml::Table, field: &str) -> Result<Ident, syn::Error> { |
80 | | - t.get(field) |
81 | | - .and_then(|b| b.as_str()) |
82 | | - .ok_or_else(invalid_wrangler_toml) |
83 | | - .and_then(|name| syn::parse_str::<Ident>(name) |
84 | | - .map_err(|_| invalid_name(name)) |
85 | | - ) |
86 | | - } |
| 79 | +// #[derive(serde::Deserialize, Default)] |
| 80 | +// struct BindingCollection { |
| 81 | +// vars: Option<std::collections::BTreeMap<String, String>>, |
| 82 | +// ai: Option<BindingDeclare>, |
| 83 | +// d1_databases: Option<Vec<BindingDeclare>>, |
| 84 | +// kv_namespaces: Option<Vec<BindingDeclare>>, |
| 85 | +// r2_buckets: Option<Vec<BindingDeclare>>, |
| 86 | +// services: Option<Vec<BindingDeclare>>, |
| 87 | +// queues: Option<QueueProducers>, |
| 88 | +// durable_objects: Option<BindingsArray>, |
| 89 | +// } |
| 90 | + |
| 91 | +#[derive(serde::Deserialize)] |
| 92 | +struct BindingDeclare { |
| 93 | + binding: String, |
| 94 | +} |
87 | 95 |
|
88 | | - fn binding_of(t: &toml::Table) -> Result<Ident, syn::Error> { |
89 | | - get_field_as_ident(t, "binding") |
90 | | - } |
91 | | - fn name_of(t: &toml::Table) -> Result<Ident, syn::Error> { |
92 | | - get_field_as_ident(t, "name") |
93 | | - } |
| 96 | +#[derive(serde::Deserialize)] |
| 97 | +struct QueueProducers { |
| 98 | + producers: Vec<BindingDeclare>, |
| 99 | +} |
94 | 100 |
|
95 | | - fn table_array(a: &toml::value::Array) -> Result<impl IntoIterator<Item = &toml::Table>, syn::Error> { |
96 | | - a.iter() |
97 | | - .map(|v| v.as_table().ok_or_else(invalid_wrangler_toml)) |
98 | | - .collect::<Result<Vec<_>, _>>() |
99 | | - } |
| 101 | +#[derive(serde::Deserialize)] |
| 102 | +struct BindingsArray { |
| 103 | + bindings: Vec<BindingName>, |
| 104 | +} |
100 | 105 |
|
101 | | - /////////////////////////////////////////////////////////////////////////////////////////// |
| 106 | +#[derive(serde::Deserialize)] |
| 107 | +struct BindingName { |
| 108 | + name: String, |
| 109 | +} |
102 | 110 |
|
103 | | - let mut bindings = Vec::new(); |
| 111 | +impl Binding { |
| 112 | + pub fn collect_from_env(env_name: Option<Ident>) -> Result<Vec<(Ident, Self)>, syn::Error> { |
| 113 | + let mut config = super::wrangler::parse_wrangler::<EnvBindingCollection>() |
| 114 | + .map_err(|e| syn::Error::new(Span::call_site(), e))?; |
| 115 | + let config = match env_name.as_ref() { |
| 116 | + None => config, |
| 117 | + Some(name) => { |
| 118 | + let config = config.env.get_mut(&name.to_string()) |
| 119 | + .ok_or_else(|| syn::Error::new(name.span(), format!("env `{name}` is not found in wrangler config")))?; |
| 120 | + std::mem::take(config) |
| 121 | + } |
| 122 | + }; |
104 | 123 |
|
105 | | - if let Some(toml::Value::Table(vars)) = env.get("vars") { |
106 | | - for (name, value) in vars { |
107 | | - let name = syn::parse_str(name).map_err(|_| invalid_name(name))?; |
108 | | - let value = value.as_str() |
109 | | - .ok_or_else(|| syn::Error::new( |
110 | | - Span::call_site(), |
111 | | - "`#[bindings]` doesn't support JSON values in `vars` binding" |
112 | | - ))? |
113 | | - .to_owned(); |
114 | | - bindings.push((name, Self::Variable(value))) |
| 124 | + let mut collection = Vec::new(); |
| 125 | + { |
| 126 | + if let Some(vars) = config.vars { |
| 127 | + for (name, value) in vars { |
| 128 | + collection.push((name, Self::Variable(value))); |
| 129 | + } |
115 | 130 | } |
116 | | - } |
117 | | - if let Some(toml::Value::Table(ai)) = env.get("ai") { |
118 | | - bindings.push((binding_of(ai)?, Self::AI)) |
119 | | - } |
120 | | - if let Some(toml::Value::Array(d1_databases)) = env.get("d1_databases") { |
121 | | - for d1 in table_array(d1_databases)? { |
122 | | - bindings.push((binding_of(d1)?, Self::D1)) |
| 131 | + if let Some(BindingDeclare { binding }) = config.ai { |
| 132 | + collection.push((binding, Self::AI)); |
123 | 133 | } |
124 | | - } |
125 | | - if let Some(toml::Value::Array(kv_namespaces)) = env.get("kv_namespaces") { |
126 | | - for kv in table_array(kv_namespaces)? { |
127 | | - bindings.push((binding_of(kv)?, Self::KV)) |
| 134 | + if let Some(d1_databases) = config.d1_databases { |
| 135 | + for BindingDeclare { binding } in d1_databases { |
| 136 | + collection.push((binding, Self::D1)); |
| 137 | + } |
128 | 138 | } |
129 | | - } |
130 | | - if let Some(toml::Value::Array(r2_buckets)) = env.get("r2_buckets") { |
131 | | - for r2 in table_array(r2_buckets)? { |
132 | | - bindings.push((binding_of(r2)?, Self::R2)) |
| 139 | + if let Some(kv_namespaces) = config.kv_namespaces { |
| 140 | + for BindingDeclare { binding } in kv_namespaces { |
| 141 | + collection.push((binding, Self::KV)); |
| 142 | + } |
133 | 143 | } |
134 | | - } |
135 | | - if let Some(toml::Value::Array(services)) = env.get("services") { |
136 | | - for service in table_array(services)? { |
137 | | - bindings.push((binding_of(service)?, Self::Service)) |
| 144 | + if let Some(r2_buckets) = config.r2_buckets { |
| 145 | + for BindingDeclare { binding } in r2_buckets { |
| 146 | + collection.push((binding, Self::R2)); |
| 147 | + } |
138 | 148 | } |
139 | | - } |
140 | | - if let Some(toml::Value::Table(queues)) = env.get("queues") { |
141 | | - if let Some(toml::Value::Array(producers)) = queues.get("producers") { |
142 | | - for producer in table_array(producers)? { |
143 | | - bindings.push((binding_of(producer)?, Self::Queue)) |
| 149 | + if let Some(services) = config.services { |
| 150 | + for BindingDeclare { binding } in services { |
| 151 | + collection.push((binding, Self::Service)); |
144 | 152 | } |
145 | 153 | } |
146 | | - } |
147 | | - if let Some(toml::Value::Table(durable_objects)) = env.get("durable_objects") { |
148 | | - if let Some(toml::Value::Array(durable_object_bindings)) = durable_objects.get("bindings") { |
149 | | - for durable_object in table_array(durable_object_bindings)? { |
150 | | - bindings.push((name_of(durable_object)?, Self::DurableObject)) |
| 154 | + if let Some(QueueProducers { producers }) = config.queues { |
| 155 | + for BindingDeclare { binding } in producers { |
| 156 | + collection.push((binding, Self::Queue)); |
151 | 157 | } |
152 | 158 | } |
153 | | - } |
154 | | - |
155 | | - Ok(bindings) |
| 159 | + if let Some(BindingsArray { bindings }) = config.durable_objects { |
| 160 | + for BindingName { name } in bindings { |
| 161 | + collection.push((name, Self::DurableObject)); |
| 162 | + } |
| 163 | + } |
| 164 | + } |
| 165 | + |
| 166 | + collection |
| 167 | + .into_iter() |
| 168 | + .map(|(name, binding)| { |
| 169 | + let name = syn::parse_str(&name).map_err(|_| syn::Error::new( |
| 170 | + Span::call_site(), |
| 171 | + format!("can't handle binding name `{name}` as a Rust identifier") |
| 172 | + ))?; |
| 173 | + Ok((name, binding)) |
| 174 | + }) |
| 175 | + .collect() |
156 | 176 | } |
157 | 177 | } |
0 commit comments