From 92eac4952a1da3ca8a55c0a271bb2504963eee58 Mon Sep 17 00:00:00 2001 From: David Sherret Date: Fri, 30 Aug 2024 09:00:05 -0400 Subject: [PATCH] fix(fast_check/dts): remove initializers in class methods/ctors (#521) --- src/fast_check/transform_dts.rs | 177 ++++++++++++------ .../fast_check/class_params_initializers.txt | 109 +++++++++++ 2 files changed, 226 insertions(+), 60 deletions(-) create mode 100644 tests/specs/graph/fast_check/class_params_initializers.txt diff --git a/src/fast_check/transform_dts.rs b/src/fast_check/transform_dts.rs index 6018abbe..651b4dd9 100644 --- a/src/fast_check/transform_dts.rs +++ b/src/fast_check/transform_dts.rs @@ -504,66 +504,7 @@ impl<'a> FastCheckDtsTransformer<'a> { fn_decl.function.body = None; fn_decl.declare = is_declare; - for param in &mut fn_decl.function.params { - match &mut param.pat { - Pat::Ident(ident) => { - if ident.type_ann.is_none() { - self.mark_diagnostic_any_fallback(ident.range()); - ident.type_ann = Some(any_type_ann()); - } - } - Pat::Assign(assign_pat) => { - match &mut *assign_pat.left { - Pat::Ident(ident) => { - if ident.type_ann.is_none() { - ident.type_ann = self.infer_expr_fallback_any( - *assign_pat.right.clone(), - false, - false, - ); - } - - ident.optional = true; - param.pat = Pat::Ident(ident.clone()); - } - Pat::Array(arr_pat) => { - if arr_pat.type_ann.is_none() { - arr_pat.type_ann = self.infer_expr_fallback_any( - *assign_pat.right.clone(), - false, - false, - ); - } - - arr_pat.optional = true; - param.pat = Pat::Array(arr_pat.clone()); - } - Pat::Object(obj_pat) => { - if obj_pat.type_ann.is_none() { - obj_pat.type_ann = self.infer_expr_fallback_any( - *assign_pat.right.clone(), - false, - false, - ); - } - - obj_pat.optional = true; - param.pat = Pat::Object(obj_pat.clone()); - } - Pat::Rest(_) - | Pat::Assign(_) - | Pat::Expr(_) - | Pat::Invalid(_) => {} - }; - } - Pat::Array(_) - | Pat::Rest(_) - | Pat::Object(_) - | Pat::Invalid(_) - | Pat::Expr(_) => {} - } - } - + self.handle_func_params(&mut fn_decl.function.params); Some(Decl::Fn(fn_decl)) } Decl::Var(mut var_decl) => { @@ -830,6 +771,7 @@ impl<'a> FastCheckDtsTransformer<'a> { .filter_map(|member| match member { ClassMember::Constructor(mut class_constructor) => { class_constructor.body = None; + self.handle_ts_param_props(&mut class_constructor.params); Some(ClassMember::Constructor(class_constructor)) } ClassMember::Method(mut method) => { @@ -837,6 +779,7 @@ impl<'a> FastCheckDtsTransformer<'a> { if method.kind == MethodKind::Setter { method.function.return_type = None; } + self.handle_func_params(&mut method.function.params); Some(ClassMember::Method(method)) } ClassMember::ClassProp(mut prop) => { @@ -868,6 +811,120 @@ impl<'a> FastCheckDtsTransformer<'a> { .collect() } + fn handle_ts_param_props( + &mut self, + param_props: &mut Vec, + ) { + for param in param_props { + match param { + ParamOrTsParamProp::TsParamProp(param) => { + match &mut param.param { + TsParamPropParam::Ident(ident) => { + self.handle_func_param_ident(ident); + } + TsParamPropParam::Assign(assign) => { + if let Some(new_pat) = self.handle_func_param_assign(assign) { + match new_pat { + Pat::Ident(new_ident) => { + param.param = TsParamPropParam::Ident(new_ident) + } + Pat::Assign(new_assign) => { + param.param = TsParamPropParam::Assign(new_assign) + } + Pat::Rest(_) + | Pat::Object(_) + | Pat::Array(_) + | Pat::Invalid(_) + | Pat::Expr(_) => { + // should never happen for parameter properties + unreachable!(); + } + } + } + } + } + } + ParamOrTsParamProp::Param(param) => self.handle_func_param(param), + } + } + } + + fn handle_func_params(&mut self, params: &mut Vec) { + for param in params { + self.handle_func_param(param); + } + } + + fn handle_func_param(&mut self, param: &mut Param) { + match &mut param.pat { + Pat::Ident(ident) => { + self.handle_func_param_ident(ident); + } + Pat::Assign(assign_pat) => { + if let Some(new_pat) = self.handle_func_param_assign(assign_pat) { + param.pat = new_pat; + } + } + Pat::Array(_) + | Pat::Rest(_) + | Pat::Object(_) + | Pat::Invalid(_) + | Pat::Expr(_) => {} + } + } + + fn handle_func_param_ident(&mut self, ident: &mut BindingIdent) { + if ident.type_ann.is_none() { + self.mark_diagnostic_any_fallback(ident.range()); + ident.type_ann = Some(any_type_ann()); + } + } + + fn handle_func_param_assign( + &mut self, + assign_pat: &mut AssignPat, + ) -> Option { + match &mut *assign_pat.left { + Pat::Ident(ident) => { + if ident.type_ann.is_none() { + ident.type_ann = self.infer_expr_fallback_any( + *assign_pat.right.clone(), + false, + false, + ); + } + + ident.optional = true; + Some(Pat::Ident(ident.clone())) + } + Pat::Array(arr_pat) => { + if arr_pat.type_ann.is_none() { + arr_pat.type_ann = self.infer_expr_fallback_any( + *assign_pat.right.clone(), + false, + false, + ); + } + + arr_pat.optional = true; + Some(Pat::Array(arr_pat.clone())) + } + Pat::Object(obj_pat) => { + if obj_pat.type_ann.is_none() { + obj_pat.type_ann = self.infer_expr_fallback_any( + *assign_pat.right.clone(), + false, + false, + ); + } + + obj_pat.optional = true; + Some(Pat::Object(obj_pat.clone())) + } + Pat::Rest(_) | Pat::Assign(_) | Pat::Expr(_) | Pat::Invalid(_) => None, + } + } + fn pat_to_ts_fn_param(&mut self, pat: Pat) -> Option { match pat { Pat::Ident(binding_id) => Some(TsFnParam::Ident(binding_id)), diff --git a/tests/specs/graph/fast_check/class_params_initializers.txt b/tests/specs/graph/fast_check/class_params_initializers.txt new file mode 100644 index 00000000..2d46fcdd --- /dev/null +++ b/tests/specs/graph/fast_check/class_params_initializers.txt @@ -0,0 +1,109 @@ +# https://jsr.io/@scope/a/meta.json +{"versions": { "1.0.0": {} } } + +# https://jsr.io/@scope/a/1.0.0_meta.json +{ "exports": { ".": "./mod.ts" } } + +# https://jsr.io/@scope/a/1.0.0/mod.ts +export class Object { + constructor( + values: {}, + { + a, + b, + }: { + a?: A; + b?: B; + } = {}, + ) { + } + + method( + values: {}, + { + a, + b, + }: { + a?: A; + b?: B; + } = {}, + value = 1, + ) { + } +} + +# mod.ts +import 'jsr:@scope/a' + +# output +{ + "roots": [ + "file:///mod.ts" + ], + "modules": [ + { + "kind": "esm", + "dependencies": [ + { + "specifier": "jsr:@scope/a", + "code": { + "specifier": "jsr:@scope/a", + "span": { + "start": { + "line": 0, + "character": 7 + }, + "end": { + "line": 0, + "character": 21 + } + } + } + } + ], + "size": 22, + "mediaType": "TypeScript", + "specifier": "file:///mod.ts" + }, + { + "kind": "esm", + "size": 259, + "mediaType": "TypeScript", + "specifier": "https://jsr.io/@scope/a/1.0.0/mod.ts" + } + ], + "redirects": { + "jsr:@scope/a": "https://jsr.io/@scope/a/1.0.0/mod.ts" + }, + "packages": { + "@scope/a@*": "@scope/a@1.0.0" + } +} + +Fast check https://jsr.io/@scope/a/1.0.0/mod.ts: + {} + export class Object { + constructor(values: { + }, {}: { + a?: A; + b?: B; + } = {} as never){} + method(values: { + }, {}: { + a?: A; + b?: B; + } = {} as never, value?: number): void {} + } + --- DTS --- + export declare class Object { + constructor(values: { + }, {}?: { + a?: A; + b?: B; + }); + method(values: { + }, {}?: { + a?: A; + b?: B; + }, value?: number): void; + }