55 */
66package io .jooby .internal .openapi .asciidoc ;
77
8+ import static io .swagger .v3 .oas .models .Components .COMPONENTS_SCHEMAS_REF ;
89import static java .util .Optional .ofNullable ;
910
1011import java .io .IOException ;
3334import io .pebbletemplates .pebble .extension .AbstractExtension ;
3435import io .pebbletemplates .pebble .extension .Filter ;
3536import io .pebbletemplates .pebble .extension .Function ;
37+ import io .pebbletemplates .pebble .lexer .Syntax ;
3638import io .pebbletemplates .pebble .loader .ClasspathLoader ;
3739import io .pebbletemplates .pebble .loader .DelegatingLoader ;
3840import io .pebbletemplates .pebble .loader .FileLoader ;
@@ -56,7 +58,7 @@ public class AsciiDocContext {
5658
5759 private final AutoDataFakerMapper faker = new AutoDataFakerMapper ();
5860
59- private final Map <Object , Map <String , Object >> examples = new HashMap <>();
61+ private final Map <Schema <?> , Map <String , Object >> examples = new HashMap <>();
6062
6163 private final Instant now = Instant .now ();
6264
@@ -111,6 +113,7 @@ private static PebbleEngine createEngine(
111113 return new PebbleEngine .Builder ()
112114 .autoEscaping (false )
113115 .loader (new DelegatingLoader (loaders ))
116+ .syntax (new Syntax .Builder ().setEnableNewLineTrimming (false ).build ())
114117 .extension (
115118 new AbstractExtension () {
116119 @ Override
@@ -131,9 +134,11 @@ public Map<String, Object> getGlobalVariables() {
131134 "..." ));
132135 // Routes
133136 var operations =
134- Optional .of (context .openapi .getOperations ()).orElse (List .of ()).stream ()
135- .map (op -> new HttpRequest (context , op , Map .of ()))
136- .toList ();
137+ new HttpRequestList (
138+ context ,
139+ Optional .of (context .openapi .getOperations ()).orElse (List .of ()).stream ()
140+ .map (op -> new HttpRequest (context , op , Map .of ()))
141+ .toList ());
137142 // so we can print routes without calling function: routes() vs routes
138143 openapiRoot .put ("routes" , operations );
139144 openapiRoot .put ("operations" , operations );
@@ -150,6 +155,12 @@ public Map<String, Object> getGlobalVariables() {
150155 .toList ()))
151156 .toList ();
152157 openapiRoot .put ("tags" , tags );
158+ // Schemas
159+ var components = context .openapi .getComponents ();
160+ if (components != null && components .getSchemas () != null ) {
161+ var schemas = components .getSchemas ();
162+ openapiRoot .put ("schemas" , schemas );
163+ }
153164
154165 // make in to work without literal
155166 openapiRoot .put ("query" , "query" );
@@ -286,7 +297,7 @@ public String schemaType(Schema<?> schema) {
286297 return Optional .ofNullable (resolved .getFormat ()).orElse (resolveType (resolved ));
287298 }
288299
289- private String resolveType (Schema <?> schema ) {
300+ public String resolveType (Schema <?> schema ) {
290301 var resolved = resolveSchema (schema );
291302 if (resolved .getType () == null ) {
292303 return resolved .getTypes ().iterator ().next ();
@@ -302,7 +313,12 @@ public Schema<?> resolveSchema(Schema<?> schema) {
302313 return schema ;
303314 }
304315
305- public Map <String , Object > schemaProperties (Schema <?> schema ) {
316+ public Object schemaProperties (Schema <?> schema ) {
317+ var resolved = resolveSchema (schema );
318+ var resolvedType = resolveType (resolved );
319+ if ("array" .equals (resolvedType )) {
320+ return List .of (traverse (resolved .getItems (), NOOP ));
321+ }
306322 return traverse (schema , NOOP );
307323 }
308324
@@ -338,49 +354,48 @@ public Schema<?> emptySchema(Schema<?> schema) {
338354 return empty ;
339355 }
340356
341- public Map <String , Object > schemaExample (Schema <?> schema ) {
342- return examples .computeIfAbsent (
343- schema ,
344- s ->
345- traverse (
346- new HashSet <>(),
347- schema ,
348- (parent , property ) -> {
349- var enumItems = property .getEnum ();
350- if (enumItems == null || enumItems .isEmpty ()) {
351- var type = schemaType (property );
352- var gen = faker .getGenerator (parent .getName (), property .getName (), type , type );
353- return gen .get ();
354- } else {
355- return enumItems .get (new Random ().nextInt (enumItems .size ())).toString ();
356- }
357- },
358- NOOP ,
359- NOOP ));
357+ public Object schemaExample (Schema <?> schema ) {
358+ var resolved = resolveSchema (schema );
359+ var resolvedType = resolveType (resolved );
360+ var target = resolved ;
361+ if ("array" .equals (resolvedType )) {
362+ target = resolveSchema (resolved .getItems ());
363+ }
364+ var result =
365+ examples .computeIfAbsent (
366+ target ,
367+ key ->
368+ traverse (
369+ new HashSet <>(),
370+ key ,
371+ (parent , property ) -> {
372+ var enumItems = property .getEnum ();
373+ if (enumItems == null || enumItems .isEmpty ()) {
374+ var type = schemaType (property );
375+ var gen =
376+ faker .getGenerator (parent .getName (), property .getName (), type , type );
377+ return gen .get ();
378+ } else {
379+ return enumItems .get (new Random ().nextInt (enumItems .size ())).toString ();
380+ }
381+ },
382+ NOOP ));
383+ return "array" .equals (resolvedType ) ? List .of (result ) : result ;
360384 }
361385
362386 public void traverseSchema (Schema <?> schema , BiConsumer <String , Schema <?>> consumer ) {
363387 traverse (schema , consumer );
364388 }
365389
366390 private Map <String , Object > traverse (Schema <?> schema , BiConsumer <String , Schema <?>> consumer ) {
367- return traverse (schema , consumer , NOOP );
368- }
369-
370- private Map <String , Object > traverse (
371- Schema <?> schema ,
372- BiConsumer <String , Schema <?>> consumer ,
373- BiConsumer <String , Schema <?>> inner ) {
374- return traverse (
375- new HashSet <>(), schema , (parent , property ) -> schemaType (property ), consumer , inner );
391+ return traverse (new HashSet <>(), schema , (parent , property ) -> schemaType (property ), consumer );
376392 }
377393
378394 private Map <String , Object > traverse (
379395 Set <Object > visited ,
380396 Schema <?> schema ,
381397 SneakyThrows .Function2 <Schema <?>, Schema <?>, String > valueMapper ,
382- BiConsumer <String , Schema <?>> consumer ,
383- BiConsumer <String , Schema <?>> inner ) {
398+ BiConsumer <String , Schema <?>> consumer ) {
384399 if (schema == null ) {
385400 return Map .of ();
386401 }
@@ -395,13 +410,11 @@ private Map<String, Object> traverse(
395410 var valueType = resolveType (resolvedValue );
396411 consumer .accept (name , resolvedValue );
397412 if ("object" .equals (valueType )) {
398- result .put (name , traverse (visited , resolvedValue , valueMapper , inner , inner ));
413+ result .put (name , traverse (visited , resolvedValue , valueMapper , NOOP ));
399414 } else if ("array" .equals (valueType )) {
400415 var array =
401416 ofNullable (resolvedValue .getItems ())
402- .map (
403- items ->
404- traverse (visited , resolveSchema (items ), valueMapper , inner , inner ))
417+ .map (items -> traverse (visited , resolveSchema (items ), valueMapper , NOOP ))
405418 .map (List ::of )
406419 .orElse (List .of ());
407420 result .put (name , array );
@@ -442,8 +455,8 @@ private Optional<Schema<?>> resolveSchemaInternal(String name) {
442455 if (components == null || components .getSchemas () == null ) {
443456 throw new NoSuchElementException ("No schema found" );
444457 }
445- if (name .startsWith ("#/components/schemas/" )) {
446- name = name .substring ("#/components/schemas/" .length ());
458+ if (name .startsWith (COMPONENTS_SCHEMAS_REF )) {
459+ name = name .substring (COMPONENTS_SCHEMAS_REF .length ());
447460 }
448461 return Optional .ofNullable ((Schema <?>) components .getSchemas ().get (name ));
449462 }
0 commit comments