001/** 002 * Copyright (C) 2006-2025 Talend Inc. - www.talend.com 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.talend.sdk.component.tools; 017 018import static java.util.Locale.ENGLISH; 019import static java.util.Locale.ROOT; 020import static java.util.Optional.ofNullable; 021import static java.util.stream.Collectors.joining; 022 023import java.io.File; 024import java.util.Locale; 025import java.util.Map; 026import java.util.stream.IntStream; 027import java.util.stream.Stream; 028 029public class AsciidocDocumentationGenerator extends DocBaseGenerator { 030 031 private final String levelPrefix; 032 033 private final Map<String, String> formats; 034 035 private final Map<String, String> attributes; 036 037 private final File templateDir; 038 039 private final File workDir; 040 041 private final String templateEngine; 042 043 private final String title; 044 045 private final String version; 046 047 // CHECKSTYLE:OFF - used by reflection so better to not create a wrapper 048 public AsciidocDocumentationGenerator(final File[] classes, final File output, final String title, final int level, 049 final Map<String, String> formats, final Map<String, String> attributes, final File templateDir, 050 final String templateEngine, final Object log, final File workDir, final String version, 051 final Locale locale) { 052 // CHECKSTYLE:ON 053 super(classes, locale, log, output); 054 this.title = title; 055 this.formats = formats; 056 this.attributes = attributes; 057 this.templateDir = templateDir; 058 this.templateEngine = templateEngine; 059 this.workDir = workDir; 060 this.version = version; 061 this.levelPrefix = IntStream.range(0, level).mapToObj(i -> "=").collect(joining("")); 062 } 063 064 @Override 065 public void doRun() { 066 final String doc = components() 067 .map(this::toAsciidoc) 068 .collect(StringBuilder::new, StringBuilder::append, StringBuilder::append) 069 .toString(); 070 write(output, doc); 071 log.info("Generated " + output.getAbsolutePath()); 072 renderAdoc(); 073 } 074 075 private String toAsciidoc(final ComponentDescription desc) { 076 final String partMarker = desc.getName(); 077 return "//component_start:" + partMarker + "\n\n" + levelPrefix + " " + desc.getName() + "\n\n" 078 + desc.getDocumentation() 079 + (desc.getParameters().isEmpty() ? "" 080 : ("//configuration_start\n\n" + levelPrefix + "= Configuration\n\n" + desc 081 .parameters() 082 .map(this::toAsciidoctor) 083 .collect(joining("\n", "[cols=\"d,d,m,a,e,d\",options=\"header\"]\n" 084 + "|===\n|Display Name|Description|Default Value|Enabled If|Configuration Path|Configuration Type\n", 085 "\n|===\n\n//configuration_end\n\n")))) 086 + "//component_end:" + partMarker + "\n\n"; 087 } 088 089 private String toAsciidoctor(final Param p) { 090 return "|" + p.getDisplayName() + '|' + p.getDocumentation() + '|' + p.getDefaultValue() + '|' 091 + doRenderConditions(p.getConditions()) + '|' + p.getFullPath() + '|' + p.getType(); 092 } 093 094 private String doRenderConditions(final Conditions conditions) { 095 switch (conditions.getConditions().size()) { 096 case 0: 097 return "Always enabled"; 098 case 1: 099 return renderCondition(conditions.getConditions().iterator().next()); 100 default: 101 final String conds = conditions 102 .getConditions() 103 .stream() 104 .map(this::renderCondition) 105 .map(c -> "- " + c) 106 .collect(joining("\n", "\n", "\n")); 107 switch (conditions.getOperator().toUpperCase(ROOT)) { 108 case "OR": 109 return "One of these conditions is meet:\n" + conds; 110 case "AND": 111 default: 112 return "All of the following conditions are met:\n" + conds; 113 } 114 } 115 } 116 117 private String renderCondition(final DocBaseGenerator.Condition condition) { 118 final String values = 119 Stream.of(condition.getValue().split(",")).map(v -> '`' + v + '`').collect(joining(" or ")); 120 switch (ofNullable(condition.getStrategy()).orElse("default").toLowerCase(ROOT)) { 121 case "length": 122 if (condition.isNegate()) { 123 if (values.equals("`0`")) { 124 return '`' + condition.getPath() + "` is not empty"; 125 } 126 return "the length of `" + condition.getPath() + "` is not " + values; 127 } 128 if (values.equals("`0`")) { 129 return '`' + condition.getPath() + "` is empty"; 130 } 131 return "the length of `" + condition.getPath() + "` is " + values; 132 case "contains": 133 if (condition.isNegate()) { 134 return '`' + condition.getPath() + "` does not contain " + values; 135 } 136 return '`' + condition.getPath() + "` contains " + values; 137 case "contains(lowercase=true)": 138 if (condition.isNegate()) { 139 return "the lowercase value of `" + condition.getPath() + "` does not contain " + values; 140 } 141 return "the lowercase value of `" + condition.getPath() + "` contains " + values; 142 case "default": 143 default: 144 if (condition.isNegate()) { 145 return '`' + condition.getPath() + "` is not equal to " + values; 146 } 147 return '`' + condition.getPath() + "` is equal to " + values; 148 } 149 } 150 151 private void renderAdoc() { 152 try (final AsciidoctorExecutor asciidoctorExecutor = new AsciidoctorExecutor()) { 153 ofNullable(formats).ifPresent(f -> f.forEach((format, output) -> { 154 switch (format.toLowerCase(ENGLISH)) { 155 case "html": 156 asciidoctorExecutor 157 .render(workDir, version, log, "html5", this.output, new File(output), title, 158 attributes, templateDir, templateEngine); 159 break; 160 case "pdf": 161 asciidoctorExecutor 162 .render(workDir, version, log, "pdf", this.output, new File(output), title, 163 attributes, templateDir, templateEngine); 164 break; 165 default: 166 throw new IllegalArgumentException("unknown format: '" + format + "', supported: [html, pdf]"); 167 } 168 })); 169 } 170 } 171}