27 template<
typename WriteableType>
28 static constexpr WriteableType
output_kv( WriteableType it,
30 std::string_view value ) {
31 it.write( key,
":", it.space, value );
35 namespace json_details {
36 template<
typename JsonMember,
bool is_root =
false,
37 typename WriteableType>
39 WriteableType out_it ) {
41 if constexpr( not is_root ) {
44 out_it.next_member( );
46 out_it = utils::output_kv( out_it, R
"("type")", R"("boolean")" );
47 if constexpr( not is_root ) {
50 out_it.next_member( );
51 if constexpr( not is_root ) {
57 template<
typename JsonMember,
bool is_root =
false,
58 typename WriteableType>
59 constexpr WriteableType to_json_schema( ParseTag<JsonParseTypes::Custom>,
60 WriteableType out_it ) {
63 static_assert( JsonMember::custom_json_type ==
64 options::JsonCustomTypes::String );
65 if constexpr( not is_root ) {
68 out_it.next_member( );
70 out_it = utils::output_kv( out_it, R
"("type")", R"("string")" );
71 if constexpr( not is_root ) {
74 out_it.next_member( );
75 if constexpr( not is_root ) {
81 template<
typename JsonMember,
bool is_root =
false,
82 typename WriteableType>
83 constexpr WriteableType to_json_schema( ParseTag<JsonParseTypes::Date>,
84 WriteableType out_it ) {
86 if constexpr( not is_root ) {
89 out_it.next_member( );
91 out_it = utils::output_kv( out_it, R
"("type")", R"("string")" );
93 out_it.next_member( );
94 out_it = utils::output_kv( out_it, R
"("format")", R"("date-time")" );
95 if constexpr( not is_root ) {
98 out_it.next_member( );
99 if constexpr( not is_root ) {
105 template<
typename JsonMember,
bool is_root =
false,
106 typename WriteableType>
107 constexpr WriteableType to_json_schema( ParseTag<JsonParseTypes::Real>,
108 WriteableType out_it ) {
110 if constexpr( not is_root ) {
112 out_it.add_indent( );
113 out_it.next_member( );
115 out_it = utils::output_kv( out_it, R
"("type")", R"("number")" );
116 if constexpr( not is_root ) {
117 out_it.del_indent( );
119 out_it.next_member( );
120 if constexpr( not is_root ) {
126 template<
typename JsonMember,
bool is_root =
false,
127 typename WriteableType>
128 constexpr WriteableType to_json_schema( ParseTag<JsonParseTypes::Signed>,
129 WriteableType out_it ) {
131 if constexpr( not is_root ) {
133 out_it.add_indent( );
134 out_it.next_member( );
136 out_it = utils::output_kv( out_it, R
"("type")", R"("integer")" );
137 if constexpr( not is_root ) {
138 out_it.del_indent( );
140 out_it.next_member( );
141 if constexpr( not is_root ) {
147 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
148 constexpr WritableType
149 to_json_schema( ParseTag<JsonParseTypes::StringEscaped>,
150 WritableType out_it ) {
152 if constexpr( not is_root ) {
154 out_it.add_indent( );
155 out_it.next_member( );
157 out_it = utils::output_kv( out_it, R
"("type")", R"("string")" );
158 if constexpr( not is_root ) {
159 out_it.del_indent( );
161 out_it.next_member( );
162 if constexpr( not is_root ) {
168 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
169 constexpr WritableType
170 to_json_schema( ParseTag<JsonParseTypes::StringInsitu>, WritableType out_it ) {
171 return to_json_schema<JsonMember, is_root>(
172 ParseTag<JsonParseTypes::StringEscaped>{ }, out_it );
175 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
176 constexpr WritableType
177 to_json_schema( ParseTag<JsonParseTypes::StringRaw>,
178 WritableType out_it ) {
180 if constexpr( not is_root ) {
182 out_it.add_indent( );
183 out_it.next_member( );
185 out_it = utils::output_kv( out_it, R
"("type")", R"("string")" );
186 if constexpr( not is_root ) {
187 out_it.del_indent( );
189 out_it.next_member( );
190 if constexpr( not is_root ) {
196 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
197 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Unsigned>,
198 WritableType out_it ) {
199 if constexpr( not is_root ) {
201 out_it.add_indent( );
202 out_it.next_member( );
204 out_it = utils::output_kv( out_it, R
"("type")", R"("integer")" );
206 out_it.next_member( );
207 out_it = utils::output_kv( out_it, R
"("minimum")", "0" );
208 if constexpr( not is_root ) {
209 out_it.del_indent( );
211 out_it.next_member( );
212 if constexpr( not is_root ) {
227 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
228 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Class>,
229 WritableType out_it );
240 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
241 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Array>,
242 WritableType out_it );
244 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
245 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Null>,
246 WritableType out_it );
248 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
249 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Tuple>,
250 WritableType out_it );
252 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
253 constexpr WritableType
254 to_json_schema( ParseTag<JsonParseTypes::SizedArray>,
255 WritableType out_it );
257 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
258 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::KeyValue>,
259 WritableType out_it );
261 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
262 constexpr WritableType
263 to_json_schema( ParseTag<JsonParseTypes::KeyValueArray>,
264 WritableType out_it );
266 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
267 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Variant>,
268 WritableType out_it );
270 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
271 constexpr WritableType
272 to_json_schema( ParseTag<JsonParseTypes::VariantTagged>,
273 WritableType out_it );
275 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
276 constexpr WritableType
277 to_json_schema( ParseTag<JsonParseTypes::VariantIntrusive>,
278 WritableType out_it );
280 template<
typename,
typename>
281 struct json_class_processor;
287 template<
typename WritableType,
typename... JsonMembers>
288 struct json_class_processor<WritableType,
289 json_member_list<JsonMembers...>> {
291 static constexpr std::size_t size =
sizeof...( JsonMembers );
297 static constexpr WritableType process( WritableType out_it ) {
298 out_it = utils::output_kv( out_it, R
"("type")", R"("object")" );
300 out_it.next_member( );
301 out_it = utils::output_kv( out_it, R
"("properties")", "{" );
302 if constexpr(
sizeof...( JsonMembers ) > 0 ) {
303 out_it.add_indent( );
304 out_it.next_member( );
305 out_it = output_member_types(
306 out_it, std::index_sequence_for<JsonMembers...>{ } );
307 out_it.del_indent( );
308 out_it.next_member( );
312 out_it.next_member( );
313 out_it = utils::output_kv( out_it, R
"("required")", "[" );
315 out_it.add_indent( );
316 out_it = output_required_members( out_it );
317 out_it.del_indent( );
318 out_it.next_member( );
321 if constexpr( ( has_dependent_member_v<JsonMembers> or ... ) ) {
323 out_it.next_member( );
324 out_it = utils::output_kv( out_it, R
"("dependencies")", "{" );
325 out_it.add_indent( );
326 bool is_first =
true;
327 out_it =
static_cast<WritableType
>(
329 json_link_no_name<json_link_no_name<JsonMembers>>>(
332 out_it.del_indent( );
335 out_it.next_member( );
343 static constexpr auto indexer =
344 std::index_sequence_for<JsonMembers...>{ };
352 template<
typename JsonMember, std::
size_t Idx>
353 static constexpr WritableType output_member_type( WritableType &out_it,
361 out_it.write(
"\"", JsonMember::name,
"\":", out_it.space );
362 out_it = to_json_schema<JsonMember>(
363 ParseTag<JsonMember::expected_type>{ }, out_it );
364 if constexpr( Idx + 1 <
sizeof...( JsonMembers ) ) {
366 out_it.next_member( );
371 template<std::size_t... Is>
372 DAW_ATTRIB_INLINE
static constexpr WritableType
373 output_member_types( WritableType &out_it,
374 std::index_sequence<Is...> ) {
375 bool seen[
sizeof...( JsonMembers )]{ };
376 return static_cast<WritableType
>(
377 ( output_member_type<JsonMembers, Is>( out_it, seen ), ... ) );
380 template<
typename JsonMember>
381 static constexpr WritableType
382 output_required_member( WritableType &out_it,
bool &is_first ) {
383 if constexpr( not is_json_nullable_v<JsonMember> ) {
389 out_it.next_member( );
391 out_it = utils::copy_to_iterator( out_it, JsonMember::name );
397 template<
typename JsonMember>
398 static constexpr WritableType output_dependency( WritableType &out_it,
400 if constexpr( has_dependent_member_v<JsonMember> ) {
406 out_it.next_member( );
407 out_it.write(
"\"", JsonMember::name,
"\":", out_it.space,
"[" );
408 out_it.add_indent( );
409 out_it.next_member( );
410 out_it.write(
"\"", dependent_member_t<JsonMember>::name,
"\"" );
411 out_it.del_indent( );
412 out_it.next_member( );
418 static constexpr WritableType
419 output_required_members( WritableType &out_it ) {
420 bool is_first =
true;
421 return ( output_required_member<json_link_no_name<JsonMembers>>(
427 template<
typename WritableType,
typename... JsonMembers>
428 struct json_class_processor<WritableType,
429 json_tuple_member_list<JsonMembers...>> {
431 static constexpr std::size_t size =
sizeof...( JsonMembers );
432 static constexpr WritableType process( WritableType out_it ) {
434 out_it = utils::output_kv( out_it, R
"("type")", R"("array",)" );
435 out_it.next_member( );
436 out_it = utils::output_kv( out_it, R"("items")", "[" );
437 if constexpr(
sizeof...( JsonMembers ) > 0 ) {
438 out_it.add_indent( );
439 out_it = output_member_types( out_it );
440 out_it.del_indent( );
441 out_it.next_member( );
446 not( ( json_link_no_name<JsonMembers>::expected_type ==
447 JsonParseTypes::VariantTagged ) or
449 "A tagged variant is not supported in a tuple/ordered json "
454 static constexpr WritableType
455 output_member_types( WritableType &out_it ) {
456 bool is_first =
true;
457 return static_cast<WritableType
>(
458 ( output_member_type<json_link_no_name<JsonMembers>>( out_it,
463 template<
typename JsonMember>
464 static constexpr WritableType output_member_type( WritableType &out_it,
471 out_it.next_member( );
472 out_it = to_json_schema<JsonMember>(
473 ParseTag<JsonMember::expected_type>{ }, out_it );
478 template<
typename JsonMember,
bool is_root,
typename WritableType>
479 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Class>,
480 WritableType out_it ) {
481 using json_class_processor_t = json_class_processor<
483 json_data_contract_trait_t<json_base_type_t<JsonMember>>>;
485 if constexpr( not is_root ) {
487 out_it.add_indent( );
489 if constexpr( json_class_processor_t::size > 0 ) {
490 out_it.next_member( );
491 out_it = json_class_processor_t::process( out_it );
493 if constexpr( not is_root ) {
494 out_it.del_indent( );
496 if constexpr( not is_root ) {
497 out_it.next_member( );
503 namespace json_details {
504 template<
typename Tuple,
bool is_root,
typename WritableType,
506 DAW_ATTRIB_INLINE
constexpr WritableType
507 to_json_tuple_schema( WritableType out_it,
508 std::index_sequence<Is...> ) {
509 if constexpr( not is_root ) {
511 out_it.add_indent( );
513 out_it.next_member( );
514 out_it = utils::output_kv( out_it, R
"("type")", R"("array",)" );
515 out_it.next_member( );
516 out_it = utils::output_kv( out_it, R"("items")", "[" );
517 if constexpr(
sizeof...( Is ) > 0 ) {
518 out_it.add_indent( );
519 bool is_first =
true;
520 auto const process_member = [&is_first, &out_it](
auto Idx ) {
526 out_it.next_member( );
527 using index = daw::constant<DAW_TYPEOF( Idx )::value>;
528 using pack_element = tuple_elements_pack<Tuple>;
529 using JsonMember = json_deduced_type<
530 typename pack_element::template element_t<index::value>>;
532 out_it = to_json_schema<JsonMember>(
533 ParseTag<JsonMember::expected_type>{ }, out_it );
536 daw::empty_t expander[] = {
537 ( process_member( daw::constant_v<Is> ), daw::empty_t{ } )...,
540 out_it.del_indent( );
541 out_it.next_member( );
544 if constexpr( not is_root ) {
545 out_it.del_indent( );
547 out_it.next_member( );
548 if constexpr( not is_root ) {
555 template<
typename JsonMember,
bool is_root,
typename WritableType>
556 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Tuple>,
557 WritableType out_it ) {
558 using tuple_t =
typename JsonMember::sub_member_list;
559 return json_details::to_json_tuple_schema<tuple_t, is_root>(
561 std::make_index_sequence<tuple_elements_pack<tuple_t>::size>{ } );
564 template<
typename JsonMember,
bool is_root,
typename WritableType>
565 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Array>,
566 WritableType out_it ) {
567 if constexpr( not is_root ) {
569 out_it.add_indent( );
571 out_it.next_member( );
572 out_it = utils::output_kv( out_it, R
"("type")", R"("array",)" );
573 out_it.next_member( );
574 out_it.write( "\"items\":", out_it.space );
575 using element_t =
typename JsonMember::json_element_t;
576 out_it = to_json_schema<element_t>(
577 ParseTag<element_t::expected_type>{ }, out_it );
578 if constexpr( not is_root ) {
579 out_it.del_indent( );
581 out_it.next_member( );
582 if constexpr( not is_root ) {
588 template<
typename JsonMember,
bool is_root,
typename WritableType>
589 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Null>,
590 WritableType out_it ) {
591 using sub_member =
typename JsonMember::member_type;
592 return to_json_schema<sub_member, is_root>(
593 ParseTag<sub_member::expected_type>{ }, out_it );
596 template<
typename JsonMember,
bool is_root,
typename WritableType>
597 constexpr WritableType
598 to_json_schema( ParseTag<JsonParseTypes::SizedArray>,
599 WritableType out_it ) {
600 return to_json_schema<JsonMember, is_root>(
601 ParseTag<JsonParseTypes::Array>{ }, out_it );
604 template<
typename JsonMember,
bool is_root,
typename WritableType>
605 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::KeyValue>,
606 WritableType out_it ) {
607 if constexpr( not is_root ) {
609 out_it.add_indent( );
611 out_it.next_member( );
612 out_it = utils::output_kv( out_it, R
"("type")", R"("object")" );
614 out_it.next_member( );
615 out_it = utils::output_kv( out_it, R
"("additionalProperties")", "" );
616 using element_t =
typename JsonMember::json_element_t;
617 out_it = to_json_schema<element_t>(
618 ParseTag<element_t::expected_type>{ }, out_it );
619 if constexpr( not is_root ) {
620 out_it.del_indent( );
622 out_it.next_member( );
623 if constexpr( not is_root ) {
629 template<
typename JsonMember,
bool is_root,
typename WritableType>
630 constexpr WritableType
631 to_json_schema( ParseTag<JsonParseTypes::KeyValueArray>,
632 WritableType out_it ) {
633 if constexpr( not is_root ) {
635 out_it.add_indent( );
637 out_it.next_member( );
638 out_it = utils::output_kv( out_it, R
"("type")", R"("array",)" );
639 out_it.next_member( );
640 out_it.write( "\"items\":", out_it.space );
641 using element_t =
typename JsonMember::json_class_t;
642 out_it = to_json_schema<element_t>(
643 ParseTag<element_t::expected_type>{ }, out_it );
644 if constexpr( not is_root ) {
645 out_it.del_indent( );
647 out_it.next_member( );
648 if constexpr( not is_root ) {
654 template<
typename...>
655 struct variant_element_types;
657 template<
typename... JsonElements>
658 struct variant_element_types<json_variant_type_list<JsonElements...>> {
660 template<
typename JsonElement,
typename WritableType>
661 static constexpr WritableType output_element( WritableType out_it,
668 out_it.next_member( );
669 return to_json_schema<JsonElement>(
670 ParseTag<JsonElement::expected_type>{ }, out_it );
673 template<
typename WritableType>
674 static constexpr WritableType output_elements( WritableType out_it ) {
675 bool is_first =
true;
676 return static_cast<WritableType
>(
677 ( output_element<JsonElements>( out_it, is_first ), ... ) );
681 template<
typename JsonMember,
bool is_root,
typename WritableType>
682 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Variant>,
683 WritableType out_it ) {
684 if constexpr( not is_root ) {
686 out_it.add_indent( );
688 out_it.next_member( );
689 out_it = utils::output_kv( out_it, R
"("oneOf")", "[" );
690 using elements_t =
typename JsonMember::json_elements;
691 if constexpr( daw::pack_size_v<elements_t> != 0 ) {
692 out_it.add_indent( );
693 out_it = variant_element_types<elements_t>::output_elements( out_it );
694 out_it.del_indent( );
695 out_it.next_member( );
698 if constexpr( not is_root ) {
699 out_it.del_indent( );
701 out_it.next_member( );
702 if constexpr( not is_root ) {
708 template<
typename JsonMember,
bool is_root,
typename WritableType>
709 constexpr WritableType
710 to_json_schema( ParseTag<JsonParseTypes::VariantTagged>,
711 WritableType out_it ) {
712 static_assert( not is_root,
713 "Attempt to have a tagged variant as root object. This "
716 out_it.add_indent( );
717 out_it.next_member( );
718 out_it = utils::output_kv( out_it, R
"("oneOf")", "[" );
719 using elements_t =
typename JsonMember::json_elements;
720 if constexpr( daw::pack_size_v<elements_t> != 0 ) {
721 out_it.add_indent( );
722 out_it = variant_element_types<elements_t>::output_elements( out_it );
723 out_it.del_indent( );
724 out_it.next_member( );
727 out_it.del_indent( );
728 out_it.next_member( );
733 template<
typename JsonMember,
bool is_root,
typename WritableType>
734 constexpr WritableType
735 to_json_schema( ParseTag<JsonParseTypes::VariantIntrusive>,
736 WritableType out_it ) {
737 if constexpr( not is_root ) {
739 out_it.add_indent( );
741 out_it.next_member( );
742 out_it = utils::output_kv( out_it, R
"("oneOf")", "[" );
743 using elements_t =
typename JsonMember::json_elements;
744 if constexpr( daw::pack_size_v<elements_t> != 0 ) {
745 out_it.add_indent( );
746 out_it = variant_element_types<elements_t>::output_elements( out_it );
747 out_it.del_indent( );
748 out_it.next_member( );
751 if constexpr( not is_root ) {
752 out_it.del_indent( );
754 out_it.next_member( );
755 if constexpr( not is_root ) {
770 template<
typename T,
typename WritableType,
auto... PolicyFlags>
771 constexpr WritableType to_json_schema(
772 WritableType &it, std::string_view
id, std::string_view title,
773 options::output_flags_t<PolicyFlags...> = options::output_flags<> ) {
775 auto out_it = json_details::make_output_iterator<PolicyFlags...>( it );
778 out_it.add_indent( );
779 out_it.next_member( );
780 out_it = utils::output_kv(
783 R"("https://json-schema.org/draft/2020-12/schema",)" );
784 out_it.next_member( );
785 out_it = utils::output_kv( out_it, R"("$id")", "\"" );
786 out_it = utils::copy_to_iterator( out_it,
id );
787 out_it = utils::copy_to_iterator( out_it, R
"(",)" );
788 out_it.next_member( );
789 out_it = utils::output_kv( out_it, R"("title")", "\"" );
790 out_it = utils::copy_to_iterator( out_it, title );
791 out_it = utils::copy_to_iterator( out_it, R
"(",)" );
793 out_it = json_details::to_json_schema<json_type, true>(
795 out_it.del_indent( );
796 out_it.next_member( );
798 return out_it.get( );
810 template<
typename T,
typename Result = std::string,
auto... PolicyFlags>
812 to_json_schema( std::string_view
id, std::string_view title,
813 options::output_flags_t<PolicyFlags...> flags =
814 options::output_flags<> ) {
815 auto result = Result( );
817 (void)to_json_schema<T>( result,
id, title, flags );