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::StringRaw>,
171 WritableType out_it ) {
173 if constexpr( not is_root ) {
175 out_it.add_indent( );
176 out_it.next_member( );
178 out_it = utils::output_kv( out_it, R
"("type")", R"("string")" );
179 if constexpr( not is_root ) {
180 out_it.del_indent( );
182 out_it.next_member( );
183 if constexpr( not is_root ) {
189 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
190 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Unsigned>,
191 WritableType out_it ) {
192 if constexpr( not is_root ) {
194 out_it.add_indent( );
195 out_it.next_member( );
197 out_it = utils::output_kv( out_it, R
"("type")", R"("integer")" );
199 out_it.next_member( );
200 out_it = utils::output_kv( out_it, R
"("minimum")", "0" );
201 if constexpr( not is_root ) {
202 out_it.del_indent( );
204 out_it.next_member( );
205 if constexpr( not is_root ) {
220 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
221 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Class>,
222 WritableType out_it );
233 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
234 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Array>,
235 WritableType out_it );
237 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
238 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Null>,
239 WritableType out_it );
241 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
242 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Tuple>,
243 WritableType out_it );
245 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
246 constexpr WritableType
247 to_json_schema( ParseTag<JsonParseTypes::SizedArray>,
248 WritableType out_it );
250 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
251 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::KeyValue>,
252 WritableType out_it );
254 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
255 constexpr WritableType
256 to_json_schema( ParseTag<JsonParseTypes::KeyValueArray>,
257 WritableType out_it );
259 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
260 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Variant>,
261 WritableType out_it );
263 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
264 constexpr WritableType
265 to_json_schema( ParseTag<JsonParseTypes::VariantTagged>,
266 WritableType out_it );
268 template<
typename JsonMember,
bool is_root = false,
typename WritableType>
269 constexpr WritableType
270 to_json_schema( ParseTag<JsonParseTypes::VariantIntrusive>,
271 WritableType out_it );
273 template<
typename,
typename>
274 struct json_class_processor;
280 template<
typename WritableType,
typename... JsonMembers>
281 struct json_class_processor<WritableType,
282 json_member_list<JsonMembers...>> {
284 static constexpr std::size_t size =
sizeof...( JsonMembers );
290 static constexpr WritableType process( WritableType out_it ) {
291 out_it = utils::output_kv( out_it, R
"("type")", R"("object")" );
293 out_it.next_member( );
294 out_it = utils::output_kv( out_it, R
"("properties")", "{" );
295 if constexpr(
sizeof...( JsonMembers ) > 0 ) {
296 out_it.add_indent( );
297 out_it.next_member( );
298 out_it = output_member_types(
299 out_it, std::index_sequence_for<JsonMembers...>{ } );
300 out_it.del_indent( );
301 out_it.next_member( );
305 out_it.next_member( );
306 out_it = utils::output_kv( out_it, R
"("required")", "[" );
308 out_it.add_indent( );
309 out_it = output_required_members( out_it );
310 out_it.del_indent( );
311 out_it.next_member( );
314 if constexpr( ( has_dependent_member_v<JsonMembers> or ... ) ) {
316 out_it.next_member( );
317 out_it = utils::output_kv( out_it, R
"("dependencies")", "{" );
318 out_it.add_indent( );
319 bool is_first =
true;
320 out_it =
static_cast<WritableType
>(
322 json_link_no_name<json_link_no_name<JsonMembers>>>(
325 out_it.del_indent( );
328 out_it.next_member( );
336 static constexpr auto indexer =
337 std::index_sequence_for<JsonMembers...>{ };
345 template<
typename JsonMember, std::
size_t Idx>
346 static constexpr WritableType output_member_type( WritableType &out_it,
354 out_it.write(
"\"", JsonMember::name,
"\":", out_it.space );
355 out_it = to_json_schema<JsonMember>(
356 ParseTag<JsonMember::expected_type>{ }, out_it );
357 if constexpr( Idx + 1 <
sizeof...( JsonMembers ) ) {
359 out_it.next_member( );
364 template<std::size_t... Is>
365 DAW_ATTRIB_INLINE
static constexpr WritableType
366 output_member_types( WritableType &out_it,
367 std::index_sequence<Is...> ) {
368 bool seen[
sizeof...( JsonMembers )]{ };
369 return static_cast<WritableType
>(
370 ( output_member_type<JsonMembers, Is>( out_it, seen ), ... ) );
373 template<
typename JsonMember>
374 static constexpr WritableType
375 output_required_member( WritableType &out_it,
bool &is_first ) {
376 if constexpr( not is_json_nullable_v<JsonMember> ) {
382 out_it.next_member( );
384 out_it = utils::copy_to_iterator( out_it, JsonMember::name );
390 template<
typename JsonMember>
391 static constexpr WritableType output_dependency( WritableType &out_it,
393 if constexpr( has_dependent_member_v<JsonMember> ) {
399 out_it.next_member( );
400 out_it.write(
"\"", JsonMember::name,
"\":", out_it.space,
"[" );
401 out_it.add_indent( );
402 out_it.next_member( );
403 out_it.write(
"\"", dependent_member_t<JsonMember>::name,
"\"" );
404 out_it.del_indent( );
405 out_it.next_member( );
411 static constexpr WritableType
412 output_required_members( WritableType &out_it ) {
413 bool is_first =
true;
414 return ( output_required_member<json_link_no_name<JsonMembers>>(
420 template<
typename WritableType,
typename... JsonMembers>
421 struct json_class_processor<WritableType,
422 json_tuple_member_list<JsonMembers...>> {
424 static constexpr std::size_t size =
sizeof...( JsonMembers );
425 static constexpr WritableType process( WritableType out_it ) {
427 out_it = utils::output_kv( out_it, R
"("type")", R"("array",)" );
428 out_it.next_member( );
429 out_it = utils::output_kv( out_it, R"("items")", "[" );
430 if constexpr(
sizeof...( JsonMembers ) > 0 ) {
431 out_it.add_indent( );
432 out_it = output_member_types( out_it );
433 out_it.del_indent( );
434 out_it.next_member( );
439 not( ( json_link_no_name<JsonMembers>::expected_type ==
440 JsonParseTypes::VariantTagged ) or
442 "A tagged variant is not supported in a tuple/ordered json "
447 static constexpr WritableType
448 output_member_types( WritableType &out_it ) {
449 bool is_first =
true;
450 return static_cast<WritableType
>(
451 ( output_member_type<json_link_no_name<JsonMembers>>( out_it,
456 template<
typename JsonMember>
457 static constexpr WritableType output_member_type( WritableType &out_it,
464 out_it.next_member( );
465 out_it = to_json_schema<JsonMember>(
466 ParseTag<JsonMember::expected_type>{ }, out_it );
471 template<
typename JsonMember,
bool is_root,
typename WritableType>
472 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Class>,
473 WritableType out_it ) {
474 using json_class_processor_t = json_class_processor<
476 json_data_contract_trait_t<json_base_type_t<JsonMember>>>;
478 if constexpr( not is_root ) {
480 out_it.add_indent( );
482 if constexpr( json_class_processor_t::size > 0 ) {
483 out_it.next_member( );
484 out_it = json_class_processor_t::process( out_it );
486 if constexpr( not is_root ) {
487 out_it.del_indent( );
489 if constexpr( not is_root ) {
490 out_it.next_member( );
496 namespace json_details {
497 template<
typename Tuple,
bool is_root,
typename WritableType,
499 DAW_ATTRIB_INLINE
constexpr WritableType
500 to_json_tuple_schema( WritableType out_it,
501 std::index_sequence<Is...> ) {
502 if constexpr( not is_root ) {
504 out_it.add_indent( );
506 out_it.next_member( );
507 out_it = utils::output_kv( out_it, R
"("type")", R"("array",)" );
508 out_it.next_member( );
509 out_it = utils::output_kv( out_it, R"("items")", "[" );
510 if constexpr(
sizeof...( Is ) > 0 ) {
511 out_it.add_indent( );
512 bool is_first =
true;
513 auto const process_member = [&is_first, &out_it](
auto Idx ) {
519 out_it.next_member( );
520 using index = daw::constant<DAW_TYPEOF( Idx )::value>;
521 using pack_element = tuple_elements_pack<Tuple>;
522 using JsonMember = json_deduced_type<
523 typename pack_element::template element_t<index::value>>;
525 out_it = to_json_schema<JsonMember>(
526 ParseTag<JsonMember::expected_type>{ }, out_it );
529 daw::empty_t expander[] = {
530 ( process_member( daw::constant_v<Is> ), daw::empty_t{ } )...,
533 out_it.del_indent( );
534 out_it.next_member( );
537 if constexpr( not is_root ) {
538 out_it.del_indent( );
540 out_it.next_member( );
541 if constexpr( not is_root ) {
548 template<
typename JsonMember,
bool is_root,
typename WritableType>
549 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Tuple>,
550 WritableType out_it ) {
551 using tuple_t =
typename JsonMember::sub_member_list;
552 return json_details::to_json_tuple_schema<tuple_t, is_root>(
554 std::make_index_sequence<tuple_elements_pack<tuple_t>::size>{ } );
557 template<
typename JsonMember,
bool is_root,
typename WritableType>
558 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Array>,
559 WritableType out_it ) {
560 if constexpr( not is_root ) {
562 out_it.add_indent( );
564 out_it.next_member( );
565 out_it = utils::output_kv( out_it, R
"("type")", R"("array",)" );
566 out_it.next_member( );
567 out_it.write( "\"items\":", out_it.space );
568 using element_t =
typename JsonMember::json_element_t;
569 out_it = to_json_schema<element_t>(
570 ParseTag<element_t::expected_type>{ }, out_it );
571 if constexpr( not is_root ) {
572 out_it.del_indent( );
574 out_it.next_member( );
575 if constexpr( not is_root ) {
581 template<
typename JsonMember,
bool is_root,
typename WritableType>
582 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Null>,
583 WritableType out_it ) {
584 using sub_member =
typename JsonMember::member_type;
585 return to_json_schema<sub_member, is_root>(
586 ParseTag<sub_member::expected_type>{ }, out_it );
589 template<
typename JsonMember,
bool is_root,
typename WritableType>
590 constexpr WritableType
591 to_json_schema( ParseTag<JsonParseTypes::SizedArray>,
592 WritableType out_it ) {
593 return to_json_schema<JsonMember, is_root>(
594 ParseTag<JsonParseTypes::Array>{ }, out_it );
597 template<
typename JsonMember,
bool is_root,
typename WritableType>
598 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::KeyValue>,
599 WritableType out_it ) {
600 if constexpr( not is_root ) {
602 out_it.add_indent( );
604 out_it.next_member( );
605 out_it = utils::output_kv( out_it, R
"("type")", R"("object")" );
607 out_it.next_member( );
608 out_it = utils::output_kv( out_it, R
"("additionalProperties")", "" );
609 using element_t =
typename JsonMember::json_element_t;
610 out_it = to_json_schema<element_t>(
611 ParseTag<element_t::expected_type>{ }, out_it );
612 if constexpr( not is_root ) {
613 out_it.del_indent( );
615 out_it.next_member( );
616 if constexpr( not is_root ) {
622 template<
typename JsonMember,
bool is_root,
typename WritableType>
623 constexpr WritableType
624 to_json_schema( ParseTag<JsonParseTypes::KeyValueArray>,
625 WritableType out_it ) {
626 if constexpr( not is_root ) {
628 out_it.add_indent( );
630 out_it.next_member( );
631 out_it = utils::output_kv( out_it, R
"("type")", R"("array",)" );
632 out_it.next_member( );
633 out_it.write( "\"items\":", out_it.space );
634 using element_t =
typename JsonMember::json_class_t;
635 out_it = to_json_schema<element_t>(
636 ParseTag<element_t::expected_type>{ }, out_it );
637 if constexpr( not is_root ) {
638 out_it.del_indent( );
640 out_it.next_member( );
641 if constexpr( not is_root ) {
647 template<
typename...>
648 struct variant_element_types;
650 template<
typename... JsonElements>
651 struct variant_element_types<json_variant_type_list<JsonElements...>> {
653 template<
typename JsonElement,
typename WritableType>
654 static constexpr WritableType output_element( WritableType out_it,
661 out_it.next_member( );
662 return to_json_schema<JsonElement>(
663 ParseTag<JsonElement::expected_type>{ }, out_it );
666 template<
typename WritableType>
667 static constexpr WritableType output_elements( WritableType out_it ) {
668 bool is_first =
true;
669 return static_cast<WritableType
>(
670 ( output_element<JsonElements>( out_it, is_first ), ... ) );
674 template<
typename JsonMember,
bool is_root,
typename WritableType>
675 constexpr WritableType to_json_schema( ParseTag<JsonParseTypes::Variant>,
676 WritableType out_it ) {
677 if constexpr( not is_root ) {
679 out_it.add_indent( );
681 out_it.next_member( );
682 out_it = utils::output_kv( out_it, R
"("oneOf")", "[" );
683 using elements_t =
typename JsonMember::json_elements;
684 if constexpr( daw::pack_size_v<elements_t> != 0 ) {
685 out_it.add_indent( );
686 out_it = variant_element_types<elements_t>::output_elements( out_it );
687 out_it.del_indent( );
688 out_it.next_member( );
691 if constexpr( not is_root ) {
692 out_it.del_indent( );
694 out_it.next_member( );
695 if constexpr( not is_root ) {
701 template<
typename JsonMember,
bool is_root,
typename WritableType>
702 constexpr WritableType
703 to_json_schema( ParseTag<JsonParseTypes::VariantTagged>,
704 WritableType out_it ) {
705 static_assert( not is_root,
706 "Attempt to have a tagged variant as root object. This "
709 out_it.add_indent( );
710 out_it.next_member( );
711 out_it = utils::output_kv( out_it, R
"("oneOf")", "[" );
712 using elements_t =
typename JsonMember::json_elements;
713 if constexpr( daw::pack_size_v<elements_t> != 0 ) {
714 out_it.add_indent( );
715 out_it = variant_element_types<elements_t>::output_elements( out_it );
716 out_it.del_indent( );
717 out_it.next_member( );
720 out_it.del_indent( );
721 out_it.next_member( );
726 template<
typename JsonMember,
bool is_root,
typename WritableType>
727 constexpr WritableType
728 to_json_schema( ParseTag<JsonParseTypes::VariantIntrusive>,
729 WritableType out_it ) {
730 if constexpr( not is_root ) {
732 out_it.add_indent( );
734 out_it.next_member( );
735 out_it = utils::output_kv( out_it, R
"("oneOf")", "[" );
736 using elements_t =
typename JsonMember::json_elements;
737 if constexpr( daw::pack_size_v<elements_t> != 0 ) {
738 out_it.add_indent( );
739 out_it = variant_element_types<elements_t>::output_elements( out_it );
740 out_it.del_indent( );
741 out_it.next_member( );
744 if constexpr( not is_root ) {
745 out_it.del_indent( );
747 out_it.next_member( );
748 if constexpr( not is_root ) {
763 template<
typename T,
typename WritableType,
auto... PolicyFlags>
764 constexpr WritableType to_json_schema(
765 WritableType &it, std::string_view
id, std::string_view title,
766 options::output_flags_t<PolicyFlags...> = options::output_flags<> ) {
768 auto out_it = [&it] {
769 if constexpr( is_serialization_policy_v<WritableType> ) {
770 if constexpr(
sizeof...( PolicyFlags ) == 0 ) {
774 json_details::serialization::set_bits(
775 WritableType::policy_flags( ),
776 PolicyFlags... )>( it.get( ) );
781 options::output_flags_t<PolicyFlags...>::value>( it );
785 out_it.add_indent( );
786 out_it.next_member( );
787 out_it = utils::output_kv(
790 R"("https://json-schema.org/draft/2020-12/schema",)" );
791 out_it.next_member( );
792 out_it = utils::output_kv( out_it, R"("$id")", "\"" );
793 out_it = utils::copy_to_iterator( out_it,
id );
794 out_it = utils::copy_to_iterator( out_it, R
"(",)" );
795 out_it.next_member( );
796 out_it = utils::output_kv( out_it, R"("title")", "\"" );
797 out_it = utils::copy_to_iterator( out_it, title );
798 out_it = utils::copy_to_iterator( out_it, R
"(",)" );
800 out_it = json_details::to_json_schema<json_type, true>(
802 out_it.del_indent( );
803 out_it.next_member( );
805 return out_it.get( );
817 template<
typename T,
typename Result = std::string,
auto... PolicyFlags>
819 to_json_schema( std::string_view
id, std::string_view title,
820 options::output_flags_t<PolicyFlags...> flags =
821 options::output_flags<> ) {
822 auto result = Result( );
824 (void)to_json_schema<T>( result,
id, title, flags );