Merge remote-tracking branch 'origin/master'

Conflicts:
	src/main/java/io/github/robwin/swagger2markup/Swagger2MarkupConverter.java
	src/test/java/io/github/robwin/swagger2markup/Swagger2MarkupConverterTest.java
This commit is contained in:
N090536
2016-02-10 16:23:05 +01:00
16 changed files with 320 additions and 181 deletions

1
.gitignore vendored
View File

@@ -2,3 +2,4 @@
*.iml
.gradle
build
/bin/

View File

@@ -1,80 +1,86 @@
= Release Notes
== Version 0.1.0
* Initial version with support for AsciiDoc and Markdown
== Version 0.2.0
* This version is not downward compatible. This version supports includes of example files and JSON/XML Schema files. See documentation.
=== Version 0.2.1
* Signed jar files and published in Maven Central
=== Version 0.2.2
* Fixed wrong dependency version to io.github.robwin:markup-document-builder
=== Version 0.2.3
* Fixed issue #7: @ApiModelProperty metadata are ignored for definitions file
=== Version 0.2.4
* Fixed issue #8: logback.xml on the classpath
* Fixed issue #13: unknown format not supported for properties
== Version 0.3.0
* Support of YAML or JSON String as input.
== Version 0.4.0
* Updated Swagger-Parser from 1.0.0 to 1.0.5
* Updated commons-lang to commons-lang3
* Swagger2MarkupConverter generates three documents now: overview, paths and definitions
* Support for enums in HeaderParameter, QueryParameter, FormParameter and QueryParameter
* Support for global consumes, produces and tags
== Version 0.5.0
* Support for including hand-written descriptions instead of using Swagger Annotations for descriptions
=== Version 0.5.1
* Bugfix: Definition name must be lowercase so that descriptions file can be found
=== Version 0.5.2
* Swagger License is not mandatory anymore
* Updated markup-document-builder from v0.1.3 to v0.1.4
=== Version 0.5.3
* Fixed compiler warning: [options] bootstrap class path not set in conjunction with -source 1.7
== Version 0.6.0
* Updated swagger-parser from v1.0.5 to v1.0.6
* Support for default values in Parameters and Model properties
=== Version 0.6.1
* Updated swagger-parser from v1.0.6 to v1.0.8
=== Version 0.6.2
* curl-request.adoc from spring-restdocs is also added to the example chapters
=== Version 0.6.3
* Added possibility to write object definitions to separate files. Issue #19
== Version 0.7.0
* Added support for both reference models and composed models
=== Version 0.7.1
* Workaround: If the type of a BodyParameter is String and not a Model, the schema is null and lost. Therefore the fallback type of a BodyParameter is String now.
== Version 0.8.0
* Enhancement #26 and #27: Added a pre-process hook to modify a Swagger Model before it is converted.
* Bugfix #29: Tags are rendered twice
== Version 0.9.0
* Updated swagger-parser from v1.0.8 to v1.0.13
* Support for global responses and parameters
=== Version 0.9.1
* Added support to group the paths by tags or as-is
* Added support to order the definitions by natural ordering or as-is
=== Version 0.9.2
* Multi language support. Added russian.
=== Version 0.9.3
* Updated swagger-parser from v1.0.13 to v1.0.16
= Release Notes
== Version 0.1.0
* Initial version with support for AsciiDoc and Markdown
== Version 0.2.0
* This version is not downward compatible. This version supports includes of example files and JSON/XML Schema files. See documentation.
=== Version 0.2.1
* Signed jar files and published in Maven Central
=== Version 0.2.2
* Fixed wrong dependency version to io.github.robwin:markup-document-builder
=== Version 0.2.3
* Fixed issue #7: @ApiModelProperty metadata are ignored for definitions file
=== Version 0.2.4
* Fixed issue #8: logback.xml on the classpath
* Fixed issue #13: unknown format not supported for properties
== Version 0.3.0
* Support of YAML or JSON String as input.
== Version 0.4.0
* Updated Swagger-Parser from 1.0.0 to 1.0.5
* Updated commons-lang to commons-lang3
* Swagger2MarkupConverter generates three documents now: overview, paths and definitions
* Support for enums in HeaderParameter, QueryParameter, FormParameter and QueryParameter
* Support for global consumes, produces and tags
== Version 0.5.0
* Support for including hand-written descriptions instead of using Swagger Annotations for descriptions
=== Version 0.5.1
* Bugfix: Definition name must be lowercase so that descriptions file can be found
=== Version 0.5.2
* Swagger License is not mandatory anymore
* Updated markup-document-builder from v0.1.3 to v0.1.4
=== Version 0.5.3
* Fixed compiler warning: [options] bootstrap class path not set in conjunction with -source 1.7
== Version 0.6.0
* Updated swagger-parser from v1.0.5 to v1.0.6
* Support for default values in Parameters and Model properties
=== Version 0.6.1
* Updated swagger-parser from v1.0.6 to v1.0.8
=== Version 0.6.2
* curl-request.adoc from spring-restdocs is also added to the example chapters
=== Version 0.6.3
* Added possibility to write object definitions to separate files. Issue #19
== Version 0.7.0
* Added support for both reference models and composed models
=== Version 0.7.1
* Workaround: If the type of a BodyParameter is String and not a Model, the schema is null and lost. Therefore the fallback type of a BodyParameter is String now.
== Version 0.8.0
* Enhancement #26 and #27: Added a pre-process hook to modify a Swagger Model before it is converted.
* Bugfix #29: Tags are rendered twice
== Version 0.9.0
* Updated swagger-parser from v1.0.8 to v1.0.13
* Support for global responses and parameters
=== Version 0.9.1
* Added support to group the paths by tags or as-is
* Added support to order the definitions by natural ordering or as-is
=== Version 0.9.2
* Multi language support. Added russian.
=== Version 0.9.3
* Updated swagger-parser from v1.0.13 to v1.0.16
* Enhancement #61 Refactor separated documents logic to support inter-document cross-references
* Enhancement #53 : support for tags, paths and methods ordering
* Enhancement #51 : Support for separated operations files
* Enhancement #52: Markdown generation for inline schemas

View File

@@ -59,7 +59,7 @@ dependencies {
dependencyManagement {
dependencies {
dependency "io.github.robwin:markup-document-builder:0.1.6-SNAPSHOT"
dependency "io.swagger:swagger-compat-spec-parser:1.0.16"
dependency "io.swagger:swagger-compat-spec-parser:1.0.17"
dependency "commons-collections:commons-collections:3.2.1"
dependency "commons-io:commons-io:2.4"
dependency "junit:junit:4.11"

View File

@@ -1,6 +1,6 @@
#Sun Feb 07 12:01:31 CET 2016
#Wed Feb 10 13:33:16 CET 2016
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip

View File

@@ -46,15 +46,6 @@ public class Swagger2MarkupConverter {
private static final Logger LOG = LoggerFactory.getLogger(Swagger2MarkupConverter.class);
private final Swagger2MarkupConfig swagger2MarkupConfig;
private static final String OVERVIEW_DOCUMENT = "overview";
private static final String PATHS_DOCUMENT = "paths";
private static final String DEFINITIONS_DOCUMENT = "definitions";
private static final String SECURITY_DOCUMENT = "security";
private static final Comparator<String> DEFAULT_TAG_ORDERING = Ordering.natural();
private static final Comparator<String> DEFAULT_PATH_ORDERING = Ordering.natural();
private static final Comparator<HttpMethod> DEFAULT_PATH_METHOD_ORDERING = Ordering.explicit(HttpMethod.GET, HttpMethod.PUT, HttpMethod.POST, HttpMethod.DELETE, HttpMethod.PATCH, HttpMethod.HEAD, HttpMethod.OPTIONS);
private static final Comparator<String> DEFAULT_DEFINITION_ORDERING = Ordering.natural();
/**
* @param swagger2MarkupConfig the configuration
@@ -130,10 +121,10 @@ public class Swagger2MarkupConverter {
* @throws IOException if a file cannot be written
*/
private void buildDocuments(String directory) throws IOException {
new OverviewDocument(swagger2MarkupConfig).build().writeToFile(directory, OVERVIEW_DOCUMENT, StandardCharsets.UTF_8);
new PathsDocument(swagger2MarkupConfig, directory).build().writeToFile(directory, PATHS_DOCUMENT, StandardCharsets.UTF_8);
new DefinitionsDocument(swagger2MarkupConfig, directory).build().writeToFile(directory, DEFINITIONS_DOCUMENT, StandardCharsets.UTF_8);
new SecurityDocument(swagger2MarkupConfig).build().writeToFile(directory, SECURITY_DOCUMENT, StandardCharsets.UTF_8);
new OverviewDocument(swagger2MarkupConfig, directory).build().writeToFile(directory, swagger2MarkupConfig.getOverviewDocument(), StandardCharsets.UTF_8);
new PathsDocument(swagger2MarkupConfig, directory).build().writeToFile(directory, swagger2MarkupConfig.getPathsDocument(), StandardCharsets.UTF_8);
new DefinitionsDocument(swagger2MarkupConfig, directory).build().writeToFile(directory, swagger2MarkupConfig.getDefinitionsDocument(), StandardCharsets.UTF_8);
new SecurityDocument(swagger2MarkupConfig, directory).build().writeToFile(directory, swagger2MarkupConfig.getSecurityDocument(), StandardCharsets.UTF_8);
}
/**
@@ -143,10 +134,10 @@ public class Swagger2MarkupConverter {
*/
private String buildDocuments() {
StringBuilder sb = new StringBuilder();
sb.append(new OverviewDocument(swagger2MarkupConfig).build().toString());
sb.append(new OverviewDocument(swagger2MarkupConfig, null).build().toString());
sb.append(new PathsDocument(swagger2MarkupConfig, null).build().toString());
sb.append(new DefinitionsDocument(swagger2MarkupConfig, null).build().toString());
sb.append(new SecurityDocument(swagger2MarkupConfig).build().toString());
sb.append(new SecurityDocument(swagger2MarkupConfig, null).build().toString());
return sb.toString();
}
@@ -163,10 +154,10 @@ public class Swagger2MarkupConverter {
private MarkupLanguage markupLanguage = MarkupLanguage.ASCIIDOC;
private Language outputLanguage = Language.EN;
private int inlineSchemaDepthLevel = 0;
private Comparator<String> tagOrdering = DEFAULT_TAG_ORDERING;
private Comparator<String> pathOrdering = DEFAULT_PATH_ORDERING;
private Comparator<HttpMethod> pathMethodOrdering = DEFAULT_PATH_METHOD_ORDERING;
private Comparator<String> definitionOrdering = DEFAULT_DEFINITION_ORDERING;
private Comparator<String> tagOrdering = Ordering.natural();
private Comparator<String> pathOrdering = Ordering.natural();
private Comparator<HttpMethod> pathMethodOrdering = Ordering.explicit(HttpMethod.GET, HttpMethod.PUT, HttpMethod.POST, HttpMethod.DELETE, HttpMethod.PATCH, HttpMethod.HEAD, HttpMethod.OPTIONS);
private Comparator<String> definitionOrdering = Ordering.natural();
/**
* Creates a Builder using a given Swagger source.

View File

@@ -32,8 +32,10 @@ import io.swagger.models.refs.RefFormat;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.Validate;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
@@ -57,18 +59,15 @@ public class DefinitionsDocument extends MarkupDocument {
private static final String XML = "xml";
private static final String DESCRIPTION_FOLDER_NAME = "definitions";
private static final String DESCRIPTION_FILE_NAME = "description";
private static final String SEPARATED_DEFINITIONS_FOLDER_NAME = "definitions";
private boolean schemasEnabled;
private String schemasFolderPath;
private boolean handWrittenDescriptionsEnabled;
private String descriptionsFolderPath;
private boolean separatedDefinitionsEnabled;
private String outputDirectory;
private final int inlineSchemaDepthLevel;
private final Comparator<String> definitionOrdering;
public DefinitionsDocument(Swagger2MarkupConfig swagger2MarkupConfig, String outputDirectory){
super(swagger2MarkupConfig);
super(swagger2MarkupConfig, outputDirectory);
ResourceBundle labels = ResourceBundle.getBundle("lang/labels",
swagger2MarkupConfig.getOutputLanguage().toLocale());
@@ -103,7 +102,6 @@ public class DefinitionsDocument extends MarkupDocument {
logger.debug("Include hand-written descriptions is disabled.");
}
}
this.separatedDefinitionsEnabled = swagger2MarkupConfig.isSeparatedDefinitions();
if(this.separatedDefinitionsEnabled){
if (logger.isDebugEnabled()) {
logger.debug("Create separated definition files is enabled.");
@@ -114,7 +112,6 @@ public class DefinitionsDocument extends MarkupDocument {
logger.debug("Create separated definition files is disabled.");
}
}
this.outputDirectory = outputDirectory;
this.definitionOrdering = swagger2MarkupConfig.getDefinitionOrdering();
}
@@ -158,22 +155,28 @@ public class DefinitionsDocument extends MarkupDocument {
private void processDefinition(Map<String, Model> definitions, String definitionName, Model model) {
definition(definitions, definitionName, model, this.markupDocBuilder);
if (separatedDefinitionsEnabled) {
MarkupDocBuilder defDocBuilder = MarkupDocBuilders.documentBuilder(markupLanguage);
definition(definitions, definitionName, model, defDocBuilder);
String definitionFileName = definitionName.toLowerCase();
File definitionFile = new File(outputDirectory, resolveDefinitionDocument(definitionName));
try {
defDocBuilder.writeToFile(Paths.get(outputDirectory, SEPARATED_DEFINITIONS_FOLDER_NAME).toString(), definitionFileName, StandardCharsets.UTF_8);
String definitionDirectory = FilenameUtils.getFullPath(definitionFile.getPath());
String definitionFileName = FilenameUtils.getName(definitionFile.getPath());
defDocBuilder.writeToFileWithoutExtension(definitionDirectory, definitionFileName, StandardCharsets.UTF_8);
} catch (IOException e) {
if (logger.isWarnEnabled()) {
logger.warn(String.format("Failed to write definition file: %s", definitionFileName), e);
logger.warn(String.format("Failed to write definition file: %s", definitionFile), e);
}
}
if (logger.isInfoEnabled()) {
logger.info("Separate definition file produced: {}", definitionFileName);
logger.info("Separate definition file produced: {}", definitionFile);
}
definitionRef(definitionName, this.markupDocBuilder);
} else {
definition(definitions, definitionName, model, this.markupDocBuilder);
}
}
@@ -195,12 +198,20 @@ public class DefinitionsDocument extends MarkupDocument {
* @param docBuilder the docbuilder do use for output
*/
private void definition(Map<String, Model> definitions, String definitionName, Model model, MarkupDocBuilder docBuilder){
docBuilder.sectionTitleLevel2(definitionName);
addDefinitionTitle(definitionName, docBuilder);
descriptionSection(definitionName, model, docBuilder);
propertiesSection(definitions, definitionName, model, docBuilder);
definitionSchema(definitionName, docBuilder);
}
private void addDefinitionTitle(String title, MarkupDocBuilder docBuilder) {
docBuilder.sectionTitleLevel2(title);
}
private void definitionRef(String definitionName, MarkupDocBuilder docBuilder){
addDefinitionTitle(docBuilder.crossReferenceAsString(resolveDefinitionDocument(definitionName), definitionName, definitionName), docBuilder);
}
private class DefinitionPropertyDescriptor extends PropertyDescriptor {
public DefinitionPropertyDescriptor(Type type) {
@@ -230,7 +241,10 @@ public class DefinitionsDocument extends MarkupDocument {
Map<String, Property> properties = getAllProperties(definitions, model);
Type type = new ObjectType(definitionName, properties);
List<Type> localDefinitions = typeProperties(type, inlineSchemaDepthLevel, new PropertyDescriptor(type), docBuilder);
String definitionsRelativePath = null;
if (this.separatedDefinitionsEnabled)
definitionsRelativePath = "..";
List<Type> localDefinitions = typeProperties(type, inlineSchemaDepthLevel, new PropertyDescriptor(type), definitionsRelativePath, docBuilder);
inlineDefinitions(localDefinitions, inlineSchemaDepthLevel - 1, docBuilder);
}
@@ -367,7 +381,10 @@ public class DefinitionsDocument extends MarkupDocument {
if(CollectionUtils.isNotEmpty(definitions)){
for (Type definition: definitions) {
addInlineDefinitionTitle(definition.getName(), definition.getUniqueName(), docBuilder);
List<Type> localDefinitions = typeProperties(definition, depth, new DefinitionPropertyDescriptor(definition), docBuilder);
String definitionsRelativePath = null;
if (this.separatedDefinitionsEnabled)
definitionsRelativePath = "..";
List<Type> localDefinitions = typeProperties(definition, depth, new DefinitionPropertyDescriptor(definition), definitionsRelativePath, docBuilder);
for (Type localDefinition : localDefinitions)
inlineDefinitions(Collections.singletonList(localDefinition), depth - 1, docBuilder);
}

View File

@@ -18,6 +18,7 @@
*/
package io.github.robwin.swagger2markup.builder.document;
import com.google.common.base.Function;
import io.github.robwin.markup.builder.MarkupDocBuilder;
import io.github.robwin.markup.builder.MarkupDocBuilders;
import io.github.robwin.markup.builder.MarkupLanguage;
@@ -33,6 +34,8 @@ import org.apache.commons.collections.MapUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.*;
@@ -61,13 +64,22 @@ public abstract class MarkupDocument {
protected Swagger swagger;
protected MarkupLanguage markupLanguage;
protected MarkupDocBuilder markupDocBuilder;
protected boolean separatedDefinitionsEnabled;
protected String separatedDefinitionsFolder;
protected String definitionsDocument;
protected String outputDirectory;
protected static AtomicInteger typeIdCount = new AtomicInteger(0);
MarkupDocument(Swagger2MarkupConfig swagger2MarkupConfig) {
MarkupDocument(Swagger2MarkupConfig swagger2MarkupConfig, String outputDirectory) {
this.swagger = swagger2MarkupConfig.getSwagger();
this.markupLanguage = swagger2MarkupConfig.getMarkupLanguage();
this.markupDocBuilder = MarkupDocBuilders.documentBuilder(markupLanguage);
this.separatedDefinitionsEnabled = swagger2MarkupConfig.isSeparatedDefinitions();
this.separatedDefinitionsFolder = swagger2MarkupConfig.getSeparatedDefinitionsFolder();
this.definitionsDocument = swagger2MarkupConfig.getDefinitionsDocument();
this.outputDirectory = outputDirectory;
ResourceBundle labels = ResourceBundle.getBundle("lang/labels",
swagger2MarkupConfig.getOutputLanguage().toLocale());
@@ -84,6 +96,39 @@ public abstract class MarkupDocument {
NO_CONTENT = labels.getString("no_content");
}
protected String normalizeDefinitionFileName(String definitionName) {
return definitionName.toLowerCase();
}
protected String resolveDefinitionDocument(String definitionName, String relativePath) {
if (this.outputDirectory == null)
return null;
else if (this.separatedDefinitionsEnabled)
return new File(new File(relativePath, this.separatedDefinitionsFolder), this.markupDocBuilder.addfileExtension(normalizeDefinitionFileName(definitionName))).getPath();
else
return new File(relativePath, this.markupDocBuilder.addfileExtension(this.definitionsDocument)).getPath();
}
protected String resolveDefinitionDocument(String definitionName) {
return resolveDefinitionDocument(definitionName, null);
}
class DefinitionDocumentResolver implements Function<String, String> {
private String relativePath;
public DefinitionDocumentResolver(String relativePath) {
this.relativePath = relativePath;
}
public DefinitionDocumentResolver() {}
@Nullable
@Override
public String apply(@Nullable String definitionName) {
return resolveDefinitionDocument(definitionName, relativePath);
}
}
/**
* Builds the MarkupDocument.
*
@@ -115,7 +160,7 @@ public abstract class MarkupDocument {
return name + "-" + typeIdCount.getAndIncrement();
}
public List<Type> typeProperties(Type type, int depth, PropertyDescriptor propertyDescriptor, MarkupDocBuilder docBuilder) {
public List<Type> typeProperties(Type type, int depth, PropertyDescriptor propertyDescriptor, String definitionsRelativePath, MarkupDocBuilder docBuilder) {
List<Type> localDefinitions = new ArrayList<>();
if (type instanceof ObjectType) {
ObjectType objectType = (ObjectType) type;
@@ -130,7 +175,7 @@ public abstract class MarkupDocument {
for (Map.Entry<String, Property> propertyEntry : objectType.getProperties().entrySet()) {
Property property = propertyEntry.getValue();
String propertyName = propertyEntry.getKey();
Type propertyType = PropertyUtils.getType(property);
Type propertyType = PropertyUtils.getType(property, new DefinitionDocumentResolver(definitionsRelativePath));
if (depth > 0 && propertyType instanceof ObjectType) {
if (MapUtils.isNotEmpty(((ObjectType) propertyType).getProperties())) {
propertyType.setName(propertyName);

View File

@@ -45,8 +45,8 @@ public class OverviewDocument extends MarkupDocument {
private final String BASE_PATH;
private final String SCHEMES;
public OverviewDocument(Swagger2MarkupConfig swagger2MarkupConfig){
super(swagger2MarkupConfig);
public OverviewDocument(Swagger2MarkupConfig swagger2MarkupConfig, String outputDirectory){
super(swagger2MarkupConfig, outputDirectory);
ResourceBundle labels = ResourceBundle.getBundle("lang/labels",
swagger2MarkupConfig.getOutputLanguage().toLocale());

View File

@@ -41,10 +41,12 @@ import io.swagger.models.properties.Property;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.text.WordUtils;
import org.apache.commons.lang3.tuple.Pair;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
@@ -53,8 +55,7 @@ import java.util.*;
import java.util.regex.Pattern;
import static io.github.robwin.swagger2markup.utils.TagUtils.*;
import static org.apache.commons.lang3.StringUtils.defaultString;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import static org.apache.commons.lang3.StringUtils.*;
/**
* @author Robert Winkler
@@ -78,7 +79,6 @@ public class PathsDocument extends MarkupDocument {
private static final String CURL_EXAMPLE_FILE_NAME = "curl-request";
private static final String DESCRIPTION_FOLDER_NAME = "paths";
private static final String DESCRIPTION_FILE_NAME = "description";
private static final String SEPARATED_PATHS_FOLDER_NAME = "paths";
private final String PARAMETER;
private static final Pattern FILENAME_FORBIDDEN_PATTERN = Pattern.compile("[^0-9A-Za-z-_]+");
@@ -92,10 +92,12 @@ public class PathsDocument extends MarkupDocument {
private final Comparator<String> pathOrdering;
private final Comparator<HttpMethod> pathMethodOrdering;
private boolean separatedPathsEnabled;
private String outputDirectory;
private String separatedPathsFolder;
private String pathsDocument;
public PathsDocument(Swagger2MarkupConfig swagger2MarkupConfig, String outputDirectory){
super(swagger2MarkupConfig);
super(swagger2MarkupConfig, outputDirectory);
ResourceBundle labels = ResourceBundle.getBundle("lang/labels",
swagger2MarkupConfig.getOutputLanguage().toLocale());
@@ -112,6 +114,7 @@ public class PathsDocument extends MarkupDocument {
HTTP_CODE_COLUMN = labels.getString("http_code_column");
PARAMETER = labels.getString("parameter");
this.pathsDocument = swagger2MarkupConfig.getPathsDocument();
this.inlineSchemaDepthLevel = swagger2MarkupConfig.getInlineSchemaDepthLevel();
this.pathsGroupedBy = swagger2MarkupConfig.getPathsGroupedBy();
if(isNotBlank(swagger2MarkupConfig.getExamplesFolderPath())){
@@ -143,6 +146,7 @@ public class PathsDocument extends MarkupDocument {
}
this.separatedPathsEnabled = swagger2MarkupConfig.isSeparatedPaths();
this.separatedPathsFolder = swagger2MarkupConfig.getSeparatedPathsFolder();
if(this.separatedPathsEnabled){
if (logger.isDebugEnabled()) {
logger.debug("Create separated path files is enabled.");
@@ -153,7 +157,6 @@ public class PathsDocument extends MarkupDocument {
logger.debug("Create separated path files is disabled.");
}
}
this.outputDirectory = outputDirectory;
tagOrdering = swagger2MarkupConfig.getTagOrdering();
pathOrdering = swagger2MarkupConfig.getPathOrdering();
pathMethodOrdering = swagger2MarkupConfig.getPathMethodOrdering();
@@ -228,30 +231,61 @@ public class PathsDocument extends MarkupDocument {
}
}
private void processPath(String methodAndPath, Operation operation) {
private String normalizePathFileName(String methodAndPath, Operation operation) {
String pathFileName = operation.getOperationId();
path(methodAndPath, operation, this.markupDocBuilder);
if (pathFileName == null)
pathFileName = methodAndPath;
pathFileName = FILENAME_FORBIDDEN_PATTERN.matcher(pathFileName).replaceAll("_").toLowerCase();
return pathFileName;
}
private String resolvePathDocument(String methodAndPath, Operation operation) {
if (this.outputDirectory == null)
return null;
else if (this.separatedPathsEnabled)
return "./" + this.separatedPathsFolder + "/" + this.markupDocBuilder.addfileExtension(normalizePathFileName(methodAndPath, operation));
else
return "./" + this.markupDocBuilder.addfileExtension(this.pathsDocument);
}
private void processPath(String methodAndPath, Operation operation) {
if (separatedPathsEnabled) {
MarkupDocBuilder pathDocBuilder = MarkupDocBuilders.documentBuilder(markupLanguage);
path(methodAndPath, operation, pathDocBuilder);
String pathFileName = operation.getOperationId();
if (pathFileName == null)
pathFileName = methodAndPath;
pathFileName = FILENAME_FORBIDDEN_PATTERN.matcher(pathFileName).replaceAll("_").toLowerCase();
File pathFile = new File(outputDirectory, resolvePathDocument(methodAndPath, operation));
try {
pathDocBuilder.writeToFile(Paths.get(outputDirectory, SEPARATED_PATHS_FOLDER_NAME).toString(), pathFileName, StandardCharsets.UTF_8);
String pathDirectory = FilenameUtils.getFullPath(pathFile.getPath());
String pathFileName = FilenameUtils.getName(pathFile.getPath());
pathDocBuilder.writeToFileWithoutExtension(pathDirectory, pathFileName, StandardCharsets.UTF_8);
} catch (IOException e) {
if (logger.isWarnEnabled()) {
logger.warn(String.format("Failed to write path file: %s", pathFileName), e);
logger.warn(String.format("Failed to write path file: %s", pathFile), e);
}
}
if (logger.isInfoEnabled()) {
logger.info("Separate path file produced: {}", pathFileName);
logger.info("Separate path file produced: {}", pathFile);
}
pathRef(methodAndPath, operation, this.markupDocBuilder);
} else {
path(methodAndPath, operation, this.markupDocBuilder);
}
}
private String operationName(String methodAndPath, Operation operation) {
String operationName = operation.getSummary();
if(isBlank(operationName)) {
operationName = methodAndPath;
}
return operationName;
}
/**
* Builds an operation.
*
@@ -272,6 +306,18 @@ public class PathsDocument extends MarkupDocument {
}
}
/**
* Builds a cross-reference to separated path file
* @param methodAndPath the Method of the operation and the URL of the path
* @param operation the Swagger Operation
*/
private void pathRef(String methodAndPath, Operation operation, MarkupDocBuilder docBuilder) {
String document = resolvePathDocument(methodAndPath, operation);
String operationName = operationName(methodAndPath, operation);
addPathTitle(docBuilder.crossReferenceAsString(document, operationName, operationName), docBuilder);
}
/**
* Adds the path title to the document. If the operation has a summary, the title is the summary.
* Otherwise the title is the method of the operation and the URL of the path.
@@ -280,15 +326,13 @@ public class PathsDocument extends MarkupDocument {
* @param operation the Swagger Operation
*/
private void pathTitle(String methodAndPath, Operation operation, MarkupDocBuilder docBuilder) {
String summary = operation.getSummary();
String title;
if(isNotBlank(summary)) {
title = summary;
addPathTitle(title, docBuilder);
String operationName = operationName(methodAndPath, operation);
addPathTitle(operationName, docBuilder);
if(operationName.equals(operation.getSummary())) {
docBuilder.listing(methodAndPath);
}else{
addPathTitle(methodAndPath, docBuilder);
}
if (logger.isInfoEnabled()) {
logger.info("Path processed: {}", methodAndPath);
}
@@ -370,7 +414,7 @@ public class PathsDocument extends MarkupDocument {
new MarkupTableColumn(SCHEMA_COLUMN, 1),
new MarkupTableColumn(DEFAULT_COLUMN, 1));
for(Parameter parameter : parameters){
Type type = ParameterUtils.getType(parameter);
Type type = ParameterUtils.getType(parameter, new DefinitionDocumentResolver());
if (inlineSchemaDepthLevel > 0 && type instanceof ObjectType) {
if (MapUtils.isNotEmpty(((ObjectType) type).getProperties())) {
String localTypeName = parameter.getName();
@@ -463,7 +507,7 @@ public class PathsDocument extends MarkupDocument {
else
sortedTags = new TreeSet<>(this.tagOrdering);
sortedTags.addAll(tags);
this.markupDocBuilder.unorderedList(new ArrayList<>(sortedTags));
docBuilder.unorderedList(new ArrayList<>(sortedTags));
}
}
}
@@ -560,7 +604,8 @@ public class PathsDocument extends MarkupDocument {
if (securityDefinitions != null && securityDefinitions.containsKey(securityKey)) {
type = securityDefinitions.get(securityKey).getType();
}
List<String> content = Arrays.asList(type, docBuilder.crossReferenceAsString(securityKey, securityKey),
List<String> content = Arrays.asList(type, docBuilder.crossReferenceAsString(securityKey,
securityKey, securityKey),
Joiner.on(",").join(securityEntry.getValue()));
cells.add(content);
}
@@ -615,7 +660,7 @@ public class PathsDocument extends MarkupDocument {
Response response = entry.getValue();
if(response.getSchema() != null){
Property property = response.getSchema();
Type type = PropertyUtils.getType(property);
Type type = PropertyUtils.getType(property, new DefinitionDocumentResolver());
if (this.inlineSchemaDepthLevel > 0 && type instanceof ObjectType) {
if (MapUtils.isNotEmpty(((ObjectType) type).getProperties())) {
String localTypeName = RESPONSE + " " + entry.getKey();
@@ -650,7 +695,10 @@ public class PathsDocument extends MarkupDocument {
if(CollectionUtils.isNotEmpty(definitions)){
for (Type definition: definitions) {
addInlineDefinitionTitle(definition.getName(), definition.getUniqueName(), docBuilder);
List<Type> localDefinitions = typeProperties(definition, depth, new PropertyDescriptor(definition), this.markupDocBuilder);
String definitionsRelativePath = null;
if (this.separatedPathsEnabled)
definitionsRelativePath = "..";
List<Type> localDefinitions = typeProperties(definition, depth, new PropertyDescriptor(definition), definitionsRelativePath, docBuilder);
for (Type localDefinition : localDefinitions)
inlineDefinitions(Collections.singletonList(localDefinition), depth - 1, docBuilder);
}

View File

@@ -49,8 +49,8 @@ public class SecurityDocument extends MarkupDocument {
private final String AUTHORIZATION_URL;
private final String TOKEN_URL;
public SecurityDocument(Swagger2MarkupConfig swagger2MarkupConfig) {
super(swagger2MarkupConfig);
public SecurityDocument(Swagger2MarkupConfig swagger2MarkupConfig, String outputDirectory) {
super(swagger2MarkupConfig, outputDirectory);
ResourceBundle labels = ResourceBundle.getBundle("lang/labels",
swagger2MarkupConfig.getOutputLanguage().toLocale());

View File

@@ -46,6 +46,14 @@ public class Swagger2MarkupConfig {
private final Comparator<HttpMethod> pathMethodOrdering;
private final Comparator<String> definitionOrdering;
private static final String OVERVIEW_DOCUMENT = "overview";
private static final String PATHS_DOCUMENT = "paths";
private static final String DEFINITIONS_DOCUMENT = "definitions";
private static final String SECURITY_DOCUMENT = "security";
private static final String SEPARATED_DEFINITIONS_FOLDER = "definitions";
private static final String SEPARATED_PATHS_FOLDER = "paths";
/**
* @param swagger the Swagger source
* @param markupLanguage the markup language which is used to generate the files
@@ -144,4 +152,28 @@ public class Swagger2MarkupConfig {
public Comparator<String> getDefinitionOrdering() {
return definitionOrdering;
}
public String getOverviewDocument() {
return OVERVIEW_DOCUMENT;
}
public String getPathsDocument() {
return PATHS_DOCUMENT;
}
public String getDefinitionsDocument() {
return DEFINITIONS_DOCUMENT;
}
public String getSecurityDocument() {
return SECURITY_DOCUMENT;
}
public String getSeparatedDefinitionsFolder() {
return SEPARATED_DEFINITIONS_FOLDER;
}
public String getSeparatedPathsFolder() {
return SEPARATED_PATHS_FOLDER;
}
}

View File

@@ -4,8 +4,11 @@ import io.github.robwin.markup.builder.MarkupDocBuilder;
public class RefType extends Type {
public RefType(String name) {
private String document;
public RefType(String document, String name) {
super(name);
this.document = document;
}
public RefType(Type type) {
@@ -14,6 +17,14 @@ public class RefType extends Type {
@Override
public String displaySchema(MarkupDocBuilder docBuilder) {
return docBuilder.crossReferenceAsString(getUniqueName(), getName());
return docBuilder.crossReferenceAsString(getDocument(), getUniqueName(), getName());
}
public String getDocument() {
return document;
}
public void setDocument(String document) {
this.document = document;
}
}

View File

@@ -18,10 +18,8 @@
*/
package io.github.robwin.swagger2markup.utils;
import io.github.robwin.swagger2markup.type.ArrayType;
import io.github.robwin.swagger2markup.type.ObjectType;
import io.github.robwin.swagger2markup.type.RefType;
import io.github.robwin.swagger2markup.type.Type;
import com.google.common.base.Function;
import io.github.robwin.swagger2markup.type.*;
import io.swagger.models.ArrayModel;
import io.swagger.models.Model;
import io.swagger.models.ModelImpl;
@@ -36,15 +34,16 @@ public final class ModelUtils {
* @param model the model
* @return the type of the model, or otherwise null
*/
public static Type getType(Model model) {
public static Type getType(Model model, Function<String, String> definitionDocumentResolver) {
Validate.notNull(model, "model must not be null!");
if (model instanceof ModelImpl) {
return new ObjectType(null, model.getProperties());
} else if (model instanceof RefModel) {
return new RefType(((RefModel) model).getSimpleRef());
String simpleRef = ((RefModel) model).getSimpleRef();
return new RefType(definitionDocumentResolver.apply(simpleRef), simpleRef);
} else if (model instanceof ArrayModel) {
ArrayModel arrayModel = ((ArrayModel) model);
return new ArrayType(null, PropertyUtils.getType(arrayModel.getItems()));
return new ArrayType(null, PropertyUtils.getType(arrayModel.getItems(), definitionDocumentResolver));
}
return null;
}

View File

@@ -18,6 +18,7 @@
*/
package io.github.robwin.swagger2markup.utils;
import com.google.common.base.Function;
import io.github.robwin.swagger2markup.type.*;
import io.swagger.models.Model;
import io.swagger.models.parameters.AbstractSerializableParameter;
@@ -40,14 +41,14 @@ public final class ParameterUtils {
* @param parameter the parameter
* @return the type of the parameter, or otherwise null
*/
public static Type getType(Parameter parameter){
public static Type getType(Parameter parameter, Function<String, String> definitionDocumentResolver){
Validate.notNull(parameter, "parameter must not be null!");
Type type = null;
if(parameter instanceof BodyParameter){
BodyParameter bodyParameter = (BodyParameter)parameter;
Model model = bodyParameter.getSchema();
if(model != null){
type = ModelUtils.getType(model);
type = ModelUtils.getType(model, definitionDocumentResolver);
}else{
type = new BasicType("string");
}
@@ -63,12 +64,12 @@ public final class ParameterUtils {
}
if(type.getName().equals("array")){
String collectionFormat = serializableParameter.getCollectionFormat();
type = new ArrayType(null, PropertyUtils.getType(serializableParameter.getItems()), collectionFormat);
type = new ArrayType(null, PropertyUtils.getType(serializableParameter.getItems(), definitionDocumentResolver), collectionFormat);
}
}
else if(parameter instanceof RefParameter){
RefParameter refParameter = (RefParameter)parameter;
type = new RefType(refParameter.getSimpleRef());
String simpleRef = ((RefParameter)parameter).getSimpleRef();
type = new RefType(definitionDocumentResolver.apply(simpleRef), simpleRef);
}
return type;
}

View File

@@ -18,6 +18,7 @@
*/
package io.github.robwin.swagger2markup.utils;
import com.google.common.base.Function;
import io.github.robwin.swagger2markup.type.*;
import io.swagger.models.properties.*;
import io.swagger.models.refs.RefFormat;
@@ -37,7 +38,7 @@ public final class PropertyUtils {
* @param property the property
* @return the type of the property
*/
public static Type getType(Property property){
public static Type getType(Property property, Function<String, String> definitionDocumentResolver){
Validate.notNull(property, "property must not be null!");
Type type;
if(property instanceof RefProperty){
@@ -45,11 +46,11 @@ public final class PropertyUtils {
if (refProperty.getRefFormat() == RefFormat.RELATIVE)
type = new ObjectType(null, null); // FIXME : Workaround for https://github.com/swagger-api/swagger-parser/issues/177
else
type = new RefType(refProperty.getSimpleRef());
type = new RefType(definitionDocumentResolver.apply(refProperty.getSimpleRef()), refProperty.getSimpleRef());
}else if(property instanceof ArrayProperty){
ArrayProperty arrayProperty = (ArrayProperty)property;
Property items = arrayProperty.getItems();
type = new ArrayType(null, getType(items));
type = new ArrayType(null, getType(items, definitionDocumentResolver));
}else if(property instanceof StringProperty){
StringProperty stringProperty = (StringProperty)property;
List<String> enums = stringProperty.getEnum();

View File

@@ -259,9 +259,6 @@ public class Swagger2MarkupConverterTest {
String[] directories = outputDirectory.list();
assertThat(directories).hasSize(5).containsAll(
asList("definitions", "definitions.adoc", "overview.adoc", "paths.adoc", "security.adoc"));
File definitionsDirectory = new File(outputDirectory, "definitions");
assertThat(new String(Files.readAllBytes(new File(outputDirectory, "definitions.adoc").toPath())))
.contains(new String(Files.readAllBytes(new File(definitionsDirectory, "user.adoc").toPath())));
}
@Test
@@ -285,9 +282,6 @@ public class Swagger2MarkupConverterTest {
String[] definitions = definitionsDirectory.list();
assertThat(definitions).hasSize(6).containsAll(
asList("identified.md", "user.md", "category.md", "pet.md", "tag.md", "order.md"));
assertThat(new String(Files.readAllBytes(new File(outputDirectory, "definitions.md").toPath())))
.contains(new String(Files.readAllBytes(new File(definitionsDirectory, "user.md").toPath())));
}
@Test
@@ -306,13 +300,6 @@ public class Swagger2MarkupConverterTest {
String[] directories = outputDirectory.list();
assertThat(directories).hasSize(5).containsAll(
asList("definitions", "definitions.md", "overview.md", "paths.md", "security.md"));
verifyMarkdownContainsFieldsInTables(
new File(outputDirectory, "definitions.md"),
ImmutableMap.<String, Set<String>>builder()
.put("Identified", ImmutableSet.of("id"))
.put("User", ImmutableSet.of("id", "username", "firstName",
"lastName", "email", "password", "phone", "userStatus"))
.build());
File definitionsDirectory = new File(outputDirectory, "definitions");
verifyMarkdownContainsFieldsInTables(
new File(definitionsDirectory, "user.md"),