123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409openPpxlibopenAst_helperopenFieldopenUtilsletmin_length_key="min_length"letmax_length_key="max_length"leturl_key="url"letuuid_key="uuid"letnumeric_key="numeric"letalpha_key="alpha"letalphanumeric_key="alphanumeric"letlowercase_key="lowercase"letlowercase_alphanumeric_key="lowercase_alphanumeric"letuppercase_key="uppercase"letuppercase_alphanumeric_key="uppercase_alphanumeric"letless_than="less_than"letless_than_or_equal="less_than_or_equal"letgreater_than="greater_than"letgreater_than_or_equal="greater_than_or_equal"letequal_to="equal_to"letnot_equal_to="not_equal_to"letemail="email"letregex="regex"letlist_min_length_key="list_min_length"letlist_max_length_key="list_max_length"letdive="dive"typelist_validator=ListMinLengthofint|ListMaxLengthofint[@@derivingshow]typevalidator=|MinLengthofint|MaxLengthofint|Url|Uuid|Numeric|Alpha|Alphanumeric|Lowercase|LowercaseAlphanumeric|Uppercase|UppercaseAlphanumeric|LessThanofnumber|LessThanOrEqualofnumber|GreaterThanofnumber|GreaterThanOrEqualofnumber|EqualToofnumber|NotEqualToofnumber|Email|Regexofstring[@@derivingshow]andnumber=Intofint|Floatoffloat[@@derivingshow]andvalidators=validatorlist[@@derivingshow]letstring_of_validator=function|MinLength_->min_length_key|MaxLength_->max_length_key|Url->url_key|Uuid->uuid_key|Numeric->numeric_key|Alpha->alpha_key|Alphanumeric->alphanumeric_key|Lowercase->lowercase_key|LowercaseAlphanumeric->lowercase_alphanumeric_key|Uppercase->uppercase_key|UppercaseAlphanumeric->uppercase_alphanumeric_key|LessThan_->less_than|LessThanOrEqual_->less_than_or_equal|GreaterThan_->greater_than|GreaterThanOrEqual_->greater_than_or_equal|EqualTo_->equal_to|NotEqualTo_->not_equal_to|Email->email|Regex_->regexletprocess_numeric_attribute?loc=function|Pconst_integer(i,_)->Int(int_of_stringi)|Pconst_float(f,_)->Float(float_of_stringf)|_->Location.raise_errorf?loc"Attribute must be an integer or float"letnumber_attribute?locname=Attribute.declarenameAttribute.Context.label_declarationAst_pattern.(single_expr_payload(pexp_constant__))(process_numeric_attribute?loc)letint_attrributename=Attribute.declarePrintf.(sprintf"ppx_derive_validator.%s"name)Attribute.Context.label_declarationAst_pattern.(single_expr_payload(eint__))(funx->x)letstring_attrributename=Attribute.declarePrintf.(sprintf"ppx_derive_validator.%s"name)Attribute.Context.label_declarationAst_pattern.(single_expr_payload(estring__))(funx->x)letunit_attributename=Attribute.declarePrintf.(sprintf"ppx_derive_validator.%s"name)Attribute.Context.label_declarationAst_pattern.(pstrnil)()letmin_length_attribute=int_attrributemin_length_keyletmax_length_attribute=int_attrributemax_length_keyleturi_attribute=unit_attributeurl_keyletuuid_attribute=unit_attributeuuid_keyletnumeric_attribute=unit_attributenumeric_keyletalpha_attribute=unit_attributealpha_keyletalphanumeric_attribute=unit_attributealphanumeric_keyletlowercase_attribute=unit_attributelowercase_keyletlowercase_alphanumeric_attribute=unit_attributelowercase_alphanumeric_keyletuppercase_attribute=unit_attributeuppercase_keyletuppercase_alphanumeric_attribute=unit_attributeuppercase_alphanumeric_keyletless_than_attribute=number_attributeless_thanletless_than_or_equal_attribute=number_attributeless_than_or_equalletgreater_than_attribute=number_attributegreater_thanletgreater_than_or_equal_attribute=number_attributegreater_than_or_equalletequal_to_attribute=number_attributeequal_toletnot_equal_to_attribute=number_attributenot_equal_toletlist_min_length_attribute=int_attrributelist_min_length_keyletlist_max_length_attribute=int_attrributelist_max_length_keyletdive_attribute=unit_attributediveletemail_attribute=unit_attributeemailletregex_attribute=string_attrributeregexletextract_list_validators(ld:label_declaration)=[Attribute.getlist_min_length_attributeld|>Option.map(funx->ListMinLengthx);Attribute.getlist_max_length_attributeld|>Option.map(funx->ListMaxLengthx);]|>List.filter_map(funx->x)letextract_validators(ld:label_declaration)=[Attribute.getmin_length_attributeld|>Option.map(funx->MinLengthx);Attribute.getmax_length_attributeld|>Option.map(funx->MaxLengthx);Attribute.geturi_attributeld|>Option.map(fun_->Url);Attribute.getuuid_attributeld|>Option.map(fun_->Uuid);Attribute.getnumeric_attributeld|>Option.map(fun_->Numeric);Attribute.getalpha_attributeld|>Option.map(fun_->Alpha);Attribute.getalphanumeric_attributeld|>Option.map(fun_->Alphanumeric);Attribute.getlowercase_attributeld|>Option.map(fun_->Lowercase);Attribute.getlowercase_alphanumeric_attributeld|>Option.map(fun_->LowercaseAlphanumeric);Attribute.getuppercase_attributeld|>Option.map(fun_->Uppercase);Attribute.getuppercase_alphanumeric_attributeld|>Option.map(fun_->UppercaseAlphanumeric);Attribute.getless_than_attributeld|>Option.map(funx->LessThanx);Attribute.getless_than_or_equal_attributeld|>Option.map(funx->LessThanOrEqualx);Attribute.getgreater_than_attributeld|>Option.map(funx->GreaterThanx);Attribute.getgreater_than_or_equal_attributeld|>Option.map(funx->GreaterThanOrEqualx);Attribute.getequal_to_attributeld|>Option.map(funx->EqualTox);Attribute.getnot_equal_to_attributeld|>Option.map(funx->NotEqualTox);Attribute.getemail_attributeld|>Option.map(fun_->Email);Attribute.getregex_attributeld|>Option.map(funx->Regexx);]|>List.filter_map(funx->x)letlength_identf=matchf.field_typewith|String->Exp.(ident{txt=Ldot(Lident"String","length");loc=f.loc})|List_->Exp.(ident{txt=Ldot(Lident"List","length");loc=f.loc})|_->Location.raise_errorf~loc:f.loc"length is not supported for this type"letvalidator_exp_template~locvalidator_nameparams=letopenExpinmatchparamswith|[]->ident{txt=Ldot(Lident"Validate",validator_name);loc}|_->apply(ident{txt=Ldot(Lident"Validate",validator_name);loc})paramsletmax_length_validator_expmaxrecord_field=validator_exp_template"validate_max_length"~loc:record_field.loc[(Nolabel,length_identrecord_field);(Nolabel,Exp.constant(Pconst_integer(string_of_intmax,None)));]letmin_length_validator_expminrecord_field=validator_exp_template"validate_min_length"~loc:record_field.loc[(Nolabel,length_identrecord_field);(Nolabel,Exp.constant(Pconst_integer(string_of_intmin,None)));]leturl_validator_exprecord_field=validator_exp_template"validate_url"~loc:record_field.loc[]letuuid_validator_exprecord_field=validator_exp_template"validate_uuid"~loc:record_field.loc[]letnumeric_validator_exprecord_field=validator_exp_template"validate_numeric"~loc:record_field.loc[]letalpha_validator_exprecord_field=validator_exp_template"validate_alpha"~loc:record_field.loc[]letalphanumeric_validator_exprecord_field=validator_exp_template"validate_alphanumeric"~loc:record_field.loc[]letlowercase_validator_exprecord_field=validator_exp_template"validate_lowercase"~loc:record_field.loc[]letlowercase_alphanumeric_validator_exprecord_field=validator_exp_template"validate_lowercase_alphanumeric"~loc:record_field.loc[]letuppercase_validator_exprecord_field=validator_exp_template"validate_uppercase"~loc:record_field.loc[]letuppercase_alphanumeric_validator_exprecord_field=validator_exp_template"validate_uppercase_alphanumeric"~loc:record_field.loc[]letregex_validator_expregexrecord_field=validator_exp_template"validate_str_regex"~loc:record_field.loc[(Nolabel,Exp.constant(Pconst_string(regex,record_field.loc,None)))]letnumber_to_exp=function|Inti->Exp.constant(Pconst_integer(string_of_inti,None))|Floatf->Exp.constant(Pconst_float(string_of_floatf,None))letnumber_to_str_exp~loc=function|Int_->Exp.ident{txt=Lident"string_of_int";loc}|Float_->Exp.ident{txt=Lident"string_of_float";loc}letless_than_validator_expnumberrecord_field=validator_exp_template"validate_less_than"~loc:record_field.loc[(Nolabel,number_to_str_exp~loc:record_field.locnumber);(Nolabel,number_to_expnumber);]letless_than_or_equal_validator_expnumberrecord_field=validator_exp_template"validate_less_than_or_equal"~loc:record_field.loc[(Nolabel,number_to_str_exp~loc:record_field.locnumber);(Nolabel,number_to_expnumber);]letgreater_than_validator_expnumberrecord_field=validator_exp_template"validate_greater_than"~loc:record_field.loc[(Nolabel,number_to_str_exp~loc:record_field.locnumber);(Nolabel,number_to_expnumber);]letgreater_than_or_equal_validator_expnumberrecord_field=validator_exp_template"validate_greater_than_or_equal"~loc:record_field.loc[(Nolabel,number_to_str_exp~loc:record_field.locnumber);(Nolabel,number_to_expnumber);]letequal_to_validator_expnumberrecord_field=validator_exp_template"validate_equal_to"~loc:record_field.loc[(Nolabel,number_to_str_exp~loc:record_field.locnumber);(Nolabel,number_to_expnumber);]letnot_equal_to_validator_expnumberrecord_field=validator_exp_template"validate_not_equal_to"~loc:record_field.loc[(Nolabel,number_to_str_exp~loc:record_field.locnumber);(Nolabel,number_to_expnumber);]letoption_validator_exprecord_fieldinner=validator_exp_template"option"~loc:record_field.loc[(Nolabel,inner)]letemail_validator_exprecord_field=validator_exp_template"validate_email"~loc:record_field.loc[]letrecvalidator_exprecord_fieldvalidator=matchrecord_field.field_typewith|Bool|Int|Float|String->(matchvalidatorwith|MaxLengthmax->max_length_validator_expmaxrecord_field|MinLengthmin->min_length_validator_expminrecord_field|Url->url_validator_exprecord_field|Uuid->uuid_validator_exprecord_field|Numeric->numeric_validator_exprecord_field|Alpha->alpha_validator_exprecord_field|Alphanumeric->alphanumeric_validator_exprecord_field|Lowercase->lowercase_validator_exprecord_field|LowercaseAlphanumeric->lowercase_alphanumeric_validator_exprecord_field|Uppercase->uppercase_validator_exprecord_field|UppercaseAlphanumeric->uppercase_alphanumeric_validator_exprecord_field|LessThannumber->less_than_validator_expnumberrecord_field|LessThanOrEqualnumber->less_than_or_equal_validator_expnumberrecord_field|GreaterThannumber->greater_than_validator_expnumberrecord_field|GreaterThanOrEqualnumber->greater_than_or_equal_validator_expnumberrecord_field|EqualTonumber->equal_to_validator_expnumberrecord_field|NotEqualTonumber->not_equal_to_validator_expnumberrecord_field|Email->email_validator_exprecord_field|Regexregex->regex_validator_expregexrecord_field)|Optioninner_record_field_type->option_validator_exprecord_field(validator_exp{record_fieldwithfield_type=inner_record_field_type}validator)|_->Location.raise_errorf~loc:record_field.loc"Something went wrong"letfield_extractor_expf=letopenExpinfun_NolabelNone(Pat.var{txt="x";loc=f.loc})(field(ident{txt=Lident"x";loc=f.loc}){txt=Lidentf.name;loc=f.loc})letlist_validator_exp~locinner=letopenExpinapply(ident{txt=Ldot(Lident"Validate","list");loc})[(Nolabel,inner)]letlist_specific_validator_exprecord_fieldlist_validator=matchlist_validatorwith|ListMinLengthmin->validator_exp_template"validate_min_length"~loc:record_field.loc[(Nolabel,length_identrecord_field);(Nolabel,Exp.constant(Pconst_integer(string_of_intmin,None)));]|ListMaxLengthmax->validator_exp_template"validate_max_length"~loc:record_field.loc[(Nolabel,length_identrecord_field);(Nolabel,Exp.constant(Pconst_integer(string_of_intmax,None)));]letignored_exp~locinner=letopenExpinapply(ident{txt=Ldot(Lident"Validate","ignore_ok");loc})[(Nolabel,inner)]letcall_other_type_validator_exp~loctype_name=letopenExpinlettxt=matchtype_namewith|Lidentname->Lident(Printf.sprintf"validate_%s"name)|Ldot(module_name,name)->Ldot(module_name,Printf.sprintf"validate_%s"name)|_->Location.raise_errorf~loc"Something went wrong"inident{txt;loc}letrecfield_validators_list_expf(ld:label_declaration)=matchf.field_typewith|Listt->letlist_validators=extract_list_validatorsld|>List.map(list_specific_validator_expf)inexpr_listf.loc(list_validators@[list_validator_exp~loc:f.loc@@field_validators_list_exp{fwithfield_type=t}ld;])|Othertype_name->letdivable=Attribute.getdive_attributeld|>Option.is_someinifdivablethenexpr_listf.loc[ignored_exp~loc:f.loc@@call_other_type_validator_exp~loc:f.loctype_name;]elseexpr_listf.loc[]|_->letgenerator=validator_expfinletvalidators=extract_validatorsldinletexps=validators|>List.mapgeneratorinexpr_listf.locexpsletfield_validator_exp(ld:label_declaration)=letopenExpinletf=extract_record_fieldldinapply(ident{txt=Ldot(Lident"Validate","field");loc=f.loc})[(Nolabel,constant(Pconst_string(f.name,f.loc,None)));(Nolabel,field_extractor_expf);(Nolabel,field_validators_list_expfld);]