123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483openPpxlibopenAst_helperopenFieldopenUtilsletmin_length_key="min_length"letmax_length_key="max_length"letlength_equals_key="length_equals"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"letdive="dive"typevalidator=|MinLengthofint|MaxLengthofint|LengthEqualsofint|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|LengthEquals_->length_equals_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?locnamecontext=Attribute.declarePrintf.(sprintf"ppx_derive_validator.%s"name)contextAst_pattern.(single_expr_payload(pexp_constant__))(process_numeric_attribute?loc)letint_attrributenamecontext=Attribute.declarePrintf.(sprintf"ppx_derive_validator.%s"name)contextAst_pattern.(single_expr_payload(eint__))(funx->x)letstring_attrributenamecontext=Attribute.declarePrintf.(sprintf"ppx_derive_validator.%s"name)contextAst_pattern.(single_expr_payload(estring__))(funx->x)letunit_attributenamecontext=Attribute.declarePrintf.(sprintf"ppx_derive_validator.%s"name)contextAst_pattern.(pstrnil)()letdive_attribute_ld=unit_attributediveAttribute.Context.label_declarationletdive_attribute_ct=unit_attributediveAttribute.Context.core_typeletvalidators_extractorcontext=letmin_length_attribute=int_attrributemin_length_keycontextinletmax_length_attribute=int_attrributemax_length_keycontextinletlength_equals_attribute=int_attrributelength_equals_keycontextinleturi_attribute=unit_attributeurl_keycontextinletuuid_attribute=unit_attributeuuid_keycontextinletnumeric_attribute=unit_attributenumeric_keycontextinletalpha_attribute=unit_attributealpha_keycontextinletalphanumeric_attribute=unit_attributealphanumeric_keycontextinletlowercase_attribute=unit_attributelowercase_keycontextinletlowercase_alphanumeric_attribute=unit_attributelowercase_alphanumeric_keycontextinletuppercase_attribute=unit_attributeuppercase_keycontextinletuppercase_alphanumeric_attribute=unit_attributeuppercase_alphanumeric_keycontextinletless_than_attribute=number_attributeless_thancontextinletless_than_or_equal_attribute=number_attributeless_than_or_equalcontextinletgreater_than_attribute=number_attributegreater_thancontextinletgreater_than_or_equal_attribute=number_attributegreater_than_or_equalcontextinletequal_to_attribute=number_attributeequal_tocontextinletnot_equal_to_attribute=number_attributenot_equal_tocontextinletemail_attribute=unit_attributeemailcontextinletregex_attribute=string_attrributeregexcontextinfunitem->[Attribute.getmin_length_attributeitem|>Option.map(funx->MinLengthx);Attribute.getmax_length_attributeitem|>Option.map(funx->MaxLengthx);Attribute.getlength_equals_attributeitem|>Option.map(funx->LengthEqualsx);Attribute.geturi_attributeitem|>Option.map(fun_->Url);Attribute.getuuid_attributeitem|>Option.map(fun_->Uuid);Attribute.getnumeric_attributeitem|>Option.map(fun_->Numeric);Attribute.getalpha_attributeitem|>Option.map(fun_->Alpha);Attribute.getalphanumeric_attributeitem|>Option.map(fun_->Alphanumeric);Attribute.getlowercase_attributeitem|>Option.map(fun_->Lowercase);Attribute.getlowercase_alphanumeric_attributeitem|>Option.map(fun_->LowercaseAlphanumeric);Attribute.getuppercase_attributeitem|>Option.map(fun_->Uppercase);Attribute.getuppercase_alphanumeric_attributeitem|>Option.map(fun_->UppercaseAlphanumeric);Attribute.getless_than_attributeitem|>Option.map(funx->LessThanx);Attribute.getless_than_or_equal_attributeitem|>Option.map(funx->LessThanOrEqualx);Attribute.getgreater_than_attributeitem|>Option.map(funx->GreaterThanx);Attribute.getgreater_than_or_equal_attributeitem|>Option.map(funx->GreaterThanOrEqualx);Attribute.getequal_to_attributeitem|>Option.map(funx->EqualTox);Attribute.getnot_equal_to_attributeitem|>Option.map(funx->NotEqualTox);Attribute.getemail_attributeitem|>Option.map(fun_->Email);Attribute.getregex_attributeitem|>Option.map(funx->Regexx);]|>List.filter_map(funx->x)letextract_field_validators=validators_extractorAttribute.Context.label_declarationletextract_core_type_validators=validators_extractorAttribute.Context.core_typeletlength_identf=matchf.typwith|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)));]letlength_equals_validator_explengthrecord_field=validator_exp_template"validate_length_equals"~loc:record_field.loc[(Nolabel,length_identrecord_field);(Nolabel,Exp.constant(Pconst_integer(string_of_intlength,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.typwith|Bool|Int|Float|String|List_->(matchvalidatorwith|MaxLengthmax->max_length_validator_expmaxrecord_field|MinLengthmin->min_length_validator_expminrecord_field|LengthEqualslength->length_equals_validator_explengthrecord_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)|Option(inner_record_field_type,_)->option_validator_exprecord_field(validator_exp{record_fieldwithtyp=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_type.loc})(field(ident{txt=Lident"x";loc=f.loc_type.loc}){txt=Lidentf.name;loc=f.loc_type.loc})letlist_validator_exp~locinner=letopenExpinapply(ident{txt=Ldot(Lident"Validate","list");loc})[(Nolabel,inner)]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}letrecvalidators_list_exp~validators~divableloc_type=matchloc_type.typwith|List(t,inner_type)->letlist_validators=validators|>List.map(validator_exploc_type)inexpr_listloc_type.loc(list_validators@[list_validator_exp~loc:loc_type.loc@@validators_list_exp~validators:(extract_core_type_validatorsinner_type)~divable:(Attribute.getdive_attribute_ctinner_type|>Option.is_some){loc_typewithtyp=t};])|Othertype_name->ifdivablethenexpr_listloc_type.loc[ignored_exp~loc:loc_type.loc@@call_other_type_validator_exp~loc:loc_type.loctype_name;]elseexpr_listloc_type.loc[]|Tupletypes->letargs_count=List.lengthtypesinletpattern=Pat.tuple(List.initargs_count(funi->Pat.var{txt=Printf.sprintf"x%d"i;loc=loc_type.loc}))inletindexes=List.initargs_count(funi->i)inletindexed_types=List.combineindexestypesinlettypes_validators_exps=indexed_types|>List.map(fun(i,(t,ct))->Exp.(apply(ident{txt=Ldot(Lident"Validate","field");loc=ct.ptyp_loc;})[(Nolabel,constant(Pconst_string(string_of_inti,ct.ptyp_loc,None)));(Nolabel,fun_NolabelNonepattern(ident{txt=Lident(Printf.sprintf"x%d"i);loc=loc_type.loc;}));(Nolabel,validators_list_exp~validators:(extract_core_type_validatorsct)~divable:(Attribute.getdive_attribute_ctct|>Option.is_some){loc_typewithtyp=t});]))inletbody=Exp.(apply(ident{txt=Ldot(Lident"Validate","record");loc=loc_type.loc})[(Nolabel,expr_listloc_type.loctypes_validators_exps)])inexpr_listloc_type.loc[body]|_->letgenerator=validator_exploc_typeinletvalidators=validatorsinletexps=validators|>List.mapgeneratorinexpr_listloc_type.locexpsletfield_validator_exp(ld:label_declaration)=letopenExpinletf=extract_record_fieldldinletdivable=Attribute.getdive_attribute_ldld|>Option.is_someinletdivable_ct=Attribute.getdive_attribute_ctld.pld_type|>Option.is_someinapply(ident{txt=Ldot(Lident"Validate","field");loc=f.loc_type.loc})[(Nolabel,constant(Pconst_string(f.name,f.loc_type.loc,None)));(Nolabel,field_extractor_expf);(Nolabel,validators_list_exp~validators:(extract_field_validatorsld@extract_core_type_validatorsld.pld_type)~divable:(divable||divable_ct)f.loc_type);]lettype_validator_exp(ct:core_type)=letopenExpinletf=extract_loc_typectinapply(ident{txt=Ldot(Lident"Validate","group");loc=f.loc})[(Nolabel,validators_list_exp~validators:(extract_core_type_validatorsct)~divable:(Attribute.getdive_attribute_ctct|>Option.is_some)f);]