44import static j2html .TagCreator .*;
55
66import com .qdesrame .openapi .diff .model .*;
7+ import com .qdesrame .openapi .diff .utils .RefPointer ;
8+ import com .qdesrame .openapi .diff .utils .RefType ;
9+ import io .swagger .v3 .oas .models .media .ArraySchema ;
710import io .swagger .v3 .oas .models .media .MediaType ;
11+ import io .swagger .v3 .oas .models .media .Schema ;
812import io .swagger .v3 .oas .models .parameters .Parameter ;
913import io .swagger .v3 .oas .models .responses .ApiResponse ;
1014import j2html .tags .ContainerTag ;
@@ -16,6 +20,8 @@ public class HtmlRender implements Render {
1620
1721 private String title ;
1822 private String linkCss ;
23+ protected static RefPointer <Schema > refPointer = new RefPointer <>(RefType .SCHEMAS );
24+ protected ChangedOpenApi diff ;
1925
2026 public HtmlRender () {
2127 this ("Api Change Log" , "http://deepoove.com/swagger-diff/stylesheets/demo.css" );
@@ -27,6 +33,8 @@ public HtmlRender(String title, String linkCss) {
2733 }
2834
2935 public String render (ChangedOpenApi diff ) {
36+ this .diff = diff ;
37+
3038 List <Endpoint > newEndpoints = diff .getNewEndpoints ();
3139 ContainerTag ol_newEndpoint = ol_newEndpoint (newEndpoints );
3240
@@ -218,7 +226,7 @@ private ContainerTag li_changedRequest(String name, ChangedMediaType request) {
218226 li ().with (div_changedSchema (request .getSchema ()))
219227 .withText (String .format ("Changed body: '%s'" , name ));
220228 if (request .isIncompatible ()) {
221- li = incompatibility (li , request , "" );
229+ incompatibilities (li , request . getSchema () );
222230 }
223231 return li ;
224232 }
@@ -229,55 +237,63 @@ private ContainerTag div_changedSchema(ChangedSchema schema) {
229237 return div ;
230238 }
231239
232- private ContainerTag incompatibility (
233- final ContainerTag output , final ComposedChanged changed , final String propPrefix ) {
234- if (changed .isCoreChanged () == DiffResult .INCOMPATIBLE ) {
235- if (changed instanceof ChangedSchema ) {
236- ChangedSchema cs = (ChangedSchema ) changed ;
237-
238- cs .getMissingProperties ().keySet ().stream ()
239- .forEach (
240- (propName ) -> {
241- output .with (
242- p (String .format (
243- "Missing property: %s%s%s" ,
244- propPrefix , propPrefix .isEmpty () ? "" : "." , propName ))
245- .withClass ("missing" ));
246- });
247-
248- if (cs .isChangedType ()) {
249- output .with (p ("Changed property type: " + propPrefix ).withClass ("missing" ));
250- }
251- }
240+ private void incompatibilities (final ContainerTag output , final ChangedSchema schema ) {
241+ incompatibilities (output , "" , schema );
242+ }
243+
244+ private void incompatibilities (
245+ final ContainerTag output , String propName , final ChangedSchema schema ) {
246+ if (schema .getItems () != null ) {
247+ items (output , propName , schema .getItems ());
248+ }
249+ if (schema .isCoreChanged () == DiffResult .INCOMPATIBLE && schema .isChangedType ()) {
250+ String type = type (schema .getOldSchema ()) + " -> " + type (schema .getNewSchema ());
251+ property (output , propName , "Changed property type" , type );
252252 }
253+ String prefix = propName .isEmpty () ? "" : propName + "." ;
254+ properties (
255+ output , prefix , "Missing property" , schema .getMissingProperties (), schema .getContext ());
256+ schema
257+ .getChangedProperties ()
258+ .forEach ((name , property ) -> incompatibilities (output , prefix + name , property ));
259+ }
253260
254- if (changed instanceof ChangedSchema ) {
255- ChangedSchema cs = (ChangedSchema ) changed ;
256-
257- String description = null ;
258- if (!cs .getChangedProperties ().isEmpty ()) {
259- cs .getChangedProperties ().entrySet ().stream ()
260- .forEach (
261- (entry ) -> {
262- incompatibility (
263- output ,
264- entry .getValue (),
265- propPrefix + (propPrefix .isEmpty () ? "" : "." ) + entry .getKey ());
266- });
267- } else if (cs .getItems () != null ) {
268- incompatibility (output , cs .getItems (), propPrefix + "[n]" );
269- }
261+ private void items (ContainerTag output , String propName , ChangedSchema schema ) {
262+ incompatibilities (output , propName + "[n]" , schema );
263+ }
270264
271- return output ;
265+ private void properties (
266+ ContainerTag output ,
267+ String propPrefix ,
268+ String title ,
269+ Map <String , Schema > properties ,
270+ DiffContext context ) {
271+ if (properties != null ) {
272+ properties .forEach ((key , value ) -> property (output , propPrefix + key , title , resolve (value )));
272273 }
274+ }
273275
274- for (Changed child : changed .getChangedElements ()) {
275- if (child instanceof ComposedChanged ) {
276- incompatibility (output , (ComposedChanged ) child , "" );
277- }
278- }
276+ protected void property (ContainerTag output , String name , String title , Schema schema ) {
277+ property (output , name , title , type (schema ));
278+ }
279+
280+ protected void property (ContainerTag output , String name , String title , String type ) {
281+ output .with (p (String .format ("%s: %s (%s)" , title , name , type )).withClass ("missing" ));
282+ }
283+
284+ protected Schema resolve (Schema schema ) {
285+ return refPointer .resolveRef (
286+ diff .getNewSpecOpenApi ().getComponents (), schema , schema .get$ref ());
287+ }
279288
280- return output ;
289+ protected String type (Schema schema ) {
290+ String result = "object" ;
291+ if (schema instanceof ArraySchema ) {
292+ result = "array" ;
293+ } else if (schema .getType () != null ) {
294+ result = schema .getType ();
295+ }
296+ return result ;
281297 }
282298
283299 private ContainerTag ul_param (ChangedParameters changedParameters ) {
0 commit comments