Commit 19054687 authored by duanledexianxianxian's avatar duanledexianxianxian 😁

🎉 Initial commit.

parent 102dcc6a
Pipeline #184 failed with stages
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
hs_err_pid*
.idea
*.iml
target
.gradle
out
build
gradlew*
\ No newline at end of file
MIT License
Copyright (c) 2018 Apiggs
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
# apidoc # 🐷 Apigcc - 非侵入的RestDoc文档生成工具
基于javadoc注释自动生成api接口文档 ![](https://img.shields.io/badge/Language-Java-yellow.svg)
\ No newline at end of file
### 前言
程序员一直以来都有一个烦恼,只想写代码,不想写文档。代码就表达了我的思想和灵魂。
Python提出了一个方案,叫**docstring**,来试图解决这个问题。即编写代码,同时也能写出文档,保持代码和文档的一致。docstring说白了就是一堆代码中的注释。Python的docstring可以通过help函数直接输出一份有格式的文档,本工具的思想与此类似。
### 代码即文档
Apigcc是一个**非侵入**的RestDoc文档生成工具。工具通过分析代码和注释,获取文档信息,生成RestDoc文档。
### 有这样一段代码
```java
/**
* 欢迎使用Apigcc
* @index 1
*/
@RestController
public class HelloController {
/**
* 示例接口
* @param name 名称
* @return
*/
@RequestMapping("/greeting")
public HelloDTO greeting(@RequestParam(defaultValue="apigcc") String name) {
return new HelloDTO("hello "+name);
}
}
```
### 生成文档效果
![示例](https://apigcc-1252473972.cos.ap-shanghai.myqcloud.com/apigcc-hub-demo.png)
### 使用方式
[Hub](https://github.com/apigcc/apigcc-hub)
[Gradle插件](https://github.com/apigcc/apigcc-gradle-plugin)
[Maven插件](https://github.com/apigcc/apigcc-maven-plugin)
\ No newline at end of file
theme: jekyll-theme-cayman
\ No newline at end of file
dependencies {
compile 'com.github.javaparser:javaparser-symbol-solver-core:3.14.4'
compile 'com.fasterxml.jackson.core:jackson-databind:2.5.2'
compile 'org.asciidoctor:asciidoctorj:2.1.0'
}
package com.apidoc.core;
import com.apidoc.core.common.helper.StringHelper;
import com.apidoc.core.parser.ParserStrategy;
import com.apidoc.core.parser.VisitorParser;
import com.apidoc.core.render.ProjectRender;
import com.apidoc.core.resolver.TypeResolvers;
import com.apidoc.core.schema.Project;
import com.github.javaparser.ParseResult;
import com.github.javaparser.ParserConfiguration;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.symbolsolver.JavaSymbolSolver;
import com.github.javaparser.symbolsolver.resolution.typesolvers.CombinedTypeSolver;
import com.github.javaparser.symbolsolver.resolution.typesolvers.JarTypeSolver;
import com.github.javaparser.symbolsolver.resolution.typesolvers.JavaParserTypeSolver;
import com.github.javaparser.symbolsolver.resolution.typesolvers.ReflectionTypeSolver;
import com.github.javaparser.utils.SourceRoot;
import com.google.common.collect.Lists;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.nio.file.Path;
import java.util.List;
import java.util.Objects;
import java.util.ServiceLoader;
/**
* The type ApiDoc.
*
* @author fengyuchenglun
* @version 1.0.0
*/
@Slf4j
public class ApiDoc {
/**
* ApiDoc实例
*/
private static ApiDoc INSTANCE;
/**
* Get instance api doc.
*
* @return the api doc
*/
public static ApiDoc getInstance(){
return INSTANCE;
}
/**
* 上下文
*/
@Getter
private Context context;
/**
* 项目信息
*/
@Getter
private Project project = new Project();
/**
* The Visitor parser.
*/
private VisitorParser visitorParser = new VisitorParser();
/**
* The Parser configuration.
*/
private ParserConfiguration parserConfiguration;
/**
* The Type resolvers.
*/
@Getter
private TypeResolvers typeResolvers = new TypeResolvers();
/**
* Instantiates a new ApiDoc.
*/
private ApiDoc(){
init(new Context());
}
/**
* Instantiates a new ApiDoc.
*
* @param context the context
*/
public ApiDoc(Context context){
init(context);
}
/**
* 初始化环境配置
*
* @param context the context
*/
private void init(Context context){
INSTANCE = this;
this.context = context;
project.setId(context.getId());
project.setName(context.getName());
project.setDescription(context.getDescription());
project.setVersion(context.getVersion());
CombinedTypeSolver typeSolver = new CombinedTypeSolver();
for (Path dependency : context.getDependencies()) {
typeSolver.add(new JavaParserTypeSolver(dependency));
}
for (Path jar : context.getJars()) {
try {
typeSolver.add(new JarTypeSolver(jar));
} catch (IOException e) {
log.warn("exception on {} {}", jar, e.getMessage());
}
}
typeSolver.add(new ReflectionTypeSolver());
parserConfiguration = new ParserConfiguration();
parserConfiguration.setSymbolResolver(new JavaSymbolSolver(typeSolver));
ParserStrategy strategy = loadParserStrategy();
strategy.onLoad();
visitorParser.setParserStrategy(strategy);
}
/**
* 加载并设置解析框架
* null时,使用读取到的第一个框架解析器
* 找不到时,报错
*
* @return the parser strategy
*/
private ParserStrategy loadParserStrategy(){
ServiceLoader<ParserStrategy> serviceLoader = ServiceLoader.load(ParserStrategy.class);
List<ParserStrategy> strategies = Lists.newArrayList(serviceLoader);
if(strategies.isEmpty()){
throw new IllegalArgumentException("no ParserStrategy implements found");
}
if(StringHelper.isBlank(context.framework)){
return strategies.get(0);
}
for (ParserStrategy strategy : strategies) {
if(Objects.equals(context.framework,strategy.name())){
return strategy;
}
}
throw new IllegalArgumentException("no ParserStrategy implements found for "+context.framework);
}
/**
* 解析源代码
*
* @return project project
*/
public Project parse(){
for (Path source : this.context.getSources()) {
SourceRoot root = new SourceRoot(source, parserConfiguration);
try {
for (ParseResult<CompilationUnit> result : root.tryToParse()) {
if(result.isSuccessful() && result.getResult().isPresent()){
result.getResult().get().accept(visitorParser, project);
}
}
} catch (IOException e) {
log.warn("parse root {} error {}", source, e.getMessage());
}
}
return project;
}
/**
* 渲染解析结果
*/
public void render(){
for (ProjectRender render : this.context.getRenders()) {
render.render(project);
}
}
}
package com.apidoc.core;
import com.apidoc.core.common.helper.FileHelper;
import com.apidoc.core.render.AsciiDocRender;
import com.apidoc.core.render.PostmanRender;
import com.apidoc.core.render.ProjectRender;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.Getter;
import lombok.Setter;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
/**
* The type Context.
*
* @author fengyuchenglun
* @version 1.0.0
*/
@Getter
public class Context {
/**
* 默认-节点索引
*/
public static final Integer DEFAULT_NODE_INDEX = 99;
/**
* 默认-项目编号
*/
public static final String DEFAULT_PROJECT_ID = "api";
/**
* 默认-编译路径
*/
public static final String DEFAULT_BUILD_PATH = "build";
/**
* 默认-代码结构
*/
public static final String DEFAULT_CODE_STRUCTURE = "src/main/java";
/**
* 设置当前解析框架
*/
@Setter
public String framework;
/**
* The Renders.
*/
@Setter
public List<ProjectRender> renders = Lists.newArrayList(
new AsciiDocRender(),
new PostmanRender());
/**
* 编译目录
*/
@Setter
private Path buildPath = Paths.get(DEFAULT_BUILD_PATH);
/**
* 源码目录
*/
private List<Path> sources = Lists.newArrayList();
/**
* 依赖源码
*/
private List<Path> dependencies = Lists.newArrayList();
/**
* 依赖jar包
*/
private List<Path> jars = Lists.newArrayList();
/**
* 项目编号
*/
@Setter
private String id = DEFAULT_PROJECT_ID;
/**
* 名称
*/
@Setter
private String name;
/**
* 描述
*/
@Setter
private String description;
/**
* 版本
*/
@Setter
private String version;
/**
* 渲染html时的css
*/
@Setter
private String css;
/**
* 自定义扩展参数
*/
private Map<String,Object> ext= Maps.newHashMap();
/**
* Add source.
*
* @param path the path
*/
public void addSource(Path path){
sources.add(path);
sources.addAll(FileHelper.find(path, DEFAULT_CODE_STRUCTURE));
addDependency(path);
}
/**
* Add dependency.
*
* @param path the path
*/
public void addDependency(Path path){
dependencies.add(path);
dependencies.addAll(FileHelper.find(path, DEFAULT_CODE_STRUCTURE));
}
/**
* Add jar.
*
* @param path the path
*/
public void addJar(Path path){
jars.add(path);
}
}
package com.apidoc.core.common;
import com.google.common.base.Strings;
public class Assert {
public static boolean isBlank(String text) {
return Strings.isNullOrEmpty(text) || Strings.isNullOrEmpty(text.trim());
}
public static void notBlank(String text, String message) {
if (Strings.isNullOrEmpty(text) || Strings.isNullOrEmpty(text.trim())) {
throw new IllegalArgumentException(message);
}
}
public static void between(int num, int min, int max, String message) {
if (num < min || num > max) {
throw new IllegalArgumentException(message);
}
}
}
package com.apidoc.core.common;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.util.Iterator;
public class ObjectMappers {
public static final ObjectMapper instance;
static {
instance = new ObjectMapper();
instance.setSerializationInclusion(JsonInclude.Include.NON_NULL);
}
public static String pretty(Object node) {
try {
return instance.writerWithDefaultPrettyPrinter().writeValueAsString(node);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
public static ObjectNode merge(ObjectNode result, ObjectNode... nodes) {
if (result != null) {
for (ObjectNode node : nodes) {
Iterator<String> iterator = node.fieldNames();
while (iterator.hasNext()){
String key = iterator.next();
result.set(key,node.get(key));
}
}
}
return result;
}
}
package com.apidoc.core.common;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.util.Iterator;
public class QueryStringBuilder {
private StringBuilder builder = new StringBuilder();
public QueryStringBuilder append(Object key, Object value){
if(builder.length()>0){
builder.append("&");
}
builder.append(key);
builder.append("=");
builder.append(value);
return this;
}
public QueryStringBuilder append(ObjectNode objectNode){
Iterator<String> iterator = objectNode.fieldNames();
while (iterator.hasNext()){
String key = iterator.next();
JsonNode valueNode = objectNode.get(key);
String value = valueNode.isTextual()?valueNode.asText():valueNode.toString();
append(key,value);
}
return this;
}
public String toString(){
return builder.toString();
}
}
package com.apidoc.core.common;
import com.apidoc.core.common.helper.StringHelper;
import com.google.common.collect.Lists;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@Getter
@EqualsAndHashCode
public class URI {
private String text;
private URI next;
public URI() {
}
public URI(String text) {
this.text = text;
}
public URI add(String text){
return add(new URI(text));
}
public URI add(URI uri){
if(next!=null){
next.add(uri);
}else{
next = uri;
}
return this;
}
public void remove(URI uri){
if(Objects.equals(next,uri)){
next = null;
}else{
next.remove(uri);
}
}
@Override
public String toString(){
List<String> list = new ArrayList<>();
appendTo(list);
StringBuilder builder = new StringBuilder();
for (String text : list) {
if(StringHelper.nonBlank(text)){
builder.append("/");
builder.append(text);
}
}
return builder.toString();
}
private void appendTo(List<String> list){
if(Objects.nonNull(text)){
list.addAll(Lists.newArrayList(text.split("/")));
}
if(next!=null){
next.appendTo(list);
}
}
}
package com.apidoc.core.common.description;
import com.apidoc.core.common.ObjectMappers;
import com.apidoc.core.schema.Row;
import com.fasterxml.jackson.databind.node.ArrayNode;
import java.util.ArrayList;
import java.util.Collection;
public class ArrayTypeDescription extends TypeDescription {
protected ArrayNode value;
protected TypeDescription component;
public ArrayTypeDescription(TypeDescription component) {
this.component = component;
this.value = ObjectMappers.instance.createArrayNode();
if(component.isAvailable()){
this.type = component.getType() + "[]";
if(component.isPrimitive()){
primitive(component.asPrimitive());
}else if(component.isString()){
value.add(component.asString().getValue());
}else if(component.isArray()){
value.add(component.asArray().getValue());
}else if(component.isObject()){
value.add(component.asObject().getValue());
}
}else{
this.type = "[]";
}
}
public void primitive(PrimitiveTypeDescription typeDescription){
switch (typeDescription.getType()){
case "byte":
value.add((byte)typeDescription.getValue());
break;
case "short":
value.add((short)typeDescription.getValue());
break;
case "char":
value.add((char)typeDescription.getValue());
break;
case "int":
value.add((int)typeDescription.getValue());
break;
case "long":
value.add((long)typeDescription.getValue());
break;
case "boolean":
value.add((boolean)typeDescription.getValue());
break;
case "float":
value.add((float)typeDescription.getValue());
break;
case "double":
value.add((double)typeDescription.getValue());
break;
}
}
@Override
public void setKey(String key) {
super.setKey(key);
if (component.isAvailable()) {
component.setPrefix(fullKey());
}
}
@Override
public void setPrefix(String prefix) {
super.setPrefix(prefix);
if (component.isAvailable()) {
component.setPrefix(fullKey());
}
}
public ArrayNode getValue(){
return value;
}
@Override
public Collection<Row> rows() {
ArrayList<Row> rows = new ArrayList<>();
if(key != null){
rows.addAll(super.rows());
}
if(component.isAvailable()){
rows.addAll(component.rows());
}
return rows;
}
}
package com.apidoc.core.common.description;
import com.apidoc.core.common.ObjectMappers;
import com.apidoc.core.schema.Row;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.Lists;
import lombok.Getter;
import lombok.Setter;
import java.util.Collection;
import java.util.List;
@Setter
@Getter
public class ObjectTypeDescription extends TypeDescription {
private ObjectNode value = ObjectMappers.instance.createObjectNode();
protected List<TypeDescription> members = Lists.newArrayList();
public void merge(ObjectTypeDescription other) {
value.setAll(other.getValue());
members.addAll(other.members);
}
public void add(TypeDescription component) {
members.add(component);
if (component.isPrimitive()) {
primitive(component.asPrimitive());
} else if (component.isString()) {
value.put(component.getKey(), component.asString().getValue());
} else if (component.isArray()) {
value.set(component.getKey(), component.asArray().getValue());
} else if (component.isObject()) {
value.set(component.getKey(), component.asObject().getValue());
}
}
public void primitive(PrimitiveTypeDescription typeDescription) {
switch (typeDescription.getType()) {
case "byte":
value.put(typeDescription.getKey(), (byte) typeDescription.getValue());
break;
case "short":
value.put(typeDescription.getKey(), (short) typeDescription.getValue());
break;
case "char":
value.put(typeDescription.getKey(), (char) typeDescription.getValue());
break;
case "int":
value.put(typeDescription.getKey(), (int) typeDescription.getValue());
break;
case "long":
value.put(typeDescription.getKey(), (long) typeDescription.getValue());
break;
case "boolean":
value.put(typeDescription.getKey(), (boolean) typeDescription.getValue());
break;
case "float":
value.put(typeDescription.getKey(), (float) typeDescription.getValue());
break;
case "double":
value.put(typeDescription.getKey(), (double) typeDescription.getValue());
break;
}
}
@Override
public void setKey(String key) {
super.setKey(key);
String memberPrefix = fullKey();
for (TypeDescription member : members) {
if (member.isAvailable()) {
member.setPrefix(memberPrefix);
}
}
}
@Override
public void setPrefix(String prefix) {
super.setPrefix(prefix);
String memberPrefix = fullKey();
for (TypeDescription member : members) {
if (member.isAvailable()) {
member.setPrefix(memberPrefix);
}
}
}
public ObjectNode getValue() {
return value;
}
@Override
public Collection<Row> rows() {
Collection<Row> rows = super.rows();
for (TypeDescription member : members) {
if (member.isAvailable()) {
rows.addAll(member.rows());
}
}
return rows;
}
}
package com.apidoc.core.common.description;
import com.github.javaparser.resolution.types.ResolvedPrimitiveType;
import com.github.javaparser.resolution.types.ResolvedReferenceType;
public class PrimitiveTypeDescription extends TypeDescription {
public PrimitiveTypeDescription(ResolvedReferenceType referenceType){
switch (referenceType.getId()){
case "java.lang.Byte":
value = (byte) 0;
type = "byte";
break;
case "java.lang.Short":
value = (short) 0;
type = "short";
break;
case "java.lang.Integer":
value = 0;
type = "int";
break;
case "java.lang.Long":
value = 0L;
type = "long";
break;
case "java.lang.Float":
value = 0f;
type = "float";
break;
case "java.lang.Double":
value = 0d;
type = "double";
break;
case "java.lang.Character":
value = (char)0;
type = "char";
break;
case "java.lang.Boolean":
value = false;
type = "boolean";
break;
}
}
public PrimitiveTypeDescription(ResolvedPrimitiveType resolvedPrimitiveType){
type = resolvedPrimitiveType.describe();
switch (resolvedPrimitiveType){
case BYTE:
value = (byte) 0;
break;
case SHORT:
value = (short) 0;
break;
case INT:
value = 0;
break;
case LONG:
value = 0L;
break;
case FLOAT:
value = 0f;
break;
case DOUBLE:
value = 0d;
break;
case CHAR:
value = (char)0;
break;
case BOOLEAN:
value = false;
break;
}
}
}
package com.apidoc.core.common.description;
public class StringTypeDescription extends TypeDescription {
public StringTypeDescription(String type, CharSequence charSequence) {
this.type = type;
value = charSequence.toString();
}
public String getValue(){
return (String)value;
}
}
package com.apidoc.core.common.description;
import com.apidoc.core.common.helper.StringHelper;
import com.apidoc.core.schema.Row;
import com.google.common.collect.Lists;
import lombok.Getter;
import lombok.Setter;
import java.util.Collection;
@Setter
@Getter
public abstract class TypeDescription {
protected String prefix = "";
protected String key = "";
protected String type;
protected StringBuilder condition = new StringBuilder();
protected String remark;
protected Object value;
protected Object defaultValue;
protected Boolean required;
public boolean isAvailable() {
return !isUnAvailable();
}
public boolean isUnAvailable() {
return this instanceof UnAvailableTypeDescription;
}
public boolean isPrimitive() {
return this instanceof PrimitiveTypeDescription;
}
public PrimitiveTypeDescription asPrimitive() {
return (PrimitiveTypeDescription) this;
}
public boolean isString() {
return this instanceof StringTypeDescription;
}
public StringTypeDescription asString() {
return (StringTypeDescription) this;
}
public boolean isArray() {
return this instanceof ArrayTypeDescription;
}
public ArrayTypeDescription asArray() {
return (ArrayTypeDescription) this;
}
public boolean isObject() {
return this instanceof ObjectTypeDescription;
}
public ObjectTypeDescription asObject() {
return (ObjectTypeDescription) this;
}
public void addRemark(String value){
if(value==null){
return;
}
if(remark==null){
remark = value;
}else{
remark += " " + value;
}
}
public String fullKey(){
return StringHelper.join(".",prefix,key);
}
public Collection<Row> rows() {
String key = fullKey();
if(StringHelper.isBlank(key)){
return Lists.newArrayList();
}
String def;
if(defaultValue!=null){
def = String.valueOf(defaultValue);
}else if(value!=null){
def = String.valueOf(value);
}else{
def = "";
}
if(required!=null){
condition.append("required=").append(required);
}
return Lists.newArrayList(new Row(key, type, condition.toString(), def, remark));
}
}
package com.apidoc.core.common.description;
import com.apidoc.core.schema.Row;
import java.util.Collection;
/**
* 未知类型,应该忽略
*/
public class UnAvailableTypeDescription extends TypeDescription {
public UnAvailableTypeDescription() {
}
@Override
public Object getValue() {
throw new IllegalArgumentException("unAvailable type not support");
}
@Override
public Collection<Row> rows() {
throw new IllegalArgumentException("unAvailable type not support");
}
}
package com.apidoc.core.common.diff;
import com.google.common.base.Charsets;
import lombok.Getter;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.OpenOption;
import java.nio.file.Path;
import java.util.List;
/**
* 文件对比工具
*/
@Getter
public class FileMatcher {
MatchPatcher matchPatcher = new MatchPatcher();
/**
* 变化的点
*/
private int changs;
private List<MatchPatcher.Diff> diffs;
public int compare(Path template, Path build) {
return compare(readFile(template), readFile(build));
}
public int compare(String templateText, String buildText) {
diffs = matchPatcher.diff_main(templateText, buildText, true);
for (MatchPatcher.Diff diff : diffs) {
if (!diff.operation.equals(MatchPatcher.Operation.EQUAL)) {
changs++;
}
}
return changs;
}
public void rederHtml(Path templateHtml, Path resultHtml) {
String results = matchPatcher.diff_prettyHtml(diffs);
String[] lines = br(results).replaceAll("<span>|</span>", "").split("\n");
String html = readFile(templateHtml);
html = html.replace("${content}", lines(lines));
writeFile(resultHtml, html, Charsets.UTF_8);
FileSystem.open(resultHtml);
}
private String lines(String[] lines) {
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < lines.length; i++) {
stringBuilder.append("<tr><td class=\"line-numbers\">").append(i)
.append("</td><td>")
.append(lines[i]).append("</td></tr>");
}
return stringBuilder.toString();
}
private static String br(String text) {
return text.replaceAll("&para;", "");
}
/**
* 读取文件内容
*
* @param path
* @return
* @throws IOException
*/
public static String readFile(Path path) {
// Read a file from disk and return the text contents.
StringBuilder sb = new StringBuilder();
try (FileReader input = new FileReader(path.toFile());
BufferedReader bufRead = new BufferedReader(input)) {
String line = bufRead.readLine();
while (line != null) {
sb.append(line).append('\n');
line = bufRead.readLine();
}
} catch (Exception e) {
throw new IllegalArgumentException(e.getMessage(), e);
}
return sb.toString();
}
public void writeFile(Path file, String content, Charset charset, OpenOption... openOptions) {
if (file.getParent() != null) {
try {
Files.createDirectories(file.getParent());
} catch (IOException e) {
throw new RuntimeException("Failed create directory", e);
}
}
try (BufferedWriter writer = Files.newBufferedWriter(file, charset, openOptions)) {
writer.write(content);
writer.flush();
} catch (IOException e) {
throw new RuntimeException("Failed to write file", e);
}
}
}
package com.apidoc.core.common.diff;
import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
public class FileSystem {
public static boolean open(Path path) {
if(!Files.exists(path)){
return false;
}
if (cmd(path.toString())) {
return true;
}
return jdk(path.toFile());
}
private static boolean cmd(String file) {
return cmd(currentOS().getCommand(), file);
}
private static boolean cmd(String command, String args) {
try {
Process p = Runtime.getRuntime().exec(new String[]{command,args});
return p!=null;
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
private static boolean jdk(File file) {
try {
if (Desktop.isDesktopSupported()) {
Desktop.getDesktop().open(file);
return true;
}
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
public enum OS {
mac("open"),
win("explorer");
private String command;
OS(String command) {
this.command = command;
}
public String getCommand(){
return command;
}
}
private static OS currentOS() {
String s = System.getProperty("os.name").toLowerCase();
if (s.contains("win")) {
return OS.win;
}
return OS.mac;
}
}
package com.apidoc.core.common.helper;
import com.github.javaparser.ast.expr.*;
import com.github.javaparser.ast.nodeTypes.NodeWithAnnotations;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
public class AnnotationHelper {
public static boolean isAnnotationPresent(NodeWithAnnotations node, List<String> annotationNames) {
for (String annotationName : annotationNames) {
if (node.isAnnotationPresent(annotationName)) {
return true;
}
}
return false;
}
public static Optional<Expression> getAttribute(AnnotationExpr annotationExpr, String key) {
if (Objects.equals("value", key) && annotationExpr.isSingleMemberAnnotationExpr()) {
return Optional.of(annotationExpr.asSingleMemberAnnotationExpr().getMemberValue());
}
if (annotationExpr.isNormalAnnotationExpr()) {
for (MemberValuePair pair : annotationExpr.asNormalAnnotationExpr().getPairs()) {
if (Objects.equals(key, pair.getNameAsString())){
return Optional.of(pair.getValue());
}
}
}
return Optional.empty();
}
public static Optional<Expression> getAnyAttribute(AnnotationExpr annotationExpr, String ... keys) {
for (String key : keys) {
Optional<Expression> optional = getAttribute(annotationExpr, key);
if(optional.isPresent()){
return optional;
}
}
return Optional.empty();
}
}
package com.apidoc.core.common.helper;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.FieldDeclaration;
import com.github.javaparser.ast.type.ClassOrInterfaceType;
import com.github.javaparser.resolution.types.ResolvedReferenceType;
import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserClassDeclaration;
import com.github.javaparser.symbolsolver.reflectionmodel.ReflectionClassDeclaration;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@Slf4j
public class ClassDeclarationHelper {
public static Optional<ClassOrInterfaceDeclaration> getParent(ClassOrInterfaceDeclaration n) {
if (n.getExtendedTypes().isEmpty()) {
return Optional.empty();
}
return tryToResolve(n.getExtendedTypes().get(0));
}
public static Optional<ClassOrInterfaceDeclaration> tryToResolve(ClassOrInterfaceType type) {
try {
ResolvedReferenceType resolvedReferenceType = type.resolve();
if (resolvedReferenceType.getTypeDeclaration() instanceof JavaParserClassDeclaration) {
JavaParserClassDeclaration typeDeclaration = (JavaParserClassDeclaration) resolvedReferenceType.getTypeDeclaration();
return Optional.of(typeDeclaration.getWrappedNode());
}else if(resolvedReferenceType.getTypeDeclaration() instanceof ReflectionClassDeclaration){
ReflectionClassDeclaration typeDeclaration = (ReflectionClassDeclaration) resolvedReferenceType.getTypeDeclaration();
System.out.println("type Declaration:"+typeDeclaration);
//TODO
}
} catch (Exception e) {
log.warn(e.getMessage());
}
return Optional.empty();
}
}
package com.apidoc.core.common.helper;
import com.github.javaparser.ast.body.FieldDeclaration;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.comments.Comment;
import com.github.javaparser.javadoc.description.JavadocDescription;
import com.github.javaparser.javadoc.description.JavadocDescriptionElement;
import com.github.javaparser.javadoc.description.JavadocInlineTag;
import com.github.javaparser.resolution.MethodUsage;
import com.github.javaparser.resolution.declarations.ResolvedFieldDeclaration;
import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserClassDeclaration;
import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserFieldDeclaration;
import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserMethodDeclaration;
import java.util.Optional;
import java.util.stream.Collectors;
public class CommentHelper {
/**
* 获取完整注释字符串
* @param description
* @return
*/
public static String getDescription(JavadocDescription description){
return description.getElements()
.stream()
.filter(e -> !(e instanceof JavadocInlineTag))
.map(JavadocDescriptionElement::toText).collect(Collectors.joining());
}
public static String getContent(Comment comment){
if(!comment.isJavadocComment()){
return comment.getContent();
}
return getDescription(comment.asJavadocComment().parse().getDescription());
}
public static String getComment(MethodUsage it){
if (it.getDeclaration() instanceof JavaParserMethodDeclaration) {
MethodDeclaration wrappedNode = ((JavaParserMethodDeclaration) it.getDeclaration()).getWrappedNode();
Optional<Comment> optional = wrappedNode.getComment();
if(optional.isPresent()){
return CommentHelper.getContent(optional.get());
}
}
return null;
}
public static String getComment(ResolvedFieldDeclaration it){
if(it instanceof JavaParserFieldDeclaration){
FieldDeclaration wrappedNode = ((JavaParserFieldDeclaration) it).getWrappedNode();
Optional<Comment> optional = wrappedNode.getComment();
if(optional.isPresent()){
return CommentHelper.getContent(optional.get());
}
}else if(it instanceof JavaParserClassDeclaration){
JavaParserClassDeclaration classDeclaration = (JavaParserClassDeclaration) it;
}
return null;
}
}
package com.apidoc.core.common.helper;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.Node;
import java.util.Optional;
public class CompilationUnitHelper {
public static Optional<CompilationUnit> getCompilationUnit(Node node){
if(node instanceof CompilationUnit){
return Optional.of((CompilationUnit) node);
}
if (node.getParentNode().isPresent()){
return getCompilationUnit(node.getParentNode().get());
}
return Optional.empty();
}
}
package com.apidoc.core.common.helper;
import com.github.javaparser.ast.NodeList;
import com.github.javaparser.ast.expr.*;
import com.github.javaparser.resolution.Resolvable;
import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserFieldDeclaration;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
@Slf4j
public class ExpressionHelper {
/**
* 解析表达式,获取表达式的值
* TODO 更复杂的表达式解析
* @param expr
* @return
*/
public static Object getValue(Expression expr) {
if (expr.isStringLiteralExpr()) {
return expr.asStringLiteralExpr().getValue();
}
if (expr.isIntegerLiteralExpr()) {
return expr.asIntegerLiteralExpr().getValue();
}
if (expr.isDoubleLiteralExpr()) {
return expr.asDoubleLiteralExpr().getValue();
}
if (expr.isLongLiteralExpr()) {
return expr.asLongLiteralExpr().getValue();
}
if (expr.isBooleanLiteralExpr()) {
return expr.asBooleanLiteralExpr().getValue();
}
if (expr.isArrayInitializerExpr()) {
return expr.asArrayInitializerExpr().getValues().stream().map(ExpressionHelper::getValue).collect(Collectors.toList());
}
if (expr instanceof Resolvable) {
return String.valueOf(resolve((Resolvable) expr));
}
return expr.toString();
}
public static String getStringValue(Expression expression){
if(expression.isStringLiteralExpr()){
return expression.asStringLiteralExpr().getValue();
}else if(expression.isArrayInitializerExpr()){
NodeList<Expression> values = expression.asArrayInitializerExpr().getValues();
if(values.size()>0){
return getStringValue(values.get(0));
}
}else if(expression instanceof Resolvable){
return String.valueOf(resolve((Resolvable)expression));
}
return expression.toString();
}
public static List<String> getStringValues(Expression expression){
List<String> results = new ArrayList<>();
if(expression.isStringLiteralExpr()){
results.add(expression.asStringLiteralExpr().getValue());
}else if(expression.isArrayInitializerExpr()) {
NodeList<Expression> values = expression.asArrayInitializerExpr().getValues();
for (Expression value : values) {
results.addAll(getStringValues(value));
}
}else if(expression instanceof Resolvable){
results.add(String.valueOf(resolve((Resolvable)expression)));
}else{
results.add(expression.toString());
}
return results;
}
private static Object resolve(Resolvable resolvable){
try {
Object resolve = resolvable.resolve();
if(resolve instanceof JavaParserFieldDeclaration){
Optional<Expression> initializer = ((JavaParserFieldDeclaration) resolve).getVariableDeclarator().getInitializer();
if (initializer.isPresent()) {
return getStringValue(initializer.get());
}
}
} catch (Exception e) {
log.warn("resolve expression {} error: {}",resolvable.toString(),e.getMessage());
}
return resolvable;
}
}
package com.apidoc.core.common.helper;
import com.github.javaparser.ast.expr.Expression;
import com.github.javaparser.resolution.declarations.ResolvedFieldDeclaration;
import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserFieldDeclaration;
import java.util.Optional;
public class FieldHelper {
/**
* 通过access方法,获取属性名
* @param methodName access方法名
* @return 属性名
*/
public static String getByAccessMethod(String methodName){
if(methodName.startsWith("is") && methodName.length()>2){
String first = methodName.substring(2, 3);
String less = methodName.substring(3);
return first.toLowerCase() + less;
}
if(methodName.startsWith("get") && methodName.length()>3){
String first = methodName.substring(3, 4);
String less = methodName.substring(4);
return first.toLowerCase() + less;
}
return null;
}
public static Optional<Expression> getInitializer(ResolvedFieldDeclaration declaredField){
if(declaredField instanceof JavaParserFieldDeclaration){
JavaParserFieldDeclaration field = (JavaParserFieldDeclaration) declaredField;
return field.getVariableDeclarator().getInitializer();
}
return Optional.empty();
}
}
package com.apidoc.core.common.helper;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.stream.Collectors;
@Slf4j
public class FileHelper {
public static void write(Path file, String content) {
if (file.getParent() != null) {
try {
Files.createDirectories(file.getParent());
} catch (IOException e) {
throw new RuntimeException("Failed create directory", e);
}
}
try (BufferedWriter writer = Files.newBufferedWriter(file, StandardCharsets.UTF_8)) {
writer.write(content);
writer.flush();
} catch (IOException e) {
throw new RuntimeException("Failed to write file", e);
}
}
public static List<Path> find(Path start, String structure){
try {
return Files.walk(start)
.filter(p->p.endsWith(structure)).collect(Collectors.toList());
} catch (IOException e) {
log.warn("find path error:{} {}", start, e.getMessage());
}
return Lists.newArrayList();
}
}
package com.apidoc.core.common.helper;
import com.github.javaparser.ast.body.FieldDeclaration;
import com.github.javaparser.ast.expr.AnnotationExpr;
import com.github.javaparser.ast.expr.Expression;
import com.github.javaparser.resolution.declarations.ResolvedFieldDeclaration;
import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserFieldDeclaration;
import java.util.Optional;
public class JsonPropertyHelper {
public static final String ANNOTAION_JSON_PROPERTY = "JsonProperty";
public static final String ANNOTAION_JSON_FIELD = "JSONField";
public static final String ANNOTAION_SERIALIZED_NAME = "SerializedName";
public static Optional<String> getJsonName(ResolvedFieldDeclaration declaredField){
if(declaredField instanceof JavaParserFieldDeclaration){
FieldDeclaration fieldDeclaration = ((JavaParserFieldDeclaration) declaredField).getWrappedNode();
return OptionalHelper.any(
getStringValue(fieldDeclaration, ANNOTAION_JSON_PROPERTY, "value"),
getStringValue(fieldDeclaration, ANNOTAION_JSON_FIELD, "name"),
getStringValue(fieldDeclaration, ANNOTAION_SERIALIZED_NAME, "value")
);
}
return Optional.empty();
}
public static Optional<String> getStringValue(FieldDeclaration fieldDeclaration, String anno, String attr){
Optional<AnnotationExpr> optional = fieldDeclaration.getAnnotationByName(anno);
if (optional.isPresent()) {
Optional<Expression> expr = AnnotationHelper.getAttribute(optional.get(),attr);
if (expr.isPresent()) {
return Optional.of(ExpressionHelper.getStringValue(expr.get()));
}
}
return Optional.empty();
}
}
package com.apidoc.core.common.helper;
import java.util.Optional;
public class OptionalHelper {
@SafeVarargs
public static <T> Optional<T> any(Optional<T> ... optionals){
for (Optional<T> optional : optionals) {
if(optional.isPresent()){
return optional;
}
}
return Optional.empty();
}
}
package com.apidoc.core.common.helper;
import com.google.common.collect.Sets;
import java.util.Set;
/**
* 解决循环依赖问题
*/
public class ReferenceContext {
private static ThreadLocal<ReferenceContext> threadLocal = new ThreadLocal<>();
public static ReferenceContext getInstance(){
ReferenceContext context = threadLocal.get();
if (context == null) {
context = new ReferenceContext();
threadLocal.set(context);
}
return context;
}
private final Set<Object> set = Sets.newHashSet();
public boolean push(Object object){
return set.add(object);
}
public boolean remove(Object object){
return set.remove(object);
}
public Set<Object> getValues(){
return set;
}
}
package com.apidoc.core.common.helper;
import com.google.common.base.Strings;
public class StringHelper {
public static boolean isBlank(String text) {
return Strings.isNullOrEmpty(text) || Strings.isNullOrEmpty(text.trim());
}
public static boolean nonBlank(String text) {
return !isBlank(text);
}
public static boolean isBlank(Object text) {
if(text instanceof String){
return isBlank(((String) text));
}
return isBlank(String.valueOf(text));
}
public static boolean nonBlank(Object text) {
if(text instanceof String){
return nonBlank(((String) text));
}
return nonBlank(String.valueOf(text));
}
public static String join(String delimiter, String ... values){
StringBuilder builder = new StringBuilder();
for (String value : values) {
if(isBlank(value)){
continue;
}
if(builder.length()>0){
builder.append(delimiter);
}
builder.append(value);
}
return builder.toString();
}
}
package com.apidoc.core.common.helper;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.ImportDeclaration;
import com.github.javaparser.ast.type.Type;
import java.util.Optional;
public class TypeNameHelper {
public static String getName(Type type){
String name = type.toString();
if(type.isClassOrInterfaceType()){
name = type.asClassOrInterfaceType().getNameAsString();
}
Optional<CompilationUnit> optional = CompilationUnitHelper.getCompilationUnit(type);
if(optional.isPresent()){
CompilationUnit compilationUnit = optional.get();
return getNameFromImport(name, compilationUnit);
}
return name;
}
private static String getNameFromImport(String name, CompilationUnit compilationUnit){
int dotPos = name.indexOf('.');
String prefix = null;
if (dotPos > -1) {
prefix = name.substring(0, dotPos);
}
for (ImportDeclaration importDecl : compilationUnit.getImports()) {
if (!importDecl.isAsterisk()) {
String qName = importDecl.getNameAsString();
boolean defaultPackage = !importDecl.getName().getQualifier().isPresent();
boolean found = !defaultPackage && importDecl.getName().getIdentifier().equals(name);
if (!found) {
if (prefix != null) {
found = qName.endsWith("." + prefix);
if (found) {
qName = qName + name.substring(dotPos);
}
}
}
if (found) {
return qName;
}
}
}
return name;
}
}
package com.apidoc.core.common.helper;
import com.github.javaparser.resolution.declarations.ResolvedTypeParameterDeclaration;
import com.github.javaparser.resolution.types.ResolvedReferenceType;
import com.github.javaparser.resolution.types.ResolvedType;
import com.github.javaparser.utils.Pair;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
public class TypeParameterHelper {
/**
* 获取泛型信息
* @param referenceType
* @param index 位置信息
* @return
*/
public static Optional<ResolvedType> getTypeParameter(ResolvedReferenceType referenceType, int index){
List<Pair<ResolvedTypeParameterDeclaration, ResolvedType>> typeParameters = referenceType.getTypeParametersMap();
if(typeParameters.size()>index){
Pair<ResolvedTypeParameterDeclaration, ResolvedType> pair = typeParameters.get(index);
return Optional.of(pair.b);
}
return Optional.empty();
}
/**
* 获取泛型信息
* @param referenceType
* @param a 如 T E 等
* @return
*/
public static Optional<ResolvedType> getTypeParameter(ResolvedReferenceType referenceType, String a){
List<Pair<ResolvedTypeParameterDeclaration, ResolvedType>> typeParameters = referenceType.getTypeParametersMap();
for (Pair<ResolvedTypeParameterDeclaration, ResolvedType> pair : typeParameters) {
if(Objects.equals(pair.a.getName(),a)){
return Optional.of(pair.b);
}
}
return Optional.empty();
}
/**
* 使用父类的泛型
* @param parent
* @param field
*/
public static ResolvedType useClassTypeParameter(ResolvedReferenceType parent, ResolvedReferenceType field ){
for (Pair<ResolvedTypeParameterDeclaration, ResolvedType> pair : field.getTypeParametersMap()) {
if(pair.b.isTypeVariable()){
Optional<ResolvedType> typeParameter = TypeParameterHelper.getTypeParameter(parent, pair.b.asTypeVariable().describe());
if (typeParameter.isPresent()) {
return field.replaceTypeVariables(pair.b.asTypeVariable().asTypeParameter(), typeParameter.get());
}
}
}
return field;
}
}
package com.apidoc.core.common.helper;
import com.github.javaparser.ast.body.FieldDeclaration;
import com.github.javaparser.ast.expr.AnnotationExpr;
import com.github.javaparser.resolution.declarations.ResolvedFieldDeclaration;
import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserFieldDeclaration;
import com.google.common.collect.Lists;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class ValidationHelper {
public static final String NULL = "Null";
public static final String NOT_NULL = "NotNull";
public static final String ASSERT_TRUE = "AssertTrue";
public static final String ASSERT_FALSE = "AssertFalse";
public static final String NOT_EMPTY = "NotEmpty";
public static final String NOT_BLANK = "NotBlank";
public static final String EMAIL = "Email";
public static final String MIN = "Min";
public static final String MAX = "Max";
public static final String SIZE = "Size";
public static final List<String> values = Lists.newArrayList(NULL,NOT_NULL,NOT_EMPTY,EMAIL,NOT_BLANK);
public static List<String> getValidations(ResolvedFieldDeclaration declaredField){
List<String> result = new ArrayList<>();
if(declaredField instanceof JavaParserFieldDeclaration){
FieldDeclaration fieldDeclaration = ((JavaParserFieldDeclaration) declaredField).getWrappedNode();
for (String value : values) {
Optional<AnnotationExpr> optional = fieldDeclaration.getAnnotationByName(value);
if(optional.isPresent()){
result.add(value);
}
}
}
return result;
}
}
package com.apidoc.core.common.markup;
import com.apidoc.core.common.markup.asciidoc.AsciiDocBuilder;
import java.util.List;
import java.util.function.Consumer;
/**
* 文档构建器
* 只实现满足需求的部分即可
*/
public interface MarkupBuilder {
static MarkupBuilder getInstance(){
return new AsciiDocBuilder();
}
/**
* 文档头
* @param text 标题
* @param attrs 文档属性
* @return this builder
*/
MarkupBuilder header(String text, CharSequence... attrs);
/**
* 文档标题
* @param level [1,5]
* @param text 标题
* @return this builder
*/
MarkupBuilder title(int level, String text);
/**
* 行内文字
*
* @param text text
* @return this builder
*/
MarkupBuilder text(String text);
/**
* 单行文字
* @param text text 换行将被替换为空格
* @return this builder
*/
MarkupBuilder textLine(String text);
/**
* 多行文字
* @param text text
* @return this builder
*/
MarkupBuilder paragraph(String text, CharSequence... attrs);
/**
* 带icon的各种段落
*/
MarkupBuilder note(String text);
MarkupBuilder tip(String text);
MarkupBuilder important(String text);
MarkupBuilder warning(String text);
MarkupBuilder caution(String text);
/**
* 各种block
*/
MarkupBuilder block(Consumer<MarkupBuilder> consumer, CharSequence flag, CharSequence... attrs);
MarkupBuilder listing(Consumer<MarkupBuilder> consumer, CharSequence... attrs);
MarkupBuilder literal(Consumer<MarkupBuilder> consumer, CharSequence... attrs);
MarkupBuilder sidebar(Consumer<MarkupBuilder> consumer, CharSequence... attrs);
MarkupBuilder comment(Consumer<MarkupBuilder> consumer, CharSequence... attrs);
MarkupBuilder passthrough(Consumer<MarkupBuilder> consumer, CharSequence... attrs);
MarkupBuilder quote(Consumer<MarkupBuilder> consumer, CharSequence... attrs);
MarkupBuilder example(Consumer<MarkupBuilder> consumer, CharSequence... attrs);
/**
* 列表 默认数字
* @param text
* @return
*/
MarkupBuilder list(String text);
/**
* 列表 默认数字
* @param text
* @param flag 数字,字母,罗马字母
* @return
*/
MarkupBuilder list(String text, CharSequence flag);
/**
* 链接
* @param text
* @param url
* @return
*/
MarkupBuilder url(String text, String url);
/**
*
* @param text
* @param url
* @return
*/
MarkupBuilder image(String text, String url);
/**
* 表格 默认第一组数据为表头
* @param data
* @return
*/
MarkupBuilder table(List<List<String>> data);
MarkupBuilder table(List<List<String>> data, boolean header, boolean footer);
/**
* 强调
*
* @param text text
* @return this builder
*/
MarkupBuilder emphasized(String text, CharSequence... textStyle);
/**
* 加粗
*
* @param text text
* @return this builder
*/
MarkupBuilder strong(String text, CharSequence... textStyle);
/**
* 等宽
*
* @param text text
* @return this builder
*/
MarkupBuilder monospaced(String text, CharSequence... textStyle);
/**
* 单引号
*
* @param text text
* @return this builder
*/
MarkupBuilder quoted(String text, CharSequence... textStyle);
/**
* 双引号
*
* @param text text
* @return this builder
*/
MarkupBuilder doubleQuoted(String text, CharSequence... textStyle);
/**
* 正常的引用文字
*
* @param text text
* @return this builder
*/
MarkupBuilder unquoted(String text, CharSequence... textStyle);
/**
* 换行
*
* @return this builder
*/
MarkupBuilder br();
/**
* 强制换行
*
* @return this builder
*/
MarkupBuilder hbr();
/**
* 另起一行
*
* @return this builder
*/
MarkupBuilder newLine();
/**
* 横线
*
* @return this builder
*/
MarkupBuilder pageBreak();
/**
* 获取文件内容
* @return
*/
String getContent();
/**
* 清空content
*/
void clean();
}
package com.apidoc.core.common.markup.asciidoc;
public enum AsciiDoc implements CharSequence {
EXTENSION(".adoc"),
/**
* 各种关键字
*/
HEADER("= "),
TABLE("|==="),
TABLE_CELL("|"),
TITLE("="),
EMPHASIZED("_"),
STRONG("*"),
MONOSPACED("+"),
QUOTED("`"),
DOUBLE_QUOTED("``"),
UNQUOTED("#"),
LIST_FLAG("1. "),
LIST_FLAG_LETTER("a. "),
LIST_FLAG_LETTER_UPPER("A. "),
LISTING("----"),
LITERAL("...."),
SIDEBAR("****"),
COMMENT("////"),
PASSTHROUGH("++++"),
QUOTE("____"),
EXAMPLE("===="),
NOTE("NOTE"),
TIP("TIP"),
IMPORTANT("IMPORTANT"),
WARNING("WARNING"),
CAUTION("CAUTION"),
PAGEBREAKS("<<<"),
HARDBREAKS("[%hardbreaks]"),
WHITESPACE(" "),
BR("\r\n"),
NEW_LINE("\r\n\r\n"),
HBR(" +"),
/**
* 文档属性
*/
TOC(":toc:"),
LEFT("left"),
TOC_LEVEL(":toclevels:"),
TOC_TITLE(":toc-title:"),
DOCTYPE(":doctype:"),
BOOK("book"),
SOURCE_HIGHLIGHTER(":source-highlighter:"),
PRETTIFY("prettify"),
HIGHLIGHTJS("highlightjs"),
CODERAY("coderay"),
/**
* 文字样式
*/
STYLE_BIG("big"),
STYLE_SMALL("small"),
STYLE_UNDERLINE("underline"),
STYLE_OVERLINE("overline"),
STYLE_LINE_THROUGH("line-through"),
;
private final String markup;
AsciiDoc(final String markup) {
this.markup = markup;
}
@Override
public int length() {
return markup.length();
}
@Override
public char charAt(int index) {
return markup.charAt(index);
}
@Override
public CharSequence subSequence(int start, int end) {
return markup.subSequence(start, end);
}
@Override
public String toString() {
return markup;
}
public static CharSequence attr(AsciiDoc key, Object value){
return key.toString() + " " + String.valueOf(value);
}
}
package com.apidoc.core.common.markup.asciidoc;
import com.apidoc.core.common.Assert;
import com.apidoc.core.common.markup.MarkupBuilder;
import com.google.common.base.Strings;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.regex.Matcher;
public class AsciiDocBuilder implements MarkupBuilder {
public static final int MAX_TITLE = 6;
private StringBuilder content = new StringBuilder();
@Override
public MarkupBuilder header(String text, CharSequence... attrs) {
Assert.notBlank(text, "header must not be blank");
content.append(AsciiDoc.HEADER);
content.append(nobr(text.trim()));
br();
for (CharSequence attr : attrs) {
content.append(attr);
br();
}
br();
return this;
}
@Override
public MarkupBuilder title(int level, String text) {
Assert.notBlank(text, "header must not be blank");
Assert.between(level, 1, MAX_TITLE, "title level can not be " + level);
br();
content.append(Strings.repeat(AsciiDoc.TITLE.toString(), level + 1)).append(AsciiDoc.WHITESPACE)
.append(nobr(text.trim()));
br();
return this;
}
@Override
public MarkupBuilder text(String text) {
if (Assert.isBlank(text)) {
return this;
}
content.append(text.trim());
return this;
}
@Override
public MarkupBuilder textLine(String text) {
if (Assert.isBlank(text)) {
return this;
}
text(nobr(text));
br();
return this;
}
@Override
public MarkupBuilder paragraph(String text, CharSequence... attrs) {
if (Assert.isBlank(text)) {
return this;
}
content.append(AsciiDoc.HARDBREAKS);
br();
if (attrs.length > 0) {
content.append("[");
for (CharSequence attr : attrs) {
content.append(attr).append(AsciiDoc.WHITESPACE);
}
content.append("]");
br();
}
text(text);
newLine();
return this;
}
@Override
public MarkupBuilder note(String text) {
paragraph(text, AsciiDoc.NOTE);
return this;
}
@Override
public MarkupBuilder tip(String text) {
paragraph(text, AsciiDoc.TIP);
return this;
}
@Override
public MarkupBuilder important(String text) {
paragraph(text, AsciiDoc.IMPORTANT);
return this;
}
@Override
public MarkupBuilder warning(String text) {
paragraph(text, AsciiDoc.WARNING);
return this;
}
@Override
public MarkupBuilder caution(String text) {
paragraph(text, AsciiDoc.CAUTION);
return this;
}
@Override
public MarkupBuilder block(Consumer<MarkupBuilder> consumer, CharSequence flag, CharSequence... attrs) {
if (attrs.length > 0) {
content.append("[");
for (CharSequence attr : attrs) {
content.append(attr).append(" ");
}
content.append("]");
br();
}
content.append(flag);
br();
consumer.accept(this);
br();
content.append(flag);
newLine();
return this;
}
@Override
public MarkupBuilder listing(Consumer<MarkupBuilder> consumer, CharSequence... attrs) {
return block(consumer, AsciiDoc.LISTING, attrs);
}
@Override
public MarkupBuilder literal(Consumer<MarkupBuilder> consumer, CharSequence... attrs) {
return block(consumer, AsciiDoc.LITERAL, attrs);
}
@Override
public MarkupBuilder sidebar(Consumer<MarkupBuilder> consumer, CharSequence... attrs) {
return block(consumer, AsciiDoc.SIDEBAR, attrs);
}
@Override
public MarkupBuilder comment(Consumer<MarkupBuilder> consumer, CharSequence... attrs) {
return block(consumer, AsciiDoc.COMMENT, attrs);
}
@Override
public MarkupBuilder passthrough(Consumer<MarkupBuilder> consumer, CharSequence... attrs) {
return block(consumer, AsciiDoc.PASSTHROUGH, attrs);
}
@Override
public MarkupBuilder quote(Consumer<MarkupBuilder> consumer, CharSequence... attrs) {
return block(consumer, AsciiDoc.QUOTE, attrs);
}
@Override
public MarkupBuilder example(Consumer<MarkupBuilder> consumer, CharSequence... attrs) {
return block(consumer, AsciiDoc.EXAMPLE, attrs);
}
@Override
public MarkupBuilder list(String text) {
return list(text, AsciiDoc.LIST_FLAG);
}
@Override
public MarkupBuilder list(String text, CharSequence flag) {
if (!Assert.isBlank(text)) {
content.append(flag).append(nobr(text));
}
return this;
}
@Override
public MarkupBuilder url(String text, String url) {
if (!Assert.isBlank(text) && !Assert.isBlank(url)) {
content.append(url).append("[").append(nobr(text)).append("]");
br();
}
return this;
}
@Override
public MarkupBuilder image(String text, String url) {
if (!Assert.isBlank(text) && !Assert.isBlank(url)) {
text("image:");
url(text, url);
}
return this;
}
@Override
public MarkupBuilder table(List<List<String>> data) {
return table(data, true, false);
}
@Override
public MarkupBuilder table(List<List<String>> data, boolean header, boolean footer) {
int min = 1;
if (header) {
min++;
}
if (footer) {
min++;
}
if (data.size() < min) {
return this;
}
content.append("[stripes=even,options=\"");
if (header) {
content.append("header");
}
if (header && footer) {
content.append(",");
}
if (footer) {
content.append("footer");
}
content.append("\"]");
br();
content.append(AsciiDoc.TABLE);
br();
for (List<String> rows : data) {
for (String cell : rows) {
content.append(AsciiDoc.TABLE_CELL);
if(cell!=null){
monospaced(cell.replace(AsciiDoc.TABLE_CELL, "\\" + AsciiDoc.TABLE_CELL));
}
}
br();
}
content.append(AsciiDoc.TABLE);
newLine();
return this;
}
public MarkupBuilder style(CharSequence flag, String text, CharSequence... textStyle) {
if (Assert.isBlank(text)) {
return this;
}
if (Objects.nonNull(textStyle) && textStyle.length > 0) {
content.append("[");
for (CharSequence style : textStyle) {
content.append(style).append(" ");
}
content.append("]");
}
content.append(flag);
text(text);
content.append(flag);
return this;
}
@Override
public MarkupBuilder emphasized(String text, CharSequence... textStyle) {
return style(AsciiDoc.EMPHASIZED, text, textStyle);
}
@Override
public MarkupBuilder strong(String text, CharSequence... textStyle) {
return style(AsciiDoc.STRONG, text, textStyle);
}
@Override
public MarkupBuilder monospaced(String text, CharSequence... textStyle) {
return style(AsciiDoc.MONOSPACED, text, textStyle);
}
@Override
public MarkupBuilder quoted(String text, CharSequence... textStyle) {
return style(AsciiDoc.QUOTE, text, textStyle);
}
@Override
public MarkupBuilder doubleQuoted(String text, CharSequence... textStyle) {
return style(AsciiDoc.DOUBLE_QUOTED, text, textStyle);
}
@Override
public MarkupBuilder unquoted(String text, CharSequence... textStyle) {
return style(AsciiDoc.UNQUOTED, text, textStyle);
}
@Override
public MarkupBuilder br() {
content.append(AsciiDoc.BR);
return this;
}
@Override
public MarkupBuilder hbr() {
content.append(AsciiDoc.HBR);
return this;
}
@Override
public MarkupBuilder newLine() {
content.append(AsciiDoc.NEW_LINE);
return this;
}
@Override
public MarkupBuilder pageBreak() {
content.append(AsciiDoc.PAGEBREAKS);
br();
return this;
}
@Override
public String getContent() {
return content.toString();
}
@Override
public void clean() {
content = new StringBuilder();
}
String nobr(String content) {
if (Assert.isBlank(content)) {
return content;
}
return content.replaceAll(AsciiDoc.BR.toString(),
Matcher.quoteReplacement(AsciiDoc.WHITESPACE.toString()));
}
}
package com.apidoc.core.common.postman;
import lombok.Getter;
import lombok.Setter;
import java.util.ArrayList;
import java.util.List;
@Getter
@Setter
public class Body{
BodyMode mode;
String raw;
List<Parameter> urlencoded = new ArrayList<>();
List<Parameter> formdata = new ArrayList<>();
}
package com.apidoc.core.common.postman;
/**
* 对应postman定义的mode
*/
public enum BodyMode {
raw,urlencoded,formdata,file
}
package com.apidoc.core.common.postman;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Getter;
import lombok.Setter;
import java.util.ArrayList;
import java.util.List;
@Getter
@Setter
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Folder {
String name;
String description;
List<Folder> item = new ArrayList<>();
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment