Skip to content

Commit 075e700

Browse files
feat(bindgen): add --strict option for enabling type checks
1 parent f73a907 commit 075e700

File tree

19 files changed

+135
-53
lines changed

19 files changed

+135
-53
lines changed

crates/js-component-bindgen-component/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ impl bindings::Guest for JsComponentBindgenComponent {
6969
import_bindings: options.import_bindings.map(Into::into),
7070
guest: options.guest.unwrap_or(false),
7171
async_mode: options.async_mode.map(Into::into),
72+
strict: options.strict.unwrap_or(false),
7273
};
7374

7475
let js_component_bindgen::Transpiled {
@@ -163,6 +164,7 @@ impl bindings::Guest for JsComponentBindgenComponent {
163164
import_bindings: None,
164165
guest: opts.guest.unwrap_or(false),
165166
async_mode: opts.async_mode.map(Into::into),
167+
strict: opts.strict.unwrap_or(false),
166168
};
167169

168170
let files = js_component_bindgen::generate_types(&name, resolve, world, opts)

crates/js-component-bindgen-component/wit/js-component-bindgen.wit

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ world js-component-bindgen {
6969
/// Configure whether to use `async` imports or exports with
7070
/// JavaScript Promise Integration (JSPI).
7171
async-mode: option<async-mode>,
72+
73+
/// Configure whether to generate code that includes strict type checks
74+
strict: option<bool>,
7275
}
7376

7477
record async-imports-exports {
@@ -103,18 +106,28 @@ world js-component-bindgen {
103106
record type-generation-options {
104107
/// wit to generate typing from
105108
wit: wit,
109+
106110
/// world to generate typing for
107111
%world: option<string>,
112+
108113
tla-compat: option<bool>,
114+
109115
instantiation: option<instantiation-mode>,
116+
110117
%map: option<maps>,
118+
111119
/// Features that should be enabled as part of feature gating
112120
features: option<enabled-feature-set>,
121+
113122
/// Whether to generate module declarations like `declare module "local:package/foo" {...`.
114123
guest: option<bool>,
124+
115125
/// Configure whether to use `async` imports or exports with
116126
/// JavaScript Promise Integration (JSPI).
117127
async-mode: option<async-mode>,
128+
129+
/// Configure whether to generate code that includes strict type checks
130+
strict: option<bool>,
118131
}
119132

120133
enum export-type {

crates/js-component-bindgen/src/intrinsics/component.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
33
use std::fmt::Write as _;
44

5-
use crate::intrinsics::Intrinsic;
65
use crate::intrinsics::p3::async_future::AsyncFutureIntrinsic;
76
use crate::intrinsics::p3::async_stream::AsyncStreamIntrinsic;
87
use crate::intrinsics::p3::waitable::WaitableIntrinsic;
8+
use crate::intrinsics::{Intrinsic, RenderIntrinsicsArgs};
99
use crate::source::Source;
1010
use crate::uwriteln;
1111

@@ -81,7 +81,7 @@ impl ComponentIntrinsic {
8181
}
8282

8383
/// Render an intrinsic to a string
84-
pub fn render(&self, output: &mut Source) {
84+
pub fn render(&self, output: &mut Source, _render_args: &RenderIntrinsicsArgs<'_>) {
8585
match self {
8686
Self::GlobalAsyncStateMap => {
8787
let var_name = Self::GlobalAsyncStateMap.name();

crates/js-component-bindgen/src/intrinsics/conversion.rs

Lines changed: 66 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use std::fmt::Write;
44

5-
use crate::intrinsics::Intrinsic;
5+
use crate::intrinsics::{Intrinsic, RenderIntrinsicsArgs};
66
use crate::source::Source;
77
use crate::uwriteln;
88

@@ -100,7 +100,7 @@ impl ConversionIntrinsic {
100100
}
101101

102102
/// Render an intrinsic to a string
103-
pub fn render(&self, output: &mut Source) {
103+
pub fn render(&self, output: &mut Source, render_args: &RenderIntrinsicsArgs) {
104104
match self {
105105
Self::I32ToF32 => output.push_str(
106106
"
@@ -125,40 +125,58 @@ impl ConversionIntrinsic {
125125
"),
126126

127127
Self::ToBigInt64 => {
128-
let ensure_valid_numeric_primitive_fn = Self::RequireValidNumericPrimitive.name();
128+
let strict_checks = if render_args.transpile_opts.strict {
129+
let require_valid_numeric_primitive_fn = Self::RequireValidNumericPrimitive.name();
130+
format!("{require_valid_numeric_primitive_fn}('s64', converted);")
131+
} else {
132+
"".into()
133+
};
134+
129135
uwriteln!(
130136
output,
131137
r#"
132138
function toInt64(val) {{
133139
const converted = BigInt(val)
134-
{ensure_valid_numeric_primitive_fn}('s64', converted);
140+
{strict_checks}
135141
return BigInt.asIntN(64, converted);
136142
}}
137143
"#
138144
)
139145
},
140146

141147
Self::ToBigUint64 => {
142-
let ensure_valid_numeric_primitive_fn = Self::RequireValidNumericPrimitive.name();
148+
let strict_checks = if render_args.transpile_opts.strict {
149+
let require_valid_numeric_primitive_fn = Self::RequireValidNumericPrimitive.name();
150+
format!("{require_valid_numeric_primitive_fn}('u64', converted);")
151+
} else {
152+
"".into()
153+
};
154+
143155
uwriteln!(
144156
output,
145157
r#"
146158
function toUint64(val) {{
147159
const converted = BigInt(val)
148-
{ensure_valid_numeric_primitive_fn}('u64', converted);
160+
{strict_checks}
149161
return BigInt.asUintN(64, converted);
150162
}}
151163
"#
152164
);
153165
},
154166

155167
Self::ToInt16 => {
156-
let ensure_valid_numeric_primitive_fn = Self::RequireValidNumericPrimitive.name();
168+
let strict_checks = if render_args.transpile_opts.strict {
169+
let require_valid_numeric_primitive_fn = Self::RequireValidNumericPrimitive.name();
170+
format!("{require_valid_numeric_primitive_fn}('s16', val);")
171+
} else {
172+
"".into()
173+
};
174+
157175
uwriteln!(
158176
output,
159177
r#"
160178
function toInt16(val) {{
161-
{ensure_valid_numeric_primitive_fn}('s16', val);
179+
{strict_checks}
162180
val >>>= 0;
163181
val %= 2 ** 16;
164182
if (val >= 2 ** 15) {{
@@ -171,12 +189,18 @@ impl ConversionIntrinsic {
171189
},
172190

173191
Self::ToUint16 => {
174-
let ensure_valid_numeric_primitive_fn = Self::RequireValidNumericPrimitive.name();
192+
let strict_checks = if render_args.transpile_opts.strict {
193+
let require_valid_numeric_primitive_fn = Self::RequireValidNumericPrimitive.name();
194+
format!("{require_valid_numeric_primitive_fn}('u16', val);")
195+
} else {
196+
"".into()
197+
};
198+
175199
uwriteln!(
176200
output,
177201
r#"
178202
function toUint16(val) {{
179-
{ensure_valid_numeric_primitive_fn}('u16', val);
203+
{strict_checks}
180204
val >>>= 0;
181205
val %= 2 ** 16;
182206
return val;
@@ -186,25 +210,37 @@ impl ConversionIntrinsic {
186210
},
187211

188212
Self::ToInt32 => {
189-
let ensure_valid_numeric_primitive_fn = Self::RequireValidNumericPrimitive.name();
213+
let strict_checks = if render_args.transpile_opts.strict {
214+
let require_valid_numeric_primitive_fn = Self::RequireValidNumericPrimitive.name();
215+
format!("{require_valid_numeric_primitive_fn}('s32', val);")
216+
} else {
217+
"".into()
218+
};
219+
190220
uwriteln!(
191221
output,
192222
r#"
193223
function toInt32(val) {{
194-
{ensure_valid_numeric_primitive_fn}('s32', val);
224+
{strict_checks}
195225
return val >> 0;
196226
}}
197227
"#
198228
);
199229
},
200230

201231
Self::ToInt8 => {
202-
let ensure_valid_numeric_primitive_fn = Self::RequireValidNumericPrimitive.name();
232+
let strict_checks = if render_args.transpile_opts.strict {
233+
let require_valid_numeric_primitive_fn = Self::RequireValidNumericPrimitive.name();
234+
format!("{require_valid_numeric_primitive_fn}('s8', val);")
235+
} else {
236+
"".into()
237+
};
238+
203239
uwriteln!(
204240
output,
205241
r#"
206242
function toInt8(val) {{
207-
{ensure_valid_numeric_primitive_fn}('s8', val);
243+
{strict_checks}
208244
val >>>= 0;
209245
val %= 2 ** 8;
210246
if (val >= 2 ** 7) {{
@@ -238,25 +274,37 @@ impl ConversionIntrinsic {
238274

239275

240276
Self::ToUint32 => {
241-
let ensure_valid_numeric_primitive_fn = Self::RequireValidNumericPrimitive.name();
277+
let strict_checks = if render_args.transpile_opts.strict {
278+
let require_valid_numeric_primitive_fn = Self::RequireValidNumericPrimitive.name();
279+
format!("{require_valid_numeric_primitive_fn}('u32', val);")
280+
} else {
281+
"".into()
282+
};
283+
242284
uwriteln!(
243285
output,
244286
r#"
245287
function toUint32(val) {{
246-
{ensure_valid_numeric_primitive_fn}('u32', val);
288+
{strict_checks}
247289
return val >>> 0;
248290
}}
249291
"#
250292
)
251293
},
252294

253295
Self::ToUint8 => {
254-
let ensure_valid_numeric_primitive_fn = Self::RequireValidNumericPrimitive.name();
296+
let strict_checks = if render_args.transpile_opts.strict {
297+
let require_valid_numeric_primitive_fn = Self::RequireValidNumericPrimitive.name();
298+
format!("{require_valid_numeric_primitive_fn}('u8', val);")
299+
} else {
300+
"".into()
301+
};
302+
255303
uwriteln!(
256304
output,
257305
r#"
258306
function toUint8(val) {{
259-
{ensure_valid_numeric_primitive_fn}('u8', val);
307+
{strict_checks}
260308
val >>>= 0;
261309
val %= 2 ** 8;
262310
return val;

crates/js-component-bindgen/src/intrinsics/js_helper.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
//! Intrinsics that represent helpers that should be used from JS code
22
3-
use crate::{intrinsics::Intrinsic, source::Source};
3+
use crate::{
4+
intrinsics::{Intrinsic, RenderIntrinsicsArgs},
5+
source::Source,
6+
};
47

58
/// This enum contains intrinsics that function as JS helpers
69
///
@@ -35,7 +38,7 @@ impl JsHelperIntrinsic {
3538
}
3639

3740
/// Render an intrinsic to a string
38-
pub fn render(&self, output: &mut Source) {
41+
pub fn render(&self, output: &mut Source, _args: &RenderIntrinsicsArgs) {
3942
match self {
4043
Self::EmptyFunc => output.push_str("
4144
const emptyFunc = () => {};

crates/js-component-bindgen/src/intrinsics/lift.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
//! Intrinsics that represent helpers that enable Lift integration
22
use std::fmt::Write;
33

4-
use crate::intrinsics::Intrinsic;
54
use crate::intrinsics::component::ComponentIntrinsic;
65
use crate::intrinsics::p3::async_future::AsyncFutureIntrinsic;
76
use crate::intrinsics::p3::async_stream::AsyncStreamIntrinsic;
87
use crate::intrinsics::p3::error_context::ErrCtxIntrinsic;
98
use crate::intrinsics::string::StringIntrinsic;
9+
use crate::intrinsics::{Intrinsic, RenderIntrinsicsArgs};
1010
use crate::source::Source;
1111
use crate::uwriteln;
1212

@@ -249,7 +249,7 @@ impl LiftIntrinsic {
249249
}
250250

251251
/// Render an intrinsic to a string
252-
pub fn render(&self, output: &mut Source) {
252+
pub fn render(&self, output: &mut Source, _render_args: &RenderIntrinsicsArgs<'_>) {
253253
match self {
254254
Self::LiftFlatBool => {
255255
let debug_log_fn = Intrinsic::DebugLog.name();

crates/js-component-bindgen/src/intrinsics/lower.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
//! Intrinsics that represent helpers that enable Lower integration
22
3-
use crate::intrinsics::Intrinsic;
43
use crate::intrinsics::component::ComponentIntrinsic;
54
use crate::intrinsics::p3::{async_stream::AsyncStreamIntrinsic, error_context::ErrCtxIntrinsic};
65
use crate::intrinsics::string::StringIntrinsic;
6+
use crate::intrinsics::{Intrinsic, RenderIntrinsicsArgs};
77
use crate::source::Source;
88

99
use super::conversion::ConversionIntrinsic;
@@ -245,7 +245,7 @@ impl LowerIntrinsic {
245245
}
246246

247247
/// Render an intrinsic to a string
248-
pub fn render(&self, output: &mut Source) {
248+
pub fn render(&self, output: &mut Source, _render_args: &RenderIntrinsicsArgs<'_>) {
249249
match self {
250250
Self::LowerFlatBool => {
251251
let debug_log_fn = Intrinsic::DebugLog.name();

crates/js-component-bindgen/src/intrinsics/mod.rs

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::collections::{BTreeSet, HashSet};
44
use std::fmt::Write;
55

66
use crate::source::Source;
7-
use crate::{uwrite, uwriteln};
7+
use crate::{TranspileOpts, uwrite, uwriteln};
88

99
pub(crate) mod conversion;
1010
use conversion::ConversionIntrinsic;
@@ -165,19 +165,19 @@ pub enum Intrinsic {
165165
impl Intrinsic {
166166
pub fn render(&self, output: &mut Source, args: &RenderIntrinsicsArgs) {
167167
match self {
168-
Intrinsic::JsHelper(i) => i.render(output),
169-
Intrinsic::Conversion(i) => i.render(output),
170-
Intrinsic::String(i) => i.render(output),
171-
Intrinsic::ErrCtx(i) => i.render(output),
172-
Intrinsic::Resource(i) => i.render(output),
173-
Intrinsic::AsyncTask(i) => i.render(output),
168+
Intrinsic::JsHelper(i) => i.render(output, args),
169+
Intrinsic::Conversion(i) => i.render(output, args),
170+
Intrinsic::String(i) => i.render(output, args),
171+
Intrinsic::ErrCtx(i) => i.render(output, args),
172+
Intrinsic::Resource(i) => i.render(output, args),
173+
Intrinsic::AsyncTask(i) => i.render(output, args),
174174
Intrinsic::Waitable(i) => i.render(output, args),
175-
Intrinsic::Lift(i) => i.render(output),
176-
Intrinsic::Lower(i) => i.render(output),
177-
Intrinsic::AsyncStream(i) => i.render(output),
178-
Intrinsic::AsyncFuture(i) => i.render(output),
179-
Intrinsic::Component(i) => i.render(output),
180-
Intrinsic::Host(i) => i.render(output),
175+
Intrinsic::Lift(i) => i.render(output, args),
176+
Intrinsic::Lower(i) => i.render(output, args),
177+
Intrinsic::AsyncStream(i) => i.render(output, args),
178+
Intrinsic::AsyncFuture(i) => i.render(output, args),
179+
Intrinsic::Component(i) => i.render(output, args),
180+
Intrinsic::Host(i) => i.render(output, args),
181181

182182
Intrinsic::GlobalAsyncDeterminism => {
183183
output.push_str(&format!(
@@ -1041,6 +1041,8 @@ pub struct RenderIntrinsicsArgs<'a> {
10411041
pub(crate) instantiation: bool,
10421042
/// The kind of determinism to use
10431043
pub(crate) determinism: AsyncDeterminismProfile,
1044+
/// Options provided when performing transpilation
1045+
pub(crate) transpile_opts: &'a TranspileOpts,
10441046
}
10451047

10461048
/// Intrinsics that should be rendered as early as possible

crates/js-component-bindgen/src/intrinsics/p3/async_future.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
33
use std::fmt::Write;
44

5-
use crate::intrinsics::Intrinsic;
65
use crate::intrinsics::component::ComponentIntrinsic;
6+
use crate::intrinsics::{Intrinsic, RenderIntrinsicsArgs};
77
use crate::source::Source;
88
use crate::uwriteln;
99

@@ -252,7 +252,7 @@ impl AsyncFutureIntrinsic {
252252
}
253253

254254
/// Render an intrinsic to a string
255-
pub fn render(&self, output: &mut Source) {
255+
pub fn render(&self, output: &mut Source, _render_args: &RenderIntrinsicsArgs<'_>) {
256256
match self {
257257
Self::GlobalFutureMap => {
258258
let global_future_map = Self::GlobalFutureMap.name();

0 commit comments

Comments
 (0)