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>,
171 WritableType out_it ) {
172 return to_json_schema<JsonMember, is_root>(
173 ParseTag<JsonParseTypes::StringEscaped>{ }, out_it );
176 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
177 constexpr WritableType
178 to_json_schema( ParseTag<JsonParseTypes::StringRaw>,
179 WritableType out_it ) {
181 if constexpr( not is_root ) {
183 out_it.add_indent( );
184 out_it.next_member( );
186 out_it = utils::output_kv( out_it, R
"("type")", R"("string")" );
187 if constexpr( not is_root ) {
188 out_it.del_indent( );
190 out_it.next_member( );
191 if constexpr( not is_root ) {
197 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
198 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Unsigned>,
199 WritableType out_it ) {
200 if constexpr( not is_root ) {
202 out_it.add_indent( );
203 out_it.next_member( );
205 out_it = utils::output_kv( out_it, R
"("type")", R"("integer")" );
207 out_it.next_member( );
208 out_it = utils::output_kv( out_it, R
"("minimum")", "0" );
209 if constexpr( not is_root ) {
210 out_it.del_indent( );
212 out_it.next_member( );
213 if constexpr( not is_root ) {
228 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
229 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Class>,
230 WritableType out_it );
241 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
242 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Array>,
243 WritableType out_it );
245 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
246 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Null>,
247 WritableType out_it );
249 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
250 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Tuple>,
251 WritableType out_it );
253 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
254 constexpr WritableType
255 to_json_schema( ParseTag<JsonParseTypes::SizedArray>,
256 WritableType out_it );
258 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
259 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::KeyValue>,
260 WritableType out_it );
262 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
263 constexpr WritableType
264 to_json_schema( ParseTag<JsonParseTypes::KeyValueArray>,
265 WritableType out_it );
267 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
268 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Variant>,
269 WritableType out_it );
271 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
272 constexpr WritableType
273 to_json_schema( ParseTag<JsonParseTypes::VariantTagged>,
274 WritableType out_it );
276 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
277 constexpr WritableType
278 to_json_schema( ParseTag<JsonParseTypes::VariantIntrusive>,
279 WritableType out_it );
281 template<
typename,
typename>
282 struct json_class_processor;
288 template<
typename WritableType,
typename... JsonMembers>
289 struct json_class_processor<WritableType,
290 json_member_list<JsonMembers...>> {
292 static constexpr std::size_t size =
sizeof...( JsonMembers );
298 static constexpr WritableType process( WritableType out_it ) {
299 out_it = utils::output_kv( out_it, R
"("type")", R"("object")" );
301 out_it.next_member( );
302 out_it = utils::output_kv( out_it, R
"("properties")", "{" );
303 if constexpr(
sizeof...( JsonMembers ) > 0 ) {
304 out_it.add_indent( );
305 out_it.next_member( );
306 out_it = output_member_types(
307 out_it, std::index_sequence_for<JsonMembers...>{ } );
308 out_it.del_indent( );
309 out_it.next_member( );
313 out_it.next_member( );
314 out_it = utils::output_kv( out_it, R
"("required")", "[" );
316 out_it.add_indent( );
317 out_it = output_required_members( out_it );
318 out_it.del_indent( );
319 out_it.next_member( );
322 if constexpr( ( has_dependent_member_v<JsonMembers> or ... ) ) {
324 out_it.next_member( );
325 out_it = utils::output_kv( out_it, R
"("dependencies")", "{" );
326 out_it.add_indent( );
327 bool is_first =
true;
328 out_it =
static_cast<WritableType
>(
330 json_link_no_name<json_link_no_name<JsonMembers>>>(
333 out_it.del_indent( );
336 out_it.next_member( );
344 static constexpr auto indexer =
345 std::index_sequence_for<JsonMembers...>{ };
353 template<
typename JsonMember, std::
size_t Idx>
354 static constexpr WritableType output_member_type( WritableType &out_it,
363 '"', encode_member_name_v<JsonMember>,
"\":", out_it.space );
364 out_it = to_json_schema<JsonMember>(
365 ParseTag<JsonMember::expected_type>{ }, out_it );
366 if constexpr( Idx + 1 <
sizeof...( JsonMembers ) ) {
368 out_it.next_member( );
373 template<std::size_t... Is>
374 DAW_ATTRIB_INLINE
static constexpr WritableType
375 output_member_types( WritableType &out_it,
376 std::index_sequence<Is...> ) {
377 bool seen[
sizeof...( JsonMembers )]{ };
378 return static_cast<WritableType
>(
379 ( output_member_type<JsonMembers, Is>( out_it, seen ), ... ) );
382 template<
typename JsonMember>
383 static constexpr WritableType
384 output_required_member( WritableType &out_it,
bool &is_first ) {
385 if constexpr( not is_json_nullable_v<JsonMember> ) {
391 out_it.next_member( );
392 out_it.write(
'"', encode_member_name_v<JsonMember>,
'"' );
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( );
408 '"', encode_member_name_v<JsonMember>,
"\":", out_it.space,
"[" );
409 out_it.add_indent( );
410 out_it.next_member( );
412 '"', encode_member_name_v<dependent_member_t<JsonMember>>,
'"' );
413 out_it.del_indent( );
414 out_it.next_member( );
420 static constexpr WritableType
421 output_required_members( WritableType &out_it ) {
422 bool is_first =
true;
423 return ( output_required_member<json_link_no_name<JsonMembers>>(
429 template<
typename WritableType,
typename... JsonMembers>
430 struct json_class_processor<WritableType,
431 json_tuple_member_list<JsonMembers...>> {
433 static constexpr std::size_t size =
sizeof...( JsonMembers );
434 static constexpr WritableType process( WritableType out_it ) {
436 out_it = utils::output_kv( out_it, R
"("type")", R"("array",)" );
437 out_it.next_member( );
438 out_it = utils::output_kv( out_it, R"("items")", "[" );
439 if constexpr(
sizeof...( JsonMembers ) > 0 ) {
440 out_it.add_indent( );
441 out_it = output_member_types( out_it );
442 out_it.del_indent( );
443 out_it.next_member( );
448 not( ( json_link_no_name<JsonMembers>::expected_type ==
449 JsonParseTypes::VariantTagged ) or
451 "A tagged variant is not supported in a tuple/ordered json "
456 static constexpr WritableType
457 output_member_types( WritableType &out_it ) {
458 bool is_first =
true;
459 return static_cast<WritableType
>(
460 ( output_member_type<json_link_no_name<JsonMembers>>( out_it,
465 template<
typename JsonMember>
466 static constexpr WritableType output_member_type( WritableType &out_it,
473 out_it.next_member( );
474 out_it = to_json_schema<JsonMember>(
475 ParseTag<JsonMember::expected_type>{ }, out_it );
480 template<
typename JsonMember,
bool is_root,
typename WritableType>
481 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Class>,
482 WritableType out_it ) {
483 using json_class_processor_t = json_class_processor<
485 json_data_contract_trait_t<json_base_type_t<JsonMember>>>;
487 if constexpr( not is_root ) {
489 out_it.add_indent( );
491 if constexpr( json_class_processor_t::size > 0 ) {
492 out_it.next_member( );
493 out_it = json_class_processor_t::process( out_it );
495 if constexpr( not is_root ) {
496 out_it.del_indent( );
498 if constexpr( not is_root ) {
499 out_it.next_member( );
505 namespace json_details {
506 template<
typename Tuple,
bool is_root,
typename WritableType,
508 DAW_ATTRIB_INLINE
constexpr WritableType
509 to_json_tuple_schema( WritableType out_it,
510 std::index_sequence<Is...> ) {
511 if constexpr( not is_root ) {
513 out_it.add_indent( );
515 out_it.next_member( );
516 out_it = utils::output_kv( out_it, R
"("type")", R"("array",)" );
517 out_it.next_member( );
518 out_it = utils::output_kv( out_it, R"("items")", "[" );
519 if constexpr(
sizeof...( Is ) > 0 ) {
520 out_it.add_indent( );
521 bool is_first =
true;
522 auto const process_member = [&is_first, &out_it](
auto Idx ) {
528 out_it.next_member( );
529 using index = daw::constant<DAW_TYPEOF( Idx )::value>;
530 using pack_element = tuple_elements_pack<Tuple>;
531 using JsonMember = json_deduced_type<
532 typename pack_element::template element_t<index::value>>;
534 out_it = to_json_schema<JsonMember>(
535 ParseTag<JsonMember::expected_type>{ }, out_it );
538 daw::empty_t expander[] = {
539 ( process_member( daw::constant_v<Is> ), daw::empty_t{ } )...,
542 out_it.del_indent( );
543 out_it.next_member( );
546 if constexpr( not is_root ) {
547 out_it.del_indent( );
549 out_it.next_member( );
550 if constexpr( not is_root ) {
557 template<
typename JsonMember,
bool is_root,
typename WritableType>
558 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Tuple>,
559 WritableType out_it ) {
560 using tuple_t =
typename JsonMember::sub_member_list;
561 return json_details::to_json_tuple_schema<tuple_t, is_root>(
563 std::make_index_sequence<tuple_elements_pack<tuple_t>::size>{ } );
566 template<
typename JsonMember,
bool is_root,
typename WritableType>
567 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Array>,
568 WritableType out_it ) {
569 if constexpr( not is_root ) {
571 out_it.add_indent( );
573 out_it.next_member( );
574 out_it = utils::output_kv( out_it, R
"("type")", R"("array",)" );
575 out_it.next_member( );
576 out_it.write( "\"items\":", out_it.space );
577 using element_t =
typename JsonMember::json_element_t;
578 out_it = to_json_schema<element_t>(
579 ParseTag<element_t::expected_type>{ }, out_it );
580 if constexpr( not is_root ) {
581 out_it.del_indent( );
583 out_it.next_member( );
584 if constexpr( not is_root ) {
590 template<
typename JsonMember,
bool is_root,
typename WritableType>
591 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Null>,
592 WritableType out_it ) {
593 using sub_member =
typename JsonMember::member_type;
594 return to_json_schema<sub_member, is_root>(
595 ParseTag<sub_member::expected_type>{ }, out_it );
598 template<
typename JsonMember,
bool is_root,
typename WritableType>
599 constexpr WritableType
600 to_json_schema( ParseTag<JsonParseTypes::SizedArray>,
601 WritableType out_it ) {
602 return to_json_schema<JsonMember, is_root>(
603 ParseTag<JsonParseTypes::Array>{ }, out_it );
606 template<
typename JsonMember,
bool is_root,
typename WritableType>
607 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::KeyValue>,
608 WritableType out_it ) {
609 if constexpr( not is_root ) {
611 out_it.add_indent( );
613 out_it.next_member( );
614 out_it = utils::output_kv( out_it, R
"("type")", R"("object")" );
616 out_it.next_member( );
617 out_it = utils::output_kv( out_it, R
"("additionalProperties")", "" );
618 using element_t =
typename JsonMember::json_element_t;
619 out_it = to_json_schema<element_t>(
620 ParseTag<element_t::expected_type>{ }, out_it );
621 if constexpr( not is_root ) {
622 out_it.del_indent( );
624 out_it.next_member( );
625 if constexpr( not is_root ) {
631 template<
typename JsonMember,
bool is_root,
typename WritableType>
632 constexpr WritableType
633 to_json_schema( ParseTag<JsonParseTypes::KeyValueArray>,
634 WritableType out_it ) {
635 if constexpr( not is_root ) {
637 out_it.add_indent( );
639 out_it.next_member( );
640 out_it = utils::output_kv( out_it, R
"("type")", R"("array",)" );
641 out_it.next_member( );
642 out_it.write( "\"items\":", out_it.space );
643 using element_t =
typename JsonMember::json_class_t;
644 out_it = to_json_schema<element_t>(
645 ParseTag<element_t::expected_type>{ }, out_it );
646 if constexpr( not is_root ) {
647 out_it.del_indent( );
649 out_it.next_member( );
650 if constexpr( not is_root ) {
656 template<
typename...>
657 struct variant_element_types;
659 template<
typename... JsonElements>
660 struct variant_element_types<json_variant_type_list<JsonElements...>> {
662 template<
typename JsonElement,
typename WritableType>
663 static constexpr WritableType output_element( WritableType out_it,
670 out_it.next_member( );
671 return to_json_schema<JsonElement>(
672 ParseTag<JsonElement::expected_type>{ }, out_it );
675 template<
typename WritableType>
676 static constexpr WritableType output_elements( WritableType out_it ) {
677 bool is_first =
true;
678 return static_cast<WritableType
>(
679 ( output_element<JsonElements>( out_it, is_first ), ... ) );
683 template<
typename JsonMember,
bool is_root,
typename WritableType>
684 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Variant>,
685 WritableType out_it ) {
686 if constexpr( not is_root ) {
688 out_it.add_indent( );
690 out_it.next_member( );
691 out_it = utils::output_kv( out_it, R
"("oneOf")", "[" );
692 using elements_t =
typename JsonMember::json_elements;
693 if constexpr( daw::pack_size_v<elements_t> != 0 ) {
694 out_it.add_indent( );
695 out_it = variant_element_types<elements_t>::output_elements( out_it );
696 out_it.del_indent( );
697 out_it.next_member( );
700 if constexpr( not is_root ) {
701 out_it.del_indent( );
703 out_it.next_member( );
704 if constexpr( not is_root ) {
710 template<
typename JsonMember,
bool is_root,
typename WritableType>
711 constexpr WritableType
712 to_json_schema( ParseTag<JsonParseTypes::VariantTagged>,
713 WritableType out_it ) {
714 static_assert( not is_root,
715 "Attempt to have a tagged variant as root object. This "
718 out_it.add_indent( );
719 out_it.next_member( );
720 out_it = utils::output_kv( out_it, R
"("oneOf")", "[" );
721 using elements_t =
typename JsonMember::json_elements;
722 if constexpr( daw::pack_size_v<elements_t> != 0 ) {
723 out_it.add_indent( );
724 out_it = variant_element_types<elements_t>::output_elements( out_it );
725 out_it.del_indent( );
726 out_it.next_member( );
729 out_it.del_indent( );
730 out_it.next_member( );
735 template<
typename JsonMember,
bool is_root,
typename WritableType>
736 constexpr WritableType
737 to_json_schema( ParseTag<JsonParseTypes::VariantIntrusive>,
738 WritableType out_it ) {
739 if constexpr( not is_root ) {
741 out_it.add_indent( );
743 out_it.next_member( );
744 out_it = utils::output_kv( out_it, R
"("oneOf")", "[" );
745 using elements_t =
typename JsonMember::json_elements;
746 if constexpr( daw::pack_size_v<elements_t> != 0 ) {
747 out_it.add_indent( );
748 out_it = variant_element_types<elements_t>::output_elements( out_it );
749 out_it.del_indent( );
750 out_it.next_member( );
753 if constexpr( not is_root ) {
754 out_it.del_indent( );
756 out_it.next_member( );
757 if constexpr( not is_root ) {
772 template<
typename T,
typename WritableType,
auto... PolicyFlags>
773 constexpr WritableType to_json_schema(
774 WritableType &it, std::string_view
id, std::string_view title,
775 options::output_flags_t<PolicyFlags...> = options::output_flags<> ) {
777 auto out_it = json_details::make_output_iterator<PolicyFlags...>( it );
780 out_it.add_indent( );
781 out_it.next_member( );
782 out_it = utils::output_kv(
785 R"("https://json-schema.org/draft/2020-12/schema",)" );
786 out_it.next_member( );
787 out_it = utils::output_kv( out_it, R"("$id")", "\"" );
788 out_it = utils::copy_to_iterator( out_it,
id );
789 out_it = utils::copy_to_iterator( out_it, R
"(",)" );
790 out_it.next_member( );
791 out_it = utils::output_kv( out_it, R"("title")", "\"" );
792 out_it = utils::copy_to_iterator( out_it, title );
793 out_it = utils::copy_to_iterator( out_it, R
"(",)" );
795 out_it = json_details::to_json_schema<json_type, true>(
797 out_it.del_indent( );
798 out_it.next_member( );
800 return out_it.get( );
812 template<
typename T,
typename Result = std::string,
auto... PolicyFlags>
814 to_json_schema( std::string_view
id, std::string_view title,
815 options::output_flags_t<PolicyFlags...> flags =
816 options::output_flags<> ) {
817 auto result = Result( );
819 (void)to_json_schema<T>( result,
id, title, flags );