diff --git a/LICENSE.md b/LICENSE.md index 858cc21..f60438a 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,4 +1,3 @@ - The MIT License (MIT) Copyright (c) 2023 alkoleft diff --git a/README.md b/README.md index c1533d8..786c333 100644 --- a/README.md +++ b/README.md @@ -1 +1,13 @@ # bsldoc + +## Запуск + +### Параметры запуска + +`bsldoc --format= --only-subsystems= --regions= source destination` + +* `--format` - Формат +* `--only-subsystems` - Список подсистем, по которым строится документация +* `--regions` - Фильтр регионов, для которых строится документация +* `source` - Каталог исходников +* `destination` - Каталог выгрузки документации \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 0c995c9..511dc53 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -16,6 +16,7 @@ repositories { mavenLocal() mavenCentral() maven(url = "https://jitpack.io") + maven(url = "https://s01.oss.sonatype.org/content/repositories/snapshots/") } java { @@ -28,20 +29,15 @@ java.sourceSets["main"].java { } dependencies { - // spring - implementation("org.springframework.boot:spring-boot-starter") - implementation("org.springframework.boot:spring-boot-starter-websocket") - implementation("info.picocli:picocli-spring-boot-starter:4.7.1") + implementation("info.picocli", "picocli", "4.7.5") - implementation("com.github.1c-syntax", "bsl-language-server", "0.20.0") - - implementation("com.github.1c-syntax", "mdclasses", "0.10.3") - implementation("io.github.1c-syntax", "bsl-common-library", "f6714e4e") - implementation("io.github.1c-syntax", "supportconf", "0.1.1") { - exclude("io.github.1c-syntax", "bsl-common-library") - } - implementation("com.github.1c-syntax", "bsl-parser", "167aaad827322e09ccde4658a71152dad234de4b") { + implementation("com.github.1c-syntax", "mdclasses", "develop-SNAPSHOT") + implementation("com.github.1c-syntax", "utils", "0.5.1") + implementation("io.github.1c-syntax", "bsl-common-library", "0.5.0") + implementation("io.github.1c-syntax", "supportconf", "0.12.1") + implementation("com.github.1c-syntax", "bsl-parser", "develop-SNAPSHOT") { exclude("com.tunnelvisionlabs", "antlr4-annotations") + exclude("commons-beanutils", "commons-beanutils") exclude("com.ibm.icu", "*") exclude("org.antlr", "ST4") exclude("org.abego.treelayout", "org.abego.treelayout.core") @@ -49,10 +45,12 @@ dependencies { exclude("org.glassfish", "javax.json") } + implementation("commons-io", "commons-io", "2.14.0") + implementation("ch.qos.logback:logback-core:1.2.11") + runtimeOnly("ch.qos.logback:logback-classic:1.2.11") + // template engine implementation("com.github.jknack:handlebars:4.3.1") - implementation("org.apache.velocity:velocity-engine-core:2.3") - implementation("org.apache.velocity:velocity-tools:2.0") testImplementation("org.junit.jupiter:junit-jupiter:$JUINT_VERSION") testImplementation("org.junit.jupiter:junit-jupiter-api:$JUINT_VERSION") @@ -74,41 +72,14 @@ tasks.withType { } tasks.jar { -// manifest { -// attributes["Main-Class"] = "ru.alkoleft.bsl.doc.Main" -// } enabled = true archiveClassifier.set("") } tasks.bootJar { -// manifest { -// attributes["Main-Class"] = "ru.alkoleft.bsl.doc.Main" -// } archiveClassifier.set("exec") } -tasks { - val fatJar = register("fatJar") { - dependsOn.addAll(listOf("compileJava", "processResources")) // We need this for Gradle optimization to work - archiveClassifier.set("standalone") // Naming the jar - duplicatesStrategy = DuplicatesStrategy.EXCLUDE - manifest { attributes(mapOf("Main-Class" to application.mainClass)) } // Provided we set it up in the application plugin configuration - val sourcesMain = sourceSets.main.get() - val contents = configurations.runtimeClasspath.get() - .map { if (it.isDirectory) it else zipTree(it) } + - sourcesMain.output - from(contents) - } - build { - dependsOn(fatJar) // Trigger fat jar creation during build - } - - group = "build" -} - - - publishing { repositories { maven { diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..7454180 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/src/main/java/ru/alkoleft/bsl/doc/AutodocManager.java b/src/main/java/ru/alkoleft/bsl/doc/AutodocManager.java new file mode 100644 index 0000000..d834c41 --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/AutodocManager.java @@ -0,0 +1,78 @@ +package ru.alkoleft.bsl.doc; + +import lombok.Builder; +import lombok.SneakyThrows; +import org.apache.commons.io.file.PathUtils; +import ru.alkoleft.bsl.doc.bsl.BslContext; +import ru.alkoleft.bsl.doc.bsl.Filter; +import ru.alkoleft.bsl.doc.content.processor.TitleProcessor; +import ru.alkoleft.bsl.doc.manual.ManualContent; +import ru.alkoleft.bsl.doc.model.ContentModel; +import ru.alkoleft.bsl.doc.options.ManualMergeStrategy; +import ru.alkoleft.bsl.doc.options.OutputOptions; +import ru.alkoleft.bsl.doc.render.BaseRender; +import ru.alkoleft.bsl.doc.render.StructureRender; +import ru.alkoleft.bsl.doc.render.handlebars.RenderContext; +import ru.alkoleft.bsl.doc.render.output.OutputStrategy; +import ru.alkoleft.bsl.doc.structure.StructureBuilder; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Objects; + +public class AutodocManager { + + private final OutputOptions outputOptions; + private final Path destination; + private final ManualMergeStrategy manualMergeStrategy; + private final ManualContent manualContent; + private final BslContext bslContext; + + @Builder + public AutodocManager(Filter filter, OutputOptions outputOptions, Path sources, Path destination, Path manualDocumentation, ManualMergeStrategy manualMergeStrategy) { + this.destination = destination; + this.outputOptions = outputOptions; + this.manualMergeStrategy = manualMergeStrategy; + manualContent = new ManualContent(manualDocumentation, destination); + bslContext = new BslContext(sources, filter); + + TitleProcessor.Factory.create(outputOptions.getOutputFormat()); + } + + public void loadData() { + manualContent.buildModel(outputOptions.getOutputFormat()); + } + + public void generateDocumentation() { + manualContent.copy(); + + var structure = StructureBuilder.builder(outputOptions).build(bslContext); + StructureBuilder.print(structure); + + var processor = OutputStrategy.create(manualMergeStrategy); + var contentModel = Objects.requireNonNullElseGet(manualContent.getContentModel(), ContentModel::new); + processor.init(outputOptions.getOutputFormat(), manualContent, contentModel); + var render = new StructureRender(outputOptions, processor, contentModel); + + BaseRender.setContext(RenderContext.Factory.create(outputOptions)); + render.render(structure, destination); + } + + @SneakyThrows + public void clearOutput() { + if (Files.exists(destination)) { + Files.walk(destination) + .filter(it -> it != destination) + .forEach(this::deletePath); + } + } + + private void deletePath(Path path) { + try { + PathUtils.delete(path); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/bsl/BslContext.java b/src/main/java/ru/alkoleft/bsl/doc/bsl/BslContext.java index 9d42d1d..e1d5764 100644 --- a/src/main/java/ru/alkoleft/bsl/doc/bsl/BslContext.java +++ b/src/main/java/ru/alkoleft/bsl/doc/bsl/BslContext.java @@ -1,194 +1,107 @@ package ru.alkoleft.bsl.doc.bsl; -import com.github._1c_syntax.bsl.languageserver.utils.Trees; -import com.github._1c_syntax.bsl.parser.BSLParser; -import com.github._1c_syntax.bsl.parser.BSLTokenizer; -import com.github._1c_syntax.bsl.types.MDOType; -import com.github._1c_syntax.mdclasses.Configuration; -import com.github._1c_syntax.mdclasses.mdo.MDCommonModule; -import org.antlr.v4.runtime.Token; -import ru.alkoleft.bsl.doc.bsl.symbols.MethodSymbol; -import ru.alkoleft.bsl.doc.bsl.symbols.MethodSymbolComputer; - -import java.nio.file.Files; +import com.github._1c_syntax.bsl.mdclasses.CF; +import com.github._1c_syntax.bsl.mdclasses.MDClasses; +import com.github._1c_syntax.bsl.mdo.MD; +import com.github._1c_syntax.bsl.mdo.Module; +import com.github._1c_syntax.bsl.mdo.ModuleOwner; +import com.github._1c_syntax.bsl.mdo.Subsystem; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import ru.alkoleft.bsl.doc.bsl.helpers.BslFilter; +import ru.alkoleft.bsl.doc.bsl.helpers.ModuleContextBuilder; + import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.Set; +import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.Stream; +@Slf4j public class BslContext { - Configuration configuration; - Filter filter; - - List modules = Collections.emptyList(); - - private static final Set VALID_TOKEN_TYPES_FOR_COMMENTS_SEARCH = Set.of( - BSLParser.LINE_COMMENT, - BSLParser.WHITE_SPACE, - BSLParser.AMPERSAND - ); + @Getter + private static BslContext current; + @Getter + private final CF configuration; + private final ModuleContextBuilder builder; + private List modules = Collections.emptyList(); public BslContext(Path path, Filter filter) { - this.filter = filter; - configuration = Configuration.create(path); + BslFilter.setFilter(filter); + builder = new ModuleContextBuilder(); + configuration = (CF) MDClasses.createConfiguration(path); + current = this; } - public Stream getModules() { - return modules - .stream() - .map(this::buildModuleContext) - .filter(ModuleContext::isNotEmpty); + public Stream getModules() { + return configuration.getChildren().stream() + .filter(ModuleOwner.class::isInstance) + .map(ModuleOwner.class::cast) + .flatMap(it -> it.getModules().stream()) + .filter(BslFilter::checkModule); } - public boolean contains(String name) { - return modules.stream().anyMatch(it -> it.getName().equalsIgnoreCase(name)); + public ModuleInfo getModuleContext(Module module) { + return builder.buildFilteredModuleContext(module); } - public void load() { - modules = configuration.getOrderedTopMDObjects().get(MDOType.COMMON_MODULE).stream() - .map(MDCommonModule.class::cast) - .map(this::buildModuleContext) - .collect(Collectors.toList()); - } + public Stream getRootSubsystems(boolean filtered) { + var stream = configuration.getSubsystems().stream(); - private ModuleContext buildModuleContext(MDCommonModule module) { - var bslModules = module.getModules(); - var srcPath = Path.of(bslModules.get(0).getUri()); - List methods; - String description; - try { - var content = Files.readString(srcPath); - MethodSymbolComputer computer = new MethodSymbolComputer(); - var tokenizer = new BSLTokenizer(content); - methods = computer.compute(tokenizer); - description = computeModuleDescription(tokenizer); - } catch (Exception e) { - throw new RuntimeException(module.getMdoReference().getMdoRef() + ". Module parsing error", e); + if (filtered) { + stream = stream.filter(BslFilter::checkRootSubsystem); } - - return ModuleContext.builder() - .owner(module) - .methods(methods) - .description(description) - .build(); + return stream; } - private String computeModuleDescription(BSLTokenizer tokenizer) { - var token = tokenizer.getAst().getStart(); - - var isDescription = false; - List comments = null; - while (token != null && !isDescription) { - comments = getComments(tokenizer.getTokens(), token); - isDescription = !comments.isEmpty() && comments.stream().map(Token::getText).map(it -> it.substring(2)).map(String::trim).noneMatch(it -> it.contains("Copyright") || it.contains("Экспортные")); - token = comments.isEmpty() ? null : comments.get(0); - } - if (isDescription) { - var lines = comments.stream() - .map(Token::getText) - .map(it -> it.substring(2)) - .filter(it -> it.isEmpty() || !it.matches("/+")) - .collect(Collectors.toList()); - - var chars = lines.get(0).toCharArray(); - - for (int i = 1; i < lines.size(); i++) { - var line = lines.get(i); - - for (int j = 0; j < chars.length; j++) { - if (line.length() <= j || line.charAt(j) != chars[j]) { - chars = Arrays.copyOf(chars, j); - break; - } - } - if (chars.length == 0) { - break; - } - } - - if (chars.length > 0) { - char[] finalChars = chars; - return lines.stream() - .map(it -> it.substring(finalChars.length)) - .collect(Collectors.joining("\n")); - } else { - return String.join("\n", lines); - } - } else { - return ""; - } + public Stream getChildrenSubsystems(Subsystem parent) { + return parent.getSubsystems().stream(); } - private ModuleContext buildModuleContext(ModuleContext module) { - - var stream = module.getMethods().stream(); - - if (filter.isExport()) { - stream = stream.filter(MethodSymbol::isExport); - } - - if (!filter.getRegions().isEmpty()) { - stream = stream.filter(this::regionFilter); - } - - return ModuleContext.builder() - .owner(module.getOwner()) - .methods(stream.collect(Collectors.toList())) - .description(module.getDescription()) - .build(); + public boolean contains(String name) { + return modules.stream().anyMatch(it -> it.getName().equalsIgnoreCase(name)); } - private boolean regionFilter(MethodSymbol m) { - var region = m.getRegion(); - - while (region != null) { - if (filter.getRegions().contains(region.getName())) { - return true; - } - region = region.getParent(); - } - return false; + public Optional getModule(String name) { + return modules.stream().filter(it -> it.getName().equalsIgnoreCase(name)).findAny(); } - public static List getComments(List tokens, Token token) { - List comments = new ArrayList<>(); - fillCommentsCollection(tokens, token, comments); - return comments; + public Stream getSubsystemObjects(Subsystem subsystem) { + return subsystem.getContent().stream() + .map(configuration::findChild) + .filter(Optional::isPresent) + .map(Optional::get); } - private static void fillCommentsCollection(List tokens, Token currentToken, List lines) { - - int index = currentToken.getTokenIndex(); + public void load() { + modules = getModules() + .map(builder::buildModuleContext) + .collect(Collectors.toList()); + } - if (index == 0) { - return; + public MethodInfo getMethodInfo(String link) { + if (link == null || link.isEmpty()) { + return null; } + var linkInfo = Links.parseLink(link, false); + return getMethodInfo(linkInfo); + } - var previousToken = tokens.get(index - 1); + public MethodInfo getMethodInfo(Links.Link link) { - if (abortSearchComments(previousToken, currentToken)) { - return; + if (link == null || link.getOwnerName() == null || link.getMethodName() == null) { + return null; } - fillCommentsCollection(tokens, previousToken, lines); - int type = previousToken.getType(); - if (type == BSLParser.LINE_COMMENT) { - lines.add(previousToken); - } - } + var module = getModule(link.getOwnerName()); + var method = module.flatMap(it -> it.getMethod(link.getMethodName())); - private static boolean abortSearchComments(Token previousToken, Token currentToken) { - int type = previousToken.getType(); - return !VALID_TOKEN_TYPES_FOR_COMMENTS_SEARCH.contains(type) || isBlankLine(previousToken, currentToken); + return MethodInfo.builder() + .module(module.orElse(null)) + .method(method.orElse(null)) + .publishing(module.isPresent() && method.isPresent() && BslFilter.checkModule(module.get()) && BslFilter.checkMethod(method.get())) + .build(); } - private static boolean isBlankLine(Token previousToken, Token currentToken) { - return previousToken.getType() == BSLParser.WHITE_SPACE - && (previousToken.getTokenIndex() == 0 - || (previousToken.getLine() + 1) != currentToken.getLine()); - } } diff --git a/src/main/java/ru/alkoleft/bsl/doc/bsl/Filter.java b/src/main/java/ru/alkoleft/bsl/doc/bsl/Filter.java index 8341efd..1e8cf77 100644 --- a/src/main/java/ru/alkoleft/bsl/doc/bsl/Filter.java +++ b/src/main/java/ru/alkoleft/bsl/doc/bsl/Filter.java @@ -10,6 +10,12 @@ @Builder public class Filter { boolean isExport; + boolean onlyCommonAndManagerModules = false; @Singular List regions; + @Singular + List rootSubsystems; + @Singular + List modules; + } diff --git a/src/main/java/ru/alkoleft/bsl/doc/bsl/Links.java b/src/main/java/ru/alkoleft/bsl/doc/bsl/Links.java new file mode 100644 index 0000000..2f2ab6f --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/bsl/Links.java @@ -0,0 +1,51 @@ +package ru.alkoleft.bsl.doc.bsl; + +import lombok.AllArgsConstructor; +import lombok.Value; +import lombok.experimental.UtilityClass; +import ru.alkoleft.bsl.doc.bsl.helpers.Strings; + +import java.util.regex.Pattern; + +@UtilityClass +public class Links { + private final Pattern patternWithSee = Pattern.compile("^см\\. (([\\wА-Яа-я\\.\\d]+)\\.)*([\\wА-Яа-я\\d]+)$"); + private final Pattern pattern = Pattern.compile("^(([\\wА-Яа-я\\.\\d]+)\\.)*([\\wА-Яа-я\\d]+)$"); + + public Link parseLink(String link, boolean withSee) { + var matcher = (withSee ? patternWithSee : pattern).matcher(link); + if (matcher.find()) { + return createLink(matcher.group(2), matcher.group(3)); + } + return null; + } + + public Link createLink(String owner, String method) { + if (owner != null && method != null) { + return new Link(owner, method); + } else if (BslContext.getCurrent().contains(method)) { + return new Link(method, null); + } else if (method != null) { + return new Link(null, method); + } else { + return null; + } + } + + @Value + @AllArgsConstructor + public static class Link { + String ownerName; + String methodName; + + public String getFullName() { + if (Strings.isNullOrEmpty(ownerName)) { + return methodName; + } else if (Strings.isNullOrEmpty(methodName)) { + return ownerName; + } else { + return ownerName + "." + methodName; + } + } + } +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/bsl/MethodInfo.java b/src/main/java/ru/alkoleft/bsl/doc/bsl/MethodInfo.java new file mode 100644 index 0000000..a853db0 --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/bsl/MethodInfo.java @@ -0,0 +1,13 @@ +package ru.alkoleft.bsl.doc.bsl; + +import lombok.Builder; +import lombok.Value; +import ru.alkoleft.bsl.doc.bsl.symbols.MethodSymbol; + +@Value +@Builder +public class MethodInfo { + MethodSymbol method; + ModuleInfo module; + boolean publishing; +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/bsl/ModuleContext.java b/src/main/java/ru/alkoleft/bsl/doc/bsl/ModuleContext.java deleted file mode 100644 index 219270a..0000000 --- a/src/main/java/ru/alkoleft/bsl/doc/bsl/ModuleContext.java +++ /dev/null @@ -1,25 +0,0 @@ -package ru.alkoleft.bsl.doc.bsl; - -import com.github._1c_syntax.mdclasses.mdo.AbstractMDObjectBSL; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Value; -import ru.alkoleft.bsl.doc.bsl.symbols.MethodSymbol; - -import java.util.List; - -@Builder -@Value -public class ModuleContext { - AbstractMDObjectBSL owner; - List methods; - String description; - - public String getName() { - return owner.getName(); - } - - public boolean isNotEmpty() { - return methods != null && !methods.isEmpty(); - } -} diff --git a/src/main/java/ru/alkoleft/bsl/doc/bsl/ModuleInfo.java b/src/main/java/ru/alkoleft/bsl/doc/bsl/ModuleInfo.java new file mode 100644 index 0000000..b68d0e2 --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/bsl/ModuleInfo.java @@ -0,0 +1,35 @@ +package ru.alkoleft.bsl.doc.bsl; + +import com.github._1c_syntax.bsl.mdo.MD; +import com.github._1c_syntax.bsl.mdo.Module; +import lombok.Builder; +import lombok.Value; +import ru.alkoleft.bsl.doc.bsl.symbols.MethodSymbol; + +import java.util.List; +import java.util.Optional; + +@Builder +@Value +public class ModuleInfo { + MD owner; + Module module; + List methods; + String description; + + public String getName() { + return owner.getName(); + } + + public boolean isNotEmpty() { + return methods != null && !methods.isEmpty(); + } + + public boolean isEmpty() { + return methods == null || methods.isEmpty(); + } + + public Optional getMethod(String name) { + return getMethods().stream().filter(it -> name.equalsIgnoreCase(it.getName())).findAny(); + } +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/bsl/helpers/BslFilter.java b/src/main/java/ru/alkoleft/bsl/doc/bsl/helpers/BslFilter.java new file mode 100644 index 0000000..4ee6e9c --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/bsl/helpers/BslFilter.java @@ -0,0 +1,76 @@ +package ru.alkoleft.bsl.doc.bsl.helpers; + +import com.github._1c_syntax.bsl.mdo.Module; +import com.github._1c_syntax.bsl.mdo.Subsystem; +import com.github._1c_syntax.bsl.types.ModuleType; +import com.github._1c_syntax.bsl.mdo.Module; +import lombok.Getter; +import lombok.experimental.UtilityClass; +import ru.alkoleft.bsl.doc.bsl.Filter; +import ru.alkoleft.bsl.doc.bsl.ModuleInfo; +import ru.alkoleft.bsl.doc.bsl.symbols.MethodSymbol; + +import java.util.Set; +import java.util.stream.Stream; + +@UtilityClass +public class BslFilter { + + private final Set moduleTypes = Set.of( + ModuleType.CommonModule, + ModuleType.ValueManagerModule, + ModuleType.ManagerModule + ); + + @Getter + private Filter filter; + + public static void setFilter(Filter filter) { + BslFilter.filter = filter; + } + + public boolean checkMethod(MethodSymbol method) { + return (!filter.isExport() || method.isExport()) + && (filter.getRegions().isEmpty() || checkRegion(method)); + } + + public Stream setFilter(Stream stream) { + if (filter.isExport()) { + stream = stream.filter(MethodSymbol::isExport); + } + + if (!filter.getRegions().isEmpty()) { + stream = stream.filter(BslFilter::checkRegion); + } + + return stream; + } + + public boolean checkModule(ModuleInfo module) { + return true; + } + + public boolean checkModule(Module module) { + return !filter.isOnlyCommonAndManagerModules() || moduleTypes.contains(module.getModuleType()); + } + + public boolean checkRegion(MethodSymbol m) { + var region = m.getRegion(); + + while (region != null) { + if (filter.getRegions().contains(region.getName())) { + return true; + } + region = region.getParent(); + } + return false; + } + + public boolean checkRootSubsystem(Subsystem subsystem) { + if (filter.getRootSubsystems().isEmpty()) { + return true; + } else { + return filter.getRootSubsystems().contains(subsystem.getName()); + } + } +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/bsl/helpers/MDOHelper.java b/src/main/java/ru/alkoleft/bsl/doc/bsl/helpers/MDOHelper.java new file mode 100644 index 0000000..dee6e13 --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/bsl/helpers/MDOHelper.java @@ -0,0 +1,33 @@ +package ru.alkoleft.bsl.doc.bsl.helpers; + +import com.github._1c_syntax.bsl.mdo.CommonModule; +import com.github._1c_syntax.bsl.mdo.MD; +import com.github._1c_syntax.bsl.mdo.Module; +import com.github._1c_syntax.bsl.mdo.children.ObjectModule; +import com.github._1c_syntax.bsl.types.MdoReference; +import lombok.experimental.UtilityClass; +import ru.alkoleft.bsl.doc.bsl.BslContext; + +@UtilityClass +public class MDOHelper { + + public MD getOwner(Module module) { + if (module instanceof ObjectModule) { + var reference = ((ObjectModule) module).getOwner(); + return BslContext.getCurrent().getConfiguration().findChild(reference).orElse(null); + } else if (module instanceof CommonModule) { + return ((CommonModule) module); + } else { + return null; + } + } + + public String getPresent(MD object) { + if (object.getSynonym().getContent().isEmpty()) { + return object.getName(); + } + var content = object.getSynonym().getContent(); + var itr = content.values().iterator(); + return itr.next(); + } +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/bsl/helpers/ModuleComputer.java b/src/main/java/ru/alkoleft/bsl/doc/bsl/helpers/ModuleComputer.java new file mode 100644 index 0000000..3c8b895 --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/bsl/helpers/ModuleComputer.java @@ -0,0 +1,60 @@ +package ru.alkoleft.bsl.doc.bsl.helpers; + +import com.github._1c_syntax.bsl.parser.BSLTokenizer; +import lombok.experimental.UtilityClass; +import org.antlr.v4.runtime.Token; +import ru.alkoleft.bsl.doc.bsl.symbols.Trees; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +@UtilityClass +public class ModuleComputer { + + public String computeModuleDescription(BSLTokenizer tokenizer) { + var token = tokenizer.getAst().getStart(); + + var isDescription = false; + List comments = null; + while (token != null && !isDescription) { + comments = Trees.getComments(tokenizer.getTokens(), token); + isDescription = !comments.isEmpty() && comments.stream().map(Token::getText).map(it -> it.substring(2)).map(String::trim).noneMatch(it -> it.contains("Copyright") || it.contains("Экспортные")); + token = comments.isEmpty() ? null : comments.get(0); + } + if (isDescription) { + var lines = comments.stream() + .map(Token::getText) + .map(it -> it.substring(2)) + .filter(it -> it.isEmpty() || !it.matches("/+")) + .collect(Collectors.toList()); + + var chars = lines.get(0).toCharArray(); + + for (int i = 1; i < lines.size(); i++) { + var line = lines.get(i); + + for (int j = 0; j < chars.length; j++) { + if (line.length() <= j || line.charAt(j) != chars[j]) { + chars = Arrays.copyOf(chars, j); + break; + } + } + if (chars.length == 0) { + break; + } + } + + if (chars.length > 0) { + char[] finalChars = chars; + return lines.stream() + .map(it -> it.substring(finalChars.length)) + .collect(Collectors.joining("\n")); + } else { + return String.join("\n", lines); + } + } else { + return ""; + } + } +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/bsl/helpers/ModuleContextBuilder.java b/src/main/java/ru/alkoleft/bsl/doc/bsl/helpers/ModuleContextBuilder.java new file mode 100644 index 0000000..a5d1be7 --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/bsl/helpers/ModuleContextBuilder.java @@ -0,0 +1,57 @@ +package ru.alkoleft.bsl.doc.bsl.helpers; + +import com.github._1c_syntax.bsl.mdo.Module; +import com.github._1c_syntax.bsl.parser.BSLTokenizer; +import lombok.extern.slf4j.Slf4j; +import ru.alkoleft.bsl.doc.bsl.ModuleInfo; +import ru.alkoleft.bsl.doc.bsl.symbols.MethodSymbol; +import ru.alkoleft.bsl.doc.bsl.symbols.MethodSymbolComputer; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.stream.Collectors; + +@Slf4j +public class ModuleContextBuilder { + public ModuleInfo buildModuleContext(Module bslModule) { + var owner = MDOHelper.getOwner(bslModule); + log.debug("Parse module: " + owner.getName() + "." + bslModule.getModuleType()); + var srcPath = Path.of(bslModule.getUri()); + List methods; + String description; + try { + var content = Files.readString(srcPath); + MethodSymbolComputer computer = new MethodSymbolComputer(); + var tokenizer = new BSLTokenizer(content); + methods = computer.compute(tokenizer); + description = ModuleComputer.computeModuleDescription(tokenizer); + } catch (Exception e) { + throw new RuntimeException(owner.getMdoReference().getMdoRef() + ". Module parsing error", e); + } + + return ModuleInfo.builder() + .owner(owner) + .module(bslModule) + .methods(methods) + .description(description) + .build(); + } + + public ModuleInfo buildFilteredModuleContext(Module bslModule) { + return buildModuleContext(buildModuleContext(bslModule)); + } + + public ModuleInfo buildModuleContext(ModuleInfo module) { + + var stream = BslFilter.setFilter(module.getMethods().stream()); + + return ModuleInfo.builder() + .module(module.getModule()) + .owner(module.getOwner()) + .description(module.getDescription()) + .methods(stream.collect(Collectors.toList())) + .build(); + } + +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/bsl/helpers/Strings.java b/src/main/java/ru/alkoleft/bsl/doc/bsl/helpers/Strings.java new file mode 100644 index 0000000..1cc7870 --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/bsl/helpers/Strings.java @@ -0,0 +1,10 @@ +package ru.alkoleft.bsl.doc.bsl.helpers; + +import lombok.experimental.UtilityClass; + +@UtilityClass +public class Strings { + public boolean isNullOrEmpty(String value) { + return value == null || value.isEmpty(); + } +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/bsl/symbols/MethodSymbol.java b/src/main/java/ru/alkoleft/bsl/doc/bsl/symbols/MethodSymbol.java index 6e033cb..09e247d 100644 --- a/src/main/java/ru/alkoleft/bsl/doc/bsl/symbols/MethodSymbol.java +++ b/src/main/java/ru/alkoleft/bsl/doc/bsl/symbols/MethodSymbol.java @@ -1,9 +1,14 @@ package ru.alkoleft.bsl.doc.bsl.symbols; -import com.github._1c_syntax.bsl.languageserver.context.symbol.description.MethodDescription; -import com.google.common.base.Strings; +import com.github._1c_syntax.bsl.parser.description.MethodDescription; +import com.github._1c_syntax.bsl.parser.description.support.SimpleRange; import lombok.Builder; +import lombok.Setter; import lombok.Value; +import lombok.experimental.NonFinal; +import lombok.extern.slf4j.Slf4j; +import ru.alkoleft.bsl.doc.bsl.BslContext; +import ru.alkoleft.bsl.doc.bsl.helpers.Strings; import java.util.Collections; import java.util.List; @@ -11,13 +16,18 @@ @Builder @Value +@Slf4j public class MethodSymbol { boolean deprecated; boolean function; boolean export; String name; Optional fullDescription; + List parameters; + SimpleRange range; + @Setter + @NonFinal RegionSymbol region; public String getDescription() { @@ -32,9 +42,57 @@ public TypeDescription getReturnedValue() { var result = fullDescription.map(MethodDescription::getReturnedValue).filter(it -> !it.isEmpty()).map(it -> it.get(0)).orElse(null); if (result != null) { - return new TypeDescription(result.getName(), result.getDescription(), result.getParameters(), Strings.isNullOrEmpty(result.getLink()) ? null : "см. " + result.getLink(), result.isHyperlink()); + return createTypeDescription(result); } else { return null; } } + + private TypeDescription createTypeDescription(com.github._1c_syntax.bsl.parser.description.support.TypeDescription baseDescription) { + TypeDescription result = null; + if (!Strings.isNullOrEmpty(baseDescription.getLink())) { + var methodInfo = BslContext.getCurrent().getMethodInfo(baseDescription.getLink()); + + if (methodInfo != null && methodInfo.getMethod() != null) { + result = methodInfo.getMethod().getReturnedValue(); + } else { + log.warn("Bad link: " + baseDescription.getLink()); + } + } + if (result == null) { + result = new TypeDescription(baseDescription.getName(), baseDescription.getDescription(), baseDescription.getParameters(), Strings.isNullOrEmpty(baseDescription.getLink()) ? null : "см. " + baseDescription.getLink(), baseDescription.isHyperlink()); + } + return result; + } + + public String callExample() { + var builder = new StringBuilder(); + if (function) { + builder.append("Функция"); + } else { + builder.append("Процедура"); + } + builder.append(" ").append(name).append("("); + boolean firstParameter = true; + for (var parameter : parameters) { + if (firstParameter) { + firstParameter = false; + } else { + builder.append(", "); + } + if (parameter.isByValue()) { + builder.append("Знач "); + } + builder.append(parameter.getName()); + if (parameter.getDefaultValue().getType() != ParameterDefinition.ParameterType.EMPTY) { + builder.append(" = ").append(parameter.getDefaultValue().getValue()); + } + } + builder.append(")"); + if (isExport()) { + builder.append(" Экспорт"); + } + + return builder.toString(); + } } diff --git a/src/main/java/ru/alkoleft/bsl/doc/bsl/symbols/MethodSymbolComputer.java b/src/main/java/ru/alkoleft/bsl/doc/bsl/symbols/MethodSymbolComputer.java index e9e14ee..ad961e3 100644 --- a/src/main/java/ru/alkoleft/bsl/doc/bsl/symbols/MethodSymbolComputer.java +++ b/src/main/java/ru/alkoleft/bsl/doc/bsl/symbols/MethodSymbolComputer.java @@ -1,15 +1,15 @@ package ru.alkoleft.bsl.doc.bsl.symbols; -import com.github._1c_syntax.bsl.languageserver.context.symbol.description.MethodDescription; -import com.github._1c_syntax.bsl.languageserver.utils.Ranges; -import com.github._1c_syntax.bsl.languageserver.utils.Trees; +import com.github._1c_syntax.bsl.parser.description.BSLDescriptionReader; +import com.github._1c_syntax.bsl.parser.description.MethodDescription; +import com.github._1c_syntax.bsl.parser.description.support.SimpleRange; import com.github._1c_syntax.bsl.parser.BSLParser; import com.github._1c_syntax.bsl.parser.BSLParserBaseVisitor; import com.github._1c_syntax.bsl.parser.BSLTokenizer; +import lombok.extern.slf4j.Slf4j; import org.antlr.v4.runtime.Token; import org.antlr.v4.runtime.tree.ParseTree; import org.antlr.v4.runtime.tree.TerminalNode; -import org.eclipse.lsp4j.Range; import java.util.ArrayList; import java.util.Collection; @@ -19,16 +19,27 @@ import java.util.Stack; import java.util.stream.Collectors; +@Slf4j public class MethodSymbolComputer extends BSLParserBaseVisitor { private final List methods = new ArrayList<>(); private BSLTokenizer tokenizer; - Stack regions = new Stack<>(); + List regionData = new ArrayList<>(); + Stack regions = new Stack<>(); public List compute(BSLTokenizer tokenizer) { this.tokenizer = tokenizer; methods.clear(); visitFile(tokenizer.getAst()); + + // Используется постпривязка регионов, тк порядок обхода не соответствует порядку следования объект (в метод заходит раньше региона) + for (var region : regionData) { + for (var method : methods) { + if (SimpleRange.containsRange(region.range, method.getRange())) { + method.setRegion(region.region); + } + } + } return methods; } @@ -36,35 +47,44 @@ public List compute(BSLTokenizer tokenizer) { public ParseTree visitRegionStart(BSLParser.RegionStartContext ctx) { var name = ctx.regionName().getText(); - RegionSymbol region; + log.debug("Start region: " + name); + var data = new RegionData(); + data.start = ctx; if (regions.isEmpty()) { - region = new RegionSymbol(name, null); + data.region = new RegionSymbol(name, null); } else { - region = new RegionSymbol(name, regions.peek()); + data.region = new RegionSymbol(name, regions.peek().region); } - regions.push(region); + regions.push(data); + regionData.add(data); return super.visitRegionStart(ctx); } @Override public ParseTree visitRegionEnd(BSLParser.RegionEndContext ctx) { - regions.pop(); + if (!regions.isEmpty()) { + var regionData = regions.pop(); + log.debug("End region: " + regionData.region.getName()); + regionData.end = ctx; + regionData.range = SimpleRange.create(regionData.start.start, regionData.end.stop); + } return super.visitRegionEnd(ctx); } @Override public ParseTree visitFunction(BSLParser.FunctionContext ctx) { - BSLParser.FuncDeclarationContext declaration = ctx.funcDeclaration(); - - TerminalNode startNode = declaration.FUNCTION_KEYWORD(); + var declaration = ctx.funcDeclaration(); + log.debug("Function: " + declaration.subName().getText()); + var startNode = declaration.FUNCTION_KEYWORD(); handleMethod(startNode, declaration.subName().getStart(), declaration.paramList(), true, declaration.EXPORT_KEYWORD() != null); return super.visitFunction(ctx); } @Override public ParseTree visitProcedure(BSLParser.ProcedureContext ctx) { - BSLParser.ProcDeclarationContext declaration = ctx.procDeclaration(); + var declaration = ctx.procDeclaration(); + log.debug("Procedure: " + declaration.subName().getText()); TerminalNode startNode = declaration.PROCEDURE_KEYWORD(); handleMethod(startNode, declaration.subName().getStart(), declaration.paramList(), false, declaration.EXPORT_KEYWORD() != null); @@ -72,8 +92,8 @@ public ParseTree visitProcedure(BSLParser.ProcedureContext ctx) { } private void handleMethod(TerminalNode startNode, Token subName, BSLParser.ParamListContext paramList, boolean function, boolean export) { - Optional description = createDescription(startNode.getSymbol()); - boolean deprecated = description + var description = createDescription(startNode.getSymbol()); + var deprecated = description .map(MethodDescription::isDeprecated) .orElse(false); @@ -84,7 +104,7 @@ private void handleMethod(TerminalNode startNode, Token subName, BSLParser.Param .fullDescription(description) .deprecated(deprecated) .parameters(createParameters(paramList, description)) - .region(regions.peek()) + .range(SimpleRange.create(startNode.getSymbol(), startNode.getSymbol())) .build(); methods.add(method); } @@ -175,6 +195,13 @@ private Optional createDescription(Token token) { return Optional.empty(); } - return Optional.of(new MethodDescription(comments)); + return Optional.of(BSLDescriptionReader.parseMethodDescription(comments)); + } + + private static class RegionData { + RegionSymbol region; + BSLParser.RegionStartContext start; + BSLParser.RegionEndContext end; + SimpleRange range; } } diff --git a/src/main/java/ru/alkoleft/bsl/doc/bsl/symbols/ParameterDefinition.java b/src/main/java/ru/alkoleft/bsl/doc/bsl/symbols/ParameterDefinition.java index 61fe89d..8657414 100644 --- a/src/main/java/ru/alkoleft/bsl/doc/bsl/symbols/ParameterDefinition.java +++ b/src/main/java/ru/alkoleft/bsl/doc/bsl/symbols/ParameterDefinition.java @@ -1,6 +1,6 @@ package ru.alkoleft.bsl.doc.bsl.symbols; -import com.github._1c_syntax.bsl.languageserver.context.symbol.description.TypeDescription; +import com.github._1c_syntax.bsl.parser.description.support.TypeDescription; import lombok.Builder; import lombok.Value; @@ -18,13 +18,10 @@ public class ParameterDefinition { boolean byValue; public String getDescription() { - if (description.isEmpty()) { - return ""; - } - return description.get().getTypes() + return description.map(parameterDescription -> parameterDescription.getTypes() .stream() .findFirst() - .map(TypeDescription::getDescription).orElse(""); + .map(TypeDescription::getDescription).orElse("")).orElse(""); } public List getTypes() { @@ -35,6 +32,10 @@ public List getTypes() { } } + public boolean isRequired() { + return defaultValue.type == ParameterType.EMPTY; + } + public enum ParameterType { DATETIME, BOOLEAN, diff --git a/src/main/java/ru/alkoleft/bsl/doc/bsl/symbols/ParameterDescription.java b/src/main/java/ru/alkoleft/bsl/doc/bsl/symbols/ParameterDescription.java index 85c7e57..81423e8 100644 --- a/src/main/java/ru/alkoleft/bsl/doc/bsl/symbols/ParameterDescription.java +++ b/src/main/java/ru/alkoleft/bsl/doc/bsl/symbols/ParameterDescription.java @@ -1,6 +1,6 @@ package ru.alkoleft.bsl.doc.bsl.symbols; -import com.github._1c_syntax.bsl.languageserver.context.symbol.description.TypeDescription; +import com.github._1c_syntax.bsl.parser.description.support.TypeDescription; import lombok.AllArgsConstructor; import lombok.Value; diff --git a/src/main/java/ru/alkoleft/bsl/doc/bsl/symbols/RegionSymbol.java b/src/main/java/ru/alkoleft/bsl/doc/bsl/symbols/RegionSymbol.java index a00668c..c29d700 100644 --- a/src/main/java/ru/alkoleft/bsl/doc/bsl/symbols/RegionSymbol.java +++ b/src/main/java/ru/alkoleft/bsl/doc/bsl/symbols/RegionSymbol.java @@ -13,4 +13,5 @@ public class RegionSymbol { String name; RegionSymbol parent; + } diff --git a/src/main/java/ru/alkoleft/bsl/doc/bsl/symbols/Trees.java b/src/main/java/ru/alkoleft/bsl/doc/bsl/symbols/Trees.java new file mode 100644 index 0000000..dbebb2b --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/bsl/symbols/Trees.java @@ -0,0 +1,100 @@ +/* + * This file is a part of BSL Language Server. + * + * Copyright (c) 2018-2023 + * Alexey Sosnoviy , Nikita Fedkin and contributors + * + * SPDX-License-Identifier: LGPL-3.0-or-later + * + * BSL Language Server is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * BSL Language Server is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with BSL Language Server. + */ + +// from https://github.com/1c-syntax/bsl-language-server/blob/develop/src/main/java/com/github/_1c_syntax/bsl/languageserver/utils/Trees.java + +package ru.alkoleft.bsl.doc.bsl.symbols; + +import com.github._1c_syntax.bsl.parser.BSLParser; +import lombok.experimental.UtilityClass; +import org.antlr.v4.runtime.Token; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +@UtilityClass +public class Trees { + private static final Set VALID_TOKEN_TYPES_FOR_COMMENTS_SEARCH = Set.of( + BSLParser.ANNOTATION_ATCLIENT_SYMBOL, + BSLParser.ANNOTATION_ATSERVERNOCONTEXT_SYMBOL, + BSLParser.ANNOTATION_ATCLIENTATSERVERNOCONTEXT_SYMBOL, + BSLParser.ANNOTATION_ATCLIENTATSERVER_SYMBOL, + BSLParser.ANNOTATION_ATSERVER_SYMBOL, + BSLParser.ANNOTATION_CUSTOM_SYMBOL, + BSLParser.ANNOTATION_UNKNOWN, + BSLParser.LINE_COMMENT, + BSLParser.WHITE_SPACE, + BSLParser.AMPERSAND + ); + + /** + * Поиск комментариев назад от указанного токена + * + * @param tokens - список токенов DocumentContext + * @param token - токен, для которого требуется найти комментарии + * @return - список найденных комментариев lines + */ + public static List getComments(List tokens, Token token) { + List comments = new ArrayList<>(); + fillCommentsCollection(tokens, token, comments); + return comments.stream() + .filter(it -> { + var text = it.getText(); + return !text.startsWith("// @skip") && !text.startsWith("// BSLLS:"); + }) + .collect(Collectors.toList()); + } + + private static void fillCommentsCollection(List tokens, Token currentToken, List lines) { + + int index = currentToken.getTokenIndex(); + + if (index == 0) { + return; + } + + var previousToken = tokens.get(index - 1); + + if (abortSearchComments(previousToken, currentToken)) { + return; + } + + fillCommentsCollection(tokens, previousToken, lines); + int type = previousToken.getType(); + if (type == BSLParser.LINE_COMMENT) { + lines.add(previousToken); + } + } + + private static boolean abortSearchComments(Token previousToken, Token currentToken) { + int type = previousToken.getType(); + return !VALID_TOKEN_TYPES_FOR_COMMENTS_SEARCH.contains(type) || isBlankLine(previousToken, currentToken); + } + + private static boolean isBlankLine(Token previousToken, Token currentToken) { + return previousToken.getType() == BSLParser.WHITE_SPACE + && (previousToken.getTokenIndex() == 0 + || (previousToken.getLine() + 1) != currentToken.getLine()); + } +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/bsl/symbols/TypeDescription.java b/src/main/java/ru/alkoleft/bsl/doc/bsl/symbols/TypeDescription.java index f55df7c..91a6ac5 100644 --- a/src/main/java/ru/alkoleft/bsl/doc/bsl/symbols/TypeDescription.java +++ b/src/main/java/ru/alkoleft/bsl/doc/bsl/symbols/TypeDescription.java @@ -1,6 +1,6 @@ package ru.alkoleft.bsl.doc.bsl.symbols; -import com.github._1c_syntax.bsl.languageserver.context.symbol.description.ParameterDescription; +import com.github._1c_syntax.bsl.parser.description.support.ParameterDescription; import lombok.AllArgsConstructor; import lombok.Value; diff --git a/src/main/java/ru/alkoleft/bsl/doc/commands/RenderCommand.java b/src/main/java/ru/alkoleft/bsl/doc/commands/RenderCommand.java index 84d8b0f..5c11b8e 100644 --- a/src/main/java/ru/alkoleft/bsl/doc/commands/RenderCommand.java +++ b/src/main/java/ru/alkoleft/bsl/doc/commands/RenderCommand.java @@ -1,56 +1,82 @@ package ru.alkoleft.bsl.doc.commands; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.NoArgsConstructor; import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; import picocli.CommandLine.Command; import picocli.CommandLine.Option; import picocli.CommandLine.Parameters; -import ru.alkoleft.bsl.doc.render.Render; -import ru.alkoleft.bsl.doc.bsl.BslContext; +import ru.alkoleft.bsl.doc.AutodocManager; import ru.alkoleft.bsl.doc.bsl.Filter; import ru.alkoleft.bsl.doc.bsl.symbols.RegionSymbol; -import ru.alkoleft.bsl.doc.render.Factory; -import ru.alkoleft.bsl.doc.render.OutputFormat; -import ru.alkoleft.bsl.doc.render.RenderOptions; +import ru.alkoleft.bsl.doc.options.ChildLayout; +import ru.alkoleft.bsl.doc.options.ManualMergeStrategy; +import ru.alkoleft.bsl.doc.options.OutputFormat; +import ru.alkoleft.bsl.doc.options.OutputOptions; -import java.nio.file.Files; import java.nio.file.Path; import java.util.List; +@Slf4j @Command(helpCommand = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor public class RenderCommand implements Runnable { @Parameters(description = "source") - Path sources; + private Path sources; @Parameters(description = "destination") - Path destination; - + private Path destination; @Option(names = {"-f", "--format"}, defaultValue = "Markdown") - OutputFormat format; + private OutputFormat format; @Option(names = {"-s", "--only-subsystems"}) - List onlySubsystems; - + private List onlySubsystems; @Option(names = {"-r", "--regions"}, split = " ", defaultValue = RegionSymbol.PUBLIC_REGION_RU + " " + RegionSymbol.PUBLIC_REGION_EN) - List regions; + private List regions; + @Option(names = {"-m", "--manual-docs"}, description = "Path to manual documentations") + private Path manualDocumentation; + @Option(names = {"-ms", "--merge-strategy"}, description = "Merge strategy for manual and generated documentation", defaultValue = "NONE") + private ManualMergeStrategy manualMergeStrategy; + @Option(names = {"-cl", "--child-layout"}, description = "Child pages layout", defaultValue = "SAME_DIRECTORY") + private ChildLayout childLayout; @SneakyThrows @Override public void run() { - var filter = Filter.builder() + var filterBuilder = Filter.builder() .isExport(true); - regions.forEach(filter::region); + regions.forEach(filterBuilder::region); + onlySubsystems.forEach(filterBuilder::rootSubsystem); - var options = RenderOptions.builder() + var optionsBuilder = OutputOptions.builder() .outputFormat(format) - .subsystemHierarchy(true); - onlySubsystems.forEach(options::rootSubsystem); + .subsystemHierarchy(true) + .childLayout(childLayout); + + var filter = filterBuilder.build(); + var options = optionsBuilder.build(); - var renderContext = Factory.createRenderContext(options.build()); - var render = new Render(renderContext); + log.debug("Filter: " + filter.toString()); + log.debug("Options: " + options.toString()); + log.debug("Sources: " + sources); + log.debug("Manual: " + manualDocumentation); + log.debug("Output: " + destination); + log.debug("Merge manual: " + manualMergeStrategy); - BslContext bslContext = new BslContext(sources, filter.build()); - bslContext.load(); + var manager = AutodocManager.builder() + .filter(filter) + .outputOptions(options) + .manualDocumentation(manualDocumentation) + .manualMergeStrategy(manualMergeStrategy) + .destination(destination) + .sources(sources) + .build(); - Files.createDirectories(destination); - render.render(bslContext, destination); + manager.loadData(); + manager.clearOutput(); + manager.generateDocumentation(); } } diff --git a/src/main/java/ru/alkoleft/bsl/doc/content/processor/MarkdownTitleProcessor.java b/src/main/java/ru/alkoleft/bsl/doc/content/processor/MarkdownTitleProcessor.java new file mode 100644 index 0000000..b4ae405 --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/content/processor/MarkdownTitleProcessor.java @@ -0,0 +1,33 @@ +package ru.alkoleft.bsl.doc.content.processor; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.stream.Collectors; + +public class MarkdownTitleProcessor implements TitleProcessor { + @Override + public String cleanTitle(String content) { + return content.lines() + .filter(it -> !it.startsWith("# ")) + .collect(Collectors.joining("\n")); + } + + @Override + public String getTitle(String content) { + return null; + } + + @Override + public String getTitle(Path path) { + try (var lines = Files.lines(path)) { + return lines + .filter(it -> it.startsWith("# ")) + .findFirst() + .map(it -> it.substring(2).trim()).orElse(null); + } catch (IOException e) { + // nothing + } + return ""; + } +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/content/processor/TitleProcessor.java b/src/main/java/ru/alkoleft/bsl/doc/content/processor/TitleProcessor.java new file mode 100644 index 0000000..0d16aff --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/content/processor/TitleProcessor.java @@ -0,0 +1,27 @@ +package ru.alkoleft.bsl.doc.content.processor; + +import lombok.experimental.UtilityClass; +import ru.alkoleft.bsl.doc.options.OutputFormat; + +import java.nio.file.Path; + +public interface TitleProcessor { + static TitleProcessor getInstance() { + return Factory.instance; + } + + String cleanTitle(String content); + + String getTitle(String content); + + String getTitle(Path path); + + @UtilityClass + class Factory { + TitleProcessor instance; + + public TitleProcessor create(OutputFormat format) { + return instance = new MarkdownTitleProcessor(); + } + } +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/indexer/FileIndexer.java b/src/main/java/ru/alkoleft/bsl/doc/indexer/FileIndexer.java new file mode 100644 index 0000000..50f27a3 --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/indexer/FileIndexer.java @@ -0,0 +1,26 @@ +package ru.alkoleft.bsl.doc.indexer; + +import lombok.AllArgsConstructor; +import lombok.SneakyThrows; +import org.apache.commons.io.FilenameUtils; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.stream.Stream; + +@AllArgsConstructor +public class FileIndexer { + private final String fileExtension; + + @SneakyThrows + public Stream pagePaths(Path rootPath) { + return Files.walk(rootPath) + .filter(path -> path.toFile().isFile()) + .filter(this::matchFileExtension); + + } + + protected boolean matchFileExtension(Path path) { + return FilenameUtils.getExtension(path.toString()).equals(fileExtension); + } +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/manual/ManualContent.java b/src/main/java/ru/alkoleft/bsl/doc/manual/ManualContent.java new file mode 100644 index 0000000..4919849 --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/manual/ManualContent.java @@ -0,0 +1,65 @@ +package ru.alkoleft.bsl.doc.manual; + +import lombok.SneakyThrows; +import org.apache.commons.io.FileUtils; +import ru.alkoleft.bsl.doc.model.ContentModel; +import ru.alkoleft.bsl.doc.model.ContentModelBuilder; +import ru.alkoleft.bsl.doc.model.Page; +import ru.alkoleft.bsl.doc.options.OutputFormat; + +import java.nio.file.Path; + +public class ManualContent { + private final Path location; + private final Path destination; + private ContentModel localModel; + private ContentModel destinationModel; + + public ManualContent(Path location, Path destination) { + this.location = location; + this.destination = destination; + } + + public void buildModel(OutputFormat format) { + if (location == null) { + return; + } + localModel = ContentModelBuilder.build(location, format); + destinationModel = null; + } + + public void copy() { + if (location == null) { + return; + } + copyFolder(location, destination); + destinationModel = new ContentModel(); + localModel.getPages().stream() + .map(it -> createDestinationPage(it, location, destination)) + .forEach(destinationModel.getPages()::add); + } + + public boolean isNotContains(Path path) { + if (destinationModel == null) { + return true; + } + return destinationModel.getPages() + .stream() + .map(Page::getPath) + .noneMatch(it -> it.equals(path)); + } + + public ContentModel getContentModel() { + return destinationModel; + } + + private Page createDestinationPage(Page localPage, Path local, Path dest) { + var destPath = dest.resolve(local.relativize(localPage.getPath())); + return new Page(destPath, localPage.getTitle(), localPage.getType()); + } + + @SneakyThrows + private void copyFolder(Path src, Path dest) { + FileUtils.copyDirectory(src.toFile(), dest.toFile()); + } +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/model/ContentModel.java b/src/main/java/ru/alkoleft/bsl/doc/model/ContentModel.java new file mode 100644 index 0000000..708f976 --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/model/ContentModel.java @@ -0,0 +1,42 @@ +package ru.alkoleft.bsl.doc.model; + +import lombok.Value; + +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + +@Value +public class ContentModel { + List pages = new ArrayList<>(); + + public Page append(Path path) { + var page = pages.stream() + .filter(it -> path.equals(it.getPath())) + .findAny() + .orElse(null); + + if (page == null) { + pages.add(page = new Page(path, null, PageType.UNKNOWN)); + } + return page; + } + + public List getChildrenPages(Path path) { + return pages.stream() + .filter(it -> isChild(it, path)) + .sorted(Comparator.comparing(Page::getPath)) + .collect(Collectors.toList()); + } + + boolean isChild(Page page, Path path) { + var pagePath = page.getPath(); + if (pagePath.getFileName().toString().startsWith("index.")) { + return pagePath.getParent().getParent().equals(path); + } else { + return pagePath.getParent().equals(path); + } + } +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/model/ContentModelBuilder.java b/src/main/java/ru/alkoleft/bsl/doc/model/ContentModelBuilder.java new file mode 100644 index 0000000..ab490cc --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/model/ContentModelBuilder.java @@ -0,0 +1,23 @@ +package ru.alkoleft.bsl.doc.model; + +import lombok.experimental.UtilityClass; +import ru.alkoleft.bsl.doc.content.processor.TitleProcessor; +import ru.alkoleft.bsl.doc.indexer.FileIndexer; +import ru.alkoleft.bsl.doc.options.OutputFormat; + +import java.nio.file.Path; + +@UtilityClass +public class ContentModelBuilder { + public ContentModel build(Path location, OutputFormat format) { + var model = new ContentModel(); + + try (var files = new FileIndexer(format.getExtension()).pagePaths(location)) { + files.map(it -> new Page(it, it.getFileName().getName(0).toString(), PageType.MANUAL)) + .peek(it -> it.setTitle(TitleProcessor.getInstance().getTitle(it.getPath()))) + .forEach(model.getPages()::add); + } + + return model; + } +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/model/Links.java b/src/main/java/ru/alkoleft/bsl/doc/model/Links.java new file mode 100644 index 0000000..c2b0db6 --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/model/Links.java @@ -0,0 +1,20 @@ +package ru.alkoleft.bsl.doc.model; + +import lombok.Setter; +import lombok.experimental.UtilityClass; + +import java.nio.file.Path; + +@UtilityClass +public class Links { + @Setter + private Path currentPath; + + public String getPageLink(Page from, Page to) { + return from.getPath().relativize(to.getPath()).toString(); + } + + public String getPageLink(Page to) { + return currentPath.getParent().relativize(to.getPath()).toString(); + } +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/model/Page.java b/src/main/java/ru/alkoleft/bsl/doc/model/Page.java new file mode 100644 index 0000000..b0cd1a2 --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/model/Page.java @@ -0,0 +1,25 @@ +package ru.alkoleft.bsl.doc.model; + +import lombok.AllArgsConstructor; +import lombok.Data; +import ru.alkoleft.bsl.doc.content.processor.TitleProcessor; + +import java.nio.file.Path; + +@Data +@AllArgsConstructor +public class Page { + private Path path; + private String title; + private PageType type; + + public String getTitle() { + if (title != null) { + return title; + } else if (path == null) { + return null; + } + + return title = TitleProcessor.getInstance().getTitle(path); + } +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/model/PageType.java b/src/main/java/ru/alkoleft/bsl/doc/model/PageType.java new file mode 100644 index 0000000..0e55542 --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/model/PageType.java @@ -0,0 +1,8 @@ +package ru.alkoleft.bsl.doc.model; + +public enum PageType { + UNKNOWN, + SUBSYSTEM, + MODULE, + MANUAL +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/options/ChildLayout.java b/src/main/java/ru/alkoleft/bsl/doc/options/ChildLayout.java new file mode 100644 index 0000000..f9ec591 --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/options/ChildLayout.java @@ -0,0 +1,6 @@ +package ru.alkoleft.bsl.doc.options; + +public enum ChildLayout { + SUB_DIRECTORY, + SAME_DIRECTORY +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/options/ManualMergeStrategy.java b/src/main/java/ru/alkoleft/bsl/doc/options/ManualMergeStrategy.java new file mode 100644 index 0000000..9d17a64 --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/options/ManualMergeStrategy.java @@ -0,0 +1,8 @@ +package ru.alkoleft.bsl.doc.options; + +public enum ManualMergeStrategy { + NONE, + REPLACE, + APPEND, + MERGE +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/options/OutputFormat.java b/src/main/java/ru/alkoleft/bsl/doc/options/OutputFormat.java new file mode 100644 index 0000000..124baaa --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/options/OutputFormat.java @@ -0,0 +1,16 @@ +package ru.alkoleft.bsl.doc.options; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum OutputFormat { + Docusaurus("docusaurus", "md"), + Markdown("md", "md"), + ConfluenceMarkdown("confluence-md", "md"); + + private final String path; + private final String extension; + +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/options/OutputOptions.java b/src/main/java/ru/alkoleft/bsl/doc/options/OutputOptions.java new file mode 100644 index 0000000..9e29617 --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/options/OutputOptions.java @@ -0,0 +1,15 @@ +package ru.alkoleft.bsl.doc.options; + +import lombok.Builder; +import lombok.Value; + +import java.nio.file.Path; + +@Builder +@Value +public class OutputOptions { + OutputFormat outputFormat; + boolean subsystemHierarchy; + Path destination; + ChildLayout childLayout; +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/render/BaseRender.java b/src/main/java/ru/alkoleft/bsl/doc/render/BaseRender.java new file mode 100644 index 0000000..04e2c81 --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/render/BaseRender.java @@ -0,0 +1,26 @@ +package ru.alkoleft.bsl.doc.render; + +import com.github.jknack.handlebars.Context; +import lombok.Getter; +import lombok.experimental.UtilityClass; +import ru.alkoleft.bsl.doc.render.handlebars.RenderContext; + +import java.nio.file.Path; + +@UtilityClass +public class BaseRender { + @Getter + RenderContext renderContext; + + public void setContext(RenderContext renderContext) { + BaseRender.renderContext = renderContext; + } + + public void renderToFile(String templateName, Context context, Path output) { + renderContext.renderToFile(templateName, context, output); + } + + public String render(String templateName, Context context) { + return renderContext.render(templateName, context); + } +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/render/BslRender.java b/src/main/java/ru/alkoleft/bsl/doc/render/BslRender.java new file mode 100644 index 0000000..3d055d5 --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/render/BslRender.java @@ -0,0 +1,31 @@ +package ru.alkoleft.bsl.doc.render; + +import lombok.SneakyThrows; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import ru.alkoleft.bsl.doc.bsl.ModuleInfo; +import ru.alkoleft.bsl.doc.render.contexts.ContextFactory; +import ru.alkoleft.bsl.doc.render.contexts.ModuleContext; +import ru.alkoleft.bsl.doc.render.contexts.SubsystemContext; + +@Slf4j +@UtilityClass +public class BslRender { + + @SneakyThrows + public String renderModule(ModuleInfo module, int index) { + return renderModule(ContextFactory.create(module, index)); + } + + @SneakyThrows + public String renderModule(ModuleContext module) { + log.debug("Render module '{}'", module.getName()); + return BaseRender.render("module", ContextFactory.createContext(module)); + } + + @SneakyThrows + public String renderSubsystem(SubsystemContext subsystem) { + log.debug("Render subsystem '{}'", subsystem.getName()); + return BaseRender.render("subsystem", ContextFactory.createContext(subsystem)); + } +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/render/Factory.java b/src/main/java/ru/alkoleft/bsl/doc/render/Factory.java deleted file mode 100644 index 3bf7b1c..0000000 --- a/src/main/java/ru/alkoleft/bsl/doc/render/Factory.java +++ /dev/null @@ -1,20 +0,0 @@ -package ru.alkoleft.bsl.doc.render; - -import lombok.experimental.UtilityClass; -import ru.alkoleft.bsl.doc.render.handlebars.HandlebarsRenderContext; -import ru.alkoleft.bsl.doc.render.velocity.VelocityRenderContext; - -@UtilityClass -public class Factory { - public Render createRender(RenderOptions options) { - return new Render(null); - } - - public RenderContext createRenderContext(RenderOptions options) { - return new HandlebarsRenderContext(options.getOutputFormat().getPath()); - } - - public RenderContext createVelocityRenderContext(RenderOptions options) { - return new VelocityRenderContext(options.getOutputFormat().getPath()); - } -} diff --git a/src/main/java/ru/alkoleft/bsl/doc/render/ItemRender.java b/src/main/java/ru/alkoleft/bsl/doc/render/ItemRender.java deleted file mode 100644 index 8c0ddde..0000000 --- a/src/main/java/ru/alkoleft/bsl/doc/render/ItemRender.java +++ /dev/null @@ -1,10 +0,0 @@ -package ru.alkoleft.bsl.doc.render; - -import java.io.IOException; -import java.nio.file.Path; - -public interface ItemRender { - void put(String key, Object value); - - void renderToFile(Path fileName) throws IOException; -} diff --git a/src/main/java/ru/alkoleft/bsl/doc/render/OutputFormat.java b/src/main/java/ru/alkoleft/bsl/doc/render/OutputFormat.java deleted file mode 100644 index 0b5fd20..0000000 --- a/src/main/java/ru/alkoleft/bsl/doc/render/OutputFormat.java +++ /dev/null @@ -1,15 +0,0 @@ -package ru.alkoleft.bsl.doc.render; - -import lombok.Getter; - -public enum OutputFormat { - Docusaurus("docusaurus"), - Markdown("md"); - - @Getter - private final String path; - - OutputFormat(String path) { - this.path = path; - } -} diff --git a/src/main/java/ru/alkoleft/bsl/doc/render/PathResolver.java b/src/main/java/ru/alkoleft/bsl/doc/render/PathResolver.java new file mode 100644 index 0000000..d5dc9cf --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/render/PathResolver.java @@ -0,0 +1,43 @@ +package ru.alkoleft.bsl.doc.render; + +import lombok.AllArgsConstructor; +import ru.alkoleft.bsl.doc.options.OutputFormat; +import com.github._1c_syntax.utils.Lazy; +import java.nio.file.Path; +import java.util.Stack; + +@AllArgsConstructor +public class PathResolver { + + private final Path destination; + private final OutputFormat format; + private final Stack paths = new Stack<>(); + private final Lazy currentPath = new Lazy<>(this::computeCurrentPath); + + public void entrance(String path) { + paths.push(path); + currentPath.clear(); + } + + public void exit() { + paths.pop(); + currentPath.clear(); + } + + public Path getCurrentPath() { + return currentPath.getOrCompute(); + } + + public Path getFilePath(String name) { + return getCurrentPath().resolve(name + "." + format.getExtension()); + } + + private Path computeCurrentPath() { + Path result = destination; + var iterator = paths.elements().asIterator(); + while (iterator.hasNext()) { + result = result.resolve(iterator.next()); + } + return result; + } +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/render/Render.java b/src/main/java/ru/alkoleft/bsl/doc/render/Render.java deleted file mode 100644 index 94b6a44..0000000 --- a/src/main/java/ru/alkoleft/bsl/doc/render/Render.java +++ /dev/null @@ -1,46 +0,0 @@ -package ru.alkoleft.bsl.doc.render; - -import com.github._1c_syntax.mdclasses.mdo.AbstractMDObjectBSL; -import lombok.SneakyThrows; -import ru.alkoleft.bsl.doc.bsl.BslContext; -import ru.alkoleft.bsl.doc.bsl.ModuleContext; -import ru.alkoleft.bsl.doc.render.RenderContext; - -import java.nio.file.Path; -import java.util.concurrent.atomic.AtomicInteger; - -public class Render { - - RenderContext renderContext; - - public Render(RenderContext renderContext) { - this.renderContext = renderContext; - } - - public void render(BslContext bslContext, Path output) { - AtomicInteger index = new AtomicInteger(); - - renderContext.setContext(bslContext); - bslContext.getModules().forEach(it -> renderModule(it, output, index.getAndIncrement())); - } - - @SneakyThrows - public void renderModule(ModuleContext module, Path outputPath, int index) { - var itemRender = renderContext.getRender("module"); - - itemRender.put("index", index); - itemRender.put("name", module.getOwner().getName()); - itemRender.put("present", getPresent(module.getOwner())); - itemRender.put("methods", module.getMethods()); - itemRender.put("description", module.getDescription()); - itemRender.renderToFile(outputPath.resolve(module.getOwner().getName() + ".md")); - } - - private String getPresent(AbstractMDObjectBSL object) { - if (object.getSynonyms().isEmpty()) { - return object.getName(); - } else { - return object.getSynonyms().get(0).getContent(); - } - } -} diff --git a/src/main/java/ru/alkoleft/bsl/doc/render/RenderContext.java b/src/main/java/ru/alkoleft/bsl/doc/render/RenderContext.java deleted file mode 100644 index 81fe585..0000000 --- a/src/main/java/ru/alkoleft/bsl/doc/render/RenderContext.java +++ /dev/null @@ -1,11 +0,0 @@ -package ru.alkoleft.bsl.doc.render; - -import ru.alkoleft.bsl.doc.bsl.BslContext; - -import java.io.IOException; - -public interface RenderContext { - ItemRender getRender(String name) throws IOException; - - void setContext(BslContext context); -} diff --git a/src/main/java/ru/alkoleft/bsl/doc/render/RenderOptions.java b/src/main/java/ru/alkoleft/bsl/doc/render/RenderOptions.java deleted file mode 100644 index 20f9758..0000000 --- a/src/main/java/ru/alkoleft/bsl/doc/render/RenderOptions.java +++ /dev/null @@ -1,17 +0,0 @@ -package ru.alkoleft.bsl.doc.render; - -import lombok.Builder; -import lombok.Singular; -import lombok.Value; - -import java.util.List; - -@Builder -@Value -public class RenderOptions { - OutputFormat outputFormat; - - boolean subsystemHierarchy; - @Singular - List rootSubsystems; -} diff --git a/src/main/java/ru/alkoleft/bsl/doc/render/StructureRender.java b/src/main/java/ru/alkoleft/bsl/doc/render/StructureRender.java new file mode 100644 index 0000000..be25bec --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/render/StructureRender.java @@ -0,0 +1,113 @@ +package ru.alkoleft.bsl.doc.render; + +import lombok.SneakyThrows; +import ru.alkoleft.bsl.doc.bsl.BslContext; +import ru.alkoleft.bsl.doc.bsl.helpers.MDOHelper; +import ru.alkoleft.bsl.doc.model.ContentModel; +import ru.alkoleft.bsl.doc.model.Links; +import ru.alkoleft.bsl.doc.model.PageType; +import ru.alkoleft.bsl.doc.options.ChildLayout; +import ru.alkoleft.bsl.doc.options.OutputOptions; +import ru.alkoleft.bsl.doc.render.contexts.ContextFactory; +import ru.alkoleft.bsl.doc.render.output.OutputStrategy; +import ru.alkoleft.bsl.doc.structure.Item; +import ru.alkoleft.bsl.doc.structure.MDObjectItem; +import ru.alkoleft.bsl.doc.structure.ModuleItem; +import ru.alkoleft.bsl.doc.structure.StructureVisitor; +import ru.alkoleft.bsl.doc.structure.SubsystemItem; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; + +public class StructureRender implements StructureVisitor { + private final OutputStrategy outputStrategy; + private final ContentModel contentModel; + private boolean withRoot = false; + private int subsystemLevel = 0; + private PathResolver pathResolver; + private final OutputOptions outputOptions; + + public StructureRender(OutputOptions outputOptions, OutputStrategy outputStrategy, ContentModel contentModel) { + this.outputStrategy = outputStrategy; + this.contentModel = contentModel; + this.outputOptions = outputOptions; + } + + public void render(List structure, Path destination) { + pathResolver = new PathResolver(destination, outputStrategy.getFormat()); + subsystemLevel = 0; + withRoot = outputOptions.getChildLayout() == ChildLayout.SUB_DIRECTORY || structure.size() > 1; + + for (int i = 0; i < structure.size(); i++) { + structure.get(i).accept(this, i); + } + } + + @Override + public void visit(SubsystemItem item, int index) { + var isRoot = subsystemLevel == 0; + subsystemLevel++; + if (!withRoot && isRoot) { + item.accentChildren(this); + renderSubsystemPage(item); + } else { + pathResolver.entrance(item.getName()); + item.accentChildren(this); + if (outputOptions.getChildLayout() == ChildLayout.SAME_DIRECTORY) { + renderSubsystemPage(item); + pathResolver.exit(); + } else { + pathResolver.exit(); + renderSubsystemPage(item); + } + } + subsystemLevel--; + } + + @Override + @SneakyThrows + public void visit(ModuleItem item, int index) { + var moduleContext = BslContext.getCurrent().getModuleContext(item.getModule()); + if (moduleContext.isEmpty()) { + return; + } + var path = pathResolver.getFilePath(MDOHelper.getOwner(item.getModule()).getName()); + if (!Files.exists(path.getParent())) { + Files.createDirectories(path.getParent()); + } + if (outputStrategy.needRender(path)) { + Links.setCurrentPath(path); + var content = BslRender.renderModule(moduleContext, index); + outputStrategy.save(path, content) + .setType(PageType.MODULE); + } + } + + @Override + public void visit(MDObjectItem item, int index) { + item.accentChildren(this); + } + + private void renderSubsystemPage(SubsystemItem item) { + var path = getSubsystemPagePath(item); + + if (outputStrategy.needRender(path)) { + var context = ContextFactory.create(item.getSubsystem(), 0, subsystemLevel); + context.setContentModel(contentModel); + if (outputOptions.getChildLayout() == ChildLayout.SAME_DIRECTORY) { + context.setOutputPath(path.getParent()); + } else { + context.setOutputPath(path.getParent().resolve(item.getName())); + } + Links.setCurrentPath(path); + var content = BslRender.renderSubsystem(context); + outputStrategy.save(path, content) + .setType(PageType.SUBSYSTEM); + } + } + + private Path getSubsystemPagePath(SubsystemItem item) { + return outputOptions.getChildLayout() == ChildLayout.SAME_DIRECTORY ? pathResolver.getFilePath("index") : pathResolver.getFilePath(item.getName()); + } +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/render/StructureStrategy.java b/src/main/java/ru/alkoleft/bsl/doc/render/StructureStrategy.java deleted file mode 100644 index 553ab9a..0000000 --- a/src/main/java/ru/alkoleft/bsl/doc/render/StructureStrategy.java +++ /dev/null @@ -1,64 +0,0 @@ -package ru.alkoleft.bsl.doc.render; - -import com.github._1c_syntax.bsl.mdo.MD; -import com.github._1c_syntax.bsl.mdo.MDObject; -import com.github._1c_syntax.mdclasses.Configuration; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; - -public abstract class StructureStrategy { - - protected Path path; - protected String extension; - - StructureStrategy(Path path, String extension) throws IOException { - this.path = path; - this.extension = extension; - - createIfNotExists(path); - } - - public Path getPath(MDObject object) throws IOException { - Path objectPath = path.resolve(getObjectPath(object)); - createIfNotExists(objectPath.getParent()); - return objectPath; - - } - - public Path getPath(MD object) { - return path.resolve(getFileName(object)); - } - - public String getLink(MDObject object) { - return "../" + getObjectPath(object); - } - - protected abstract String getObjectPath(MDObject object); - - public String getFileName(MD object) { - return String.format("%s.%s", object.getName(), extension); - } - - public String getFileName(Configuration object) { - return String.format("configuration.%s", extension); - } - - protected void createIfNotExists(Path path) throws IOException { - if (!Files.exists(path)) { - Files.createDirectories(path); - } - } - - static class Metadata extends StructureStrategy { - public Metadata(Path path, String extension) throws IOException { - super(path, extension); - } - - @Override - public String getObjectPath(MDObject object) { - return Path.of(object.getMdoType().getGroupName(), getFileName(object)).toString(); - } - } -} diff --git a/src/main/java/ru/alkoleft/bsl/doc/render/contexts/BaseContext.java b/src/main/java/ru/alkoleft/bsl/doc/render/contexts/BaseContext.java new file mode 100644 index 0000000..758b2f1 --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/render/contexts/BaseContext.java @@ -0,0 +1,20 @@ +package ru.alkoleft.bsl.doc.render.contexts; + +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; + +import java.nio.file.Path; + +@Getter +@AllArgsConstructor +@EqualsAndHashCode +public class BaseContext { + private final int index; + private final String name; + private final String present; + private final String description; + @Setter + private Path outputPath; +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/render/contexts/ContextFactory.java b/src/main/java/ru/alkoleft/bsl/doc/render/contexts/ContextFactory.java new file mode 100644 index 0000000..f83c6b6 --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/render/contexts/ContextFactory.java @@ -0,0 +1,77 @@ +package ru.alkoleft.bsl.doc.render.contexts; + +import com.github._1c_syntax.bsl.mdo.CommonModule; +import com.github._1c_syntax.bsl.mdo.MD; +import com.github._1c_syntax.bsl.mdo.Subsystem; +import com.github._1c_syntax.bsl.types.ModuleType; +import com.github.jknack.handlebars.Context; +import com.github.jknack.handlebars.context.FieldValueResolver; +import com.github.jknack.handlebars.context.JavaBeanValueResolver; +import com.github.jknack.handlebars.context.MapValueResolver; +import com.github.jknack.handlebars.context.MethodValueResolver; +import lombok.experimental.UtilityClass; +import ru.alkoleft.bsl.doc.bsl.ModuleInfo; +import ru.alkoleft.bsl.doc.bsl.helpers.MDOHelper; + +@UtilityClass +public class ContextFactory { + + public ModuleContext create(ModuleInfo module, int index) { + return ModuleContext.builder() + .index(index) + .name(module.getOwner().getName()) + .present(MDOHelper.getPresent(module.getOwner())) + .isCommonModule(module.getOwner() instanceof CommonModule) + .ownerType(module.getOwner().getMdoType().getNameRu()) + .moduleType(getPresent(module.getModule().getModuleType())) + .methods(module.getMethods()) + .description(module.getDescription()) + .build(); + } + + public SubsystemContext create(Subsystem subsystem, int index, int level) { + return SubsystemContext.builder() + .subsystem(subsystem) + .index(index) + .name(subsystem.getName()) + .present(MDOHelper.getPresent(subsystem)) + .description(subsystem.getComment()) + .level(level) + .build(); + } + + public Context createContext(Object obj) { + return Context.newBuilder(obj) + .resolver( + MapValueResolver.INSTANCE, + JavaBeanValueResolver.INSTANCE, + MethodValueResolver.INSTANCE, + FieldValueResolver.INSTANCE + ) + .build(); + } + + private String getPresent(ModuleType moduleType) { + switch (moduleType) { + case ManagerModule: + return "Модуль менеджера"; + case BotModule: + case ObjectModule: + return "Модуль объекта"; + case HTTPServiceModule: + return "Модуль http-сервиса"; + case WEBServiceModule: + return "Модуль web-сервиса"; + case CommonModule: + return "Модуль"; + case CommandModule: + return "Модуль команды"; + case RecordSetModule: + return "Модуль набора записей"; + case ValueManagerModule: + return "Модуль менеджера значений"; + default: + return moduleType.name(); + } + } +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/render/contexts/ModuleContext.java b/src/main/java/ru/alkoleft/bsl/doc/render/contexts/ModuleContext.java new file mode 100644 index 0000000..1407730 --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/render/contexts/ModuleContext.java @@ -0,0 +1,27 @@ +package ru.alkoleft.bsl.doc.render.contexts; + +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Value; +import ru.alkoleft.bsl.doc.bsl.symbols.MethodSymbol; + +import java.nio.file.Path; +import java.util.List; + +@EqualsAndHashCode(callSuper = true) +@Value +public class ModuleContext extends BaseContext { + boolean isCommonModule; + String ownerType; + String moduleType; + List methods; + + @Builder + public ModuleContext(int index, String name, String present, String description, Path outputPath, boolean isCommonModule, String ownerType, String moduleType, List methods) { + super(index, name, present, description, outputPath); + this.isCommonModule = isCommonModule; + this.ownerType = ownerType; + this.moduleType = moduleType; + this.methods = methods; + } +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/render/contexts/SubsystemContext.java b/src/main/java/ru/alkoleft/bsl/doc/render/contexts/SubsystemContext.java new file mode 100644 index 0000000..ed2d789 --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/render/contexts/SubsystemContext.java @@ -0,0 +1,47 @@ +package ru.alkoleft.bsl.doc.render.contexts; + +import com.github._1c_syntax.bsl.mdo.Constant; +import com.github._1c_syntax.bsl.mdo.Subsystem; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; +import ru.alkoleft.bsl.doc.bsl.BslContext; +import ru.alkoleft.bsl.doc.model.ContentModel; +import ru.alkoleft.bsl.doc.model.Page; + +import java.nio.file.Path; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +@EqualsAndHashCode(callSuper = true) +@Getter +public class SubsystemContext extends BaseContext { + private final int level; + private final Subsystem subsystem; + @Setter + private ContentModel contentModel; + + @Builder + public SubsystemContext(int index, String name, String present, String description, Path outputPath, int level, Subsystem subsystem) { + super(index, name, present, description, outputPath); + this.level = level; + this.subsystem = subsystem; + } + + public List getConstants() { + return BslContext.getCurrent().getSubsystemObjects(subsystem) + .filter(Constant.class::isInstance) + .map(Constant.class::cast) + .collect(Collectors.toList()); + } + + public List getChildrenPages() { + if (contentModel != null) { + return contentModel.getChildrenPages(getOutputPath()); + } else { + return Collections.emptyList(); + } + } +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/render/handlebars/HandleLinks.java b/src/main/java/ru/alkoleft/bsl/doc/render/handlebars/HandleLinks.java deleted file mode 100644 index 86a1585..0000000 --- a/src/main/java/ru/alkoleft/bsl/doc/render/handlebars/HandleLinks.java +++ /dev/null @@ -1,36 +0,0 @@ -package ru.alkoleft.bsl.doc.render.handlebars; - -import com.github.jknack.handlebars.Helper; -import com.github.jknack.handlebars.Options; -import ru.alkoleft.bsl.doc.bsl.BslContext; - -import java.io.IOException; -import java.util.Locale; -import java.util.regex.Pattern; - -public class HandleLinks implements Helper { - Pattern pattern = Pattern.compile("см\\. (([\\wА-Яа-я\\.\\d]+)\\.)*([\\wА-Яа-я\\d]+)"); - - BslContext context; - - @Override - public Object apply(String context, Options options) throws IOException { - var matcher = pattern.matcher(context); - if (matcher.find()) { - return matcher.replaceAll(matchResult -> String.format("[%s](%s)", matchResult.group(0), getLink(matcher.group(2), matcher.group(3)))); - } - return context; - } - - private String getLink(String owner, String method) { - if (owner != null && method != null) { - return owner + "#" + method.toLowerCase(Locale.ROOT); - } else if (context.contains(method)) { - return method; - } else if (method != null) { - return "#" + method.toLowerCase(Locale.ROOT); - } else{ - return ""; - } - } -} diff --git a/src/main/java/ru/alkoleft/bsl/doc/render/handlebars/HandlebarItemRender.java b/src/main/java/ru/alkoleft/bsl/doc/render/handlebars/HandlebarItemRender.java deleted file mode 100644 index 80cc207..0000000 --- a/src/main/java/ru/alkoleft/bsl/doc/render/handlebars/HandlebarItemRender.java +++ /dev/null @@ -1,33 +0,0 @@ -package ru.alkoleft.bsl.doc.render.handlebars; - -import com.github.jknack.handlebars.Template; -import ru.alkoleft.bsl.doc.render.ItemRender; - -import java.io.FileWriter; -import java.io.IOException; -import java.nio.file.Path; -import java.util.HashMap; -import java.util.Map; - -public class HandlebarItemRender implements ItemRender { - - private final Template template; - - HandlebarItemRender(Template template) { - this.template = template; - } - - Map context = new HashMap<>(); - - @Override - public void put(String key, Object value) { - context.put(key, value); - } - - @Override - public void renderToFile(Path fileName) throws IOException { - try (FileWriter writer = new FileWriter(fileName.toFile())) { - template.apply(context, writer); - } - } -} diff --git a/src/main/java/ru/alkoleft/bsl/doc/render/handlebars/HandlebarsRenderContext.java b/src/main/java/ru/alkoleft/bsl/doc/render/handlebars/HandlebarsRenderContext.java deleted file mode 100644 index 938c80c..0000000 --- a/src/main/java/ru/alkoleft/bsl/doc/render/handlebars/HandlebarsRenderContext.java +++ /dev/null @@ -1,45 +0,0 @@ -package ru.alkoleft.bsl.doc.render.handlebars; - -import com.github.jknack.handlebars.Handlebars; -import com.github.jknack.handlebars.Template; -import ru.alkoleft.bsl.doc.bsl.BslContext; -import ru.alkoleft.bsl.doc.render.RenderContext; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - -public class HandlebarsRenderContext implements RenderContext { - - private final String path; - private final Handlebars handlebars; - private final Map loadedTemplates = new HashMap<>(); - - private final HandleLinks linksRender; - - public HandlebarsRenderContext(String path) { - this.path = path; - handlebars = new Handlebars().with(value -> value); - handlebars.registerHelper("links", linksRender = new HandleLinks()); - handlebars.registerHelper("shift", new Shifter()); - } - - public void setContext(BslContext context) { - linksRender.context = context; - } - - @Override - public HandlebarItemRender getRender(String name) throws IOException { - return new HandlebarItemRender(getTemplate(name)); - } - - private Template getTemplate(String name) throws IOException { - if (loadedTemplates.containsKey(name)) { - return loadedTemplates.get(name); - } - var location = String.format("%s/%s", path, name); - var template = handlebars.compile(location); - loadedTemplates.put(name, template); - return template; - } -} diff --git a/src/main/java/ru/alkoleft/bsl/doc/render/handlebars/RenderContext.java b/src/main/java/ru/alkoleft/bsl/doc/render/handlebars/RenderContext.java new file mode 100644 index 0000000..2ea04c4 --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/render/handlebars/RenderContext.java @@ -0,0 +1,94 @@ +package ru.alkoleft.bsl.doc.render.handlebars; + +import com.github.jknack.handlebars.Context; +import com.github.jknack.handlebars.Handlebars; +import com.github.jknack.handlebars.Template; +import com.github.jknack.handlebars.cache.ConcurrentMapTemplateCache; +import com.github.jknack.handlebars.helper.ConditionalHelpers; +import com.github.jknack.handlebars.io.URLTemplateLoader; +import lombok.SneakyThrows; +import lombok.experimental.UtilityClass; +import lombok.extern.slf4j.Slf4j; +import ru.alkoleft.bsl.doc.bsl.BslContext; +import ru.alkoleft.bsl.doc.options.OutputOptions; +import ru.alkoleft.bsl.doc.render.handlebars.helpers.Debugger; +import ru.alkoleft.bsl.doc.render.handlebars.helpers.Links; +import ru.alkoleft.bsl.doc.render.handlebars.helpers.MdoPresent; +import ru.alkoleft.bsl.doc.render.handlebars.helpers.PageLink; +import ru.alkoleft.bsl.doc.render.handlebars.helpers.Shifter; +import ru.alkoleft.bsl.doc.render.handlebars.helpers.SingleLine; + +import java.io.FileWriter; +import java.io.IOException; +import java.io.StringWriter; +import java.net.URL; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; + +@Slf4j +public class RenderContext { + private final URL baseURL; + private final Handlebars handlebars; + private final Map loadedTemplates = new HashMap<>(); + private final Links linksRender; + + private RenderContext(String path) { + this.baseURL = getClass().getClassLoader().getResource(path); + handlebars = new Handlebars() + .with(new URLTemplateLoader() { + @Override + protected URL getResource(String location) throws IOException { + return new URL(baseURL + location); + } + }) + .with(new ConcurrentMapTemplateCache()); + + handlebars.registerHelper("great", ConditionalHelpers.gt); + handlebars.registerHelper("eq", ConditionalHelpers.eq); + + handlebars.registerHelper("links", linksRender = new Links()); + handlebars.registerHelper("mdo-present", new MdoPresent()); + handlebars.registerHelper("shift", new Shifter()); + handlebars.registerHelper("debug", new Debugger()); + handlebars.registerHelper("single-line", new SingleLine()); + handlebars.registerHelper("page-link", new PageLink()); + } + + public void setContext(BslContext context) { + linksRender.setContext(context); + } + + @SneakyThrows + public void renderToFile(String templateName, Context context, Path output) { + var template = getTemplate(templateName); + try (var writer = new FileWriter(output.toFile())) { + template.apply(context, writer); + } + } + + @SneakyThrows + public String render(String templateName, Context context) { + var template = getTemplate(templateName); + var writer = new StringWriter(); + template.apply(context, writer); + return writer.toString(); + } + + @SneakyThrows + private Template getTemplate(String name) { + if (loadedTemplates.containsKey(name)) { + return loadedTemplates.get(name); + } + var template = handlebars.compile(name); + loadedTemplates.put(name, template); + return template; + } + + @UtilityClass + public static class Factory { + public RenderContext create(OutputOptions options) { + return new RenderContext(options.getOutputFormat().getPath()); + } + } +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/render/handlebars/helpers/Debugger.java b/src/main/java/ru/alkoleft/bsl/doc/render/handlebars/helpers/Debugger.java new file mode 100644 index 0000000..f268479 --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/render/handlebars/helpers/Debugger.java @@ -0,0 +1,16 @@ +package ru.alkoleft.bsl.doc.render.handlebars.helpers; + +import com.github.jknack.handlebars.Helper; +import com.github.jknack.handlebars.Options; +import lombok.extern.slf4j.Slf4j; + +import java.io.IOException; + +@Slf4j +public class Debugger implements Helper { + @Override + public Object apply(Object context, Options options) throws IOException { + log.debug(options.fn().toString()); + return null; + } +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/render/handlebars/helpers/Links.java b/src/main/java/ru/alkoleft/bsl/doc/render/handlebars/helpers/Links.java new file mode 100644 index 0000000..b23413c --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/render/handlebars/helpers/Links.java @@ -0,0 +1,68 @@ +package ru.alkoleft.bsl.doc.render.handlebars.helpers; + +import com.github.jknack.handlebars.Context; +import com.github.jknack.handlebars.Helper; +import com.github.jknack.handlebars.Options; +import lombok.Setter; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import ru.alkoleft.bsl.doc.bsl.BslContext; + +import java.util.Locale; +import java.util.regex.Pattern; + +@Slf4j +public class Links implements Helper { + private final Pattern linkPattern = Pattern.compile("см\\. (([\\wА-Яа-я\\.\\d]+)\\.)*([\\wА-Яа-я\\d]+)"); + private final Pattern warningPattern = Pattern.compile("(\\n\\s*\\n|^)(Важно[\\s\\S]+)(\\n\\s*\\n|$)"); + @Setter + private BslContext context; + + @Override + public Object apply(String context, Options options) { + return context; +// var matcher = linkPattern.matcher(context); +// String result; +// if (matcher.find()) { +// result = matcher.replaceAll(matchResult -> replaceTo(matcher.group(0), ru.alkoleft.bsl.doc.bsl.Links.createLink(matcher.group(2), matcher.group(3)), options)); +// } else { +// result = context; +// } +// +// result = handleWarning(result); +// +// return result; + } + + @SneakyThrows + private String replaceTo(String baseValue, ru.alkoleft.bsl.doc.bsl.Links.Link link, Options options) { + var methodInfo = BslContext.getCurrent().getMethodInfo(link); + if (methodInfo == null || methodInfo.isPublishing() || methodInfo.getMethod() == null) { + return String.format("[%s](%s)", baseValue, getLink(link)); + } + + var context = Context.newBuilder(methodInfo.getMethod().getReturnedValue()).build(); + return baseValue + options.apply(options.fn, context).toString(); + } + + private String handleWarning(String content) { + // TODO Реализовать и другие блоки https://docusaurus.io/docs/markdown-features/admonitions + if (content.contains("Важно")) { + var matcher = warningPattern.matcher(content); + content = matcher.replaceAll(m -> m.group(1) + ":::tip важно\n\n" + matcher.group(2) + "\n\n:::" + matcher.group(3)); + } + return content; + } + + private String getLink(ru.alkoleft.bsl.doc.bsl.Links.Link link) { + if (link.getOwnerName() != null && link.getMethodName() != null) { + return link.getOwnerName() + "#" + link.getMethodName().toLowerCase(Locale.ROOT); + } else if (link.getOwnerName() != null) { + return link.getOwnerName(); + } else if (link.getMethodName() != null) { + return "#" + link.getMethodName().toLowerCase(Locale.ROOT); + } else { + return ""; + } + } +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/render/handlebars/helpers/MdoPresent.java b/src/main/java/ru/alkoleft/bsl/doc/render/handlebars/helpers/MdoPresent.java new file mode 100644 index 0000000..f969caf --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/render/handlebars/helpers/MdoPresent.java @@ -0,0 +1,22 @@ +package ru.alkoleft.bsl.doc.render.handlebars.helpers; + +import com.github._1c_syntax.bsl.mdo.MD; +import com.github.jknack.handlebars.Helper; +import com.github.jknack.handlebars.Options; +import ru.alkoleft.bsl.doc.bsl.helpers.MDOHelper; +import ru.alkoleft.bsl.doc.render.contexts.SubsystemContext; + +import java.io.IOException; + +public class MdoPresent implements Helper { + @Override + public Object apply(Object context, Options options) throws IOException { + if (context instanceof MD) { + return MDOHelper.getPresent((MD) context); + } else if (context instanceof SubsystemContext) { + return MDOHelper.getPresent(((SubsystemContext) context).getSubsystem()); + } else { + return context.toString(); + } + } +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/render/handlebars/helpers/PageLink.java b/src/main/java/ru/alkoleft/bsl/doc/render/handlebars/helpers/PageLink.java new file mode 100644 index 0000000..c60ad19 --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/render/handlebars/helpers/PageLink.java @@ -0,0 +1,15 @@ +package ru.alkoleft.bsl.doc.render.handlebars.helpers; + +import com.github.jknack.handlebars.Helper; +import com.github.jknack.handlebars.Options; +import ru.alkoleft.bsl.doc.model.Links; +import ru.alkoleft.bsl.doc.model.Page; + +import java.io.IOException; + +public class PageLink implements Helper { + @Override + public Object apply(Page context, Options options) throws IOException { + return Links.getPageLink(context); + } +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/render/handlebars/Shifter.java b/src/main/java/ru/alkoleft/bsl/doc/render/handlebars/helpers/Shifter.java similarity index 55% rename from src/main/java/ru/alkoleft/bsl/doc/render/handlebars/Shifter.java rename to src/main/java/ru/alkoleft/bsl/doc/render/handlebars/helpers/Shifter.java index 703434b..f1b6400 100644 --- a/src/main/java/ru/alkoleft/bsl/doc/render/handlebars/Shifter.java +++ b/src/main/java/ru/alkoleft/bsl/doc/render/handlebars/helpers/Shifter.java @@ -1,4 +1,4 @@ -package ru.alkoleft.bsl.doc.render.handlebars; +package ru.alkoleft.bsl.doc.render.handlebars.helpers; import com.github.jknack.handlebars.Helper; import com.github.jknack.handlebars.Options; @@ -10,13 +10,16 @@ public class Shifter implements Helper { @Override public Object apply(Object context, Options options) throws IOException { - Options.Buffer buffer = options.buffer(); - int startedShift = shift; + var buffer = options.buffer(); + var startedShift = shift; + + int delta = context instanceof Integer ? (Integer) context : 0; + shift += delta; shift++; var content = options.fn(); - shift--; - if (startedShift > 0) { - var newChar = "\n" + new String(new char[startedShift]).replace('\0', '\t'); + shift = startedShift; + if (startedShift + delta > 0) { + var newChar = "\n" + new String(new char[2 * (startedShift + delta)]).replace('\0', ' '); buffer.append(content.toString().replace("\n", newChar)); } else { buffer.append(content); diff --git a/src/main/java/ru/alkoleft/bsl/doc/render/handlebars/helpers/SingleLine.java b/src/main/java/ru/alkoleft/bsl/doc/render/handlebars/helpers/SingleLine.java new file mode 100644 index 0000000..0fea76e --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/render/handlebars/helpers/SingleLine.java @@ -0,0 +1,24 @@ +package ru.alkoleft.bsl.doc.render.handlebars.helpers; + +import com.github.jknack.handlebars.Helper; +import com.github.jknack.handlebars.Options; +import com.github.jknack.handlebars.TagType; + +import java.io.IOException; + +public class SingleLine implements Helper { + @Override + public Object apply(Object context, Options options) throws IOException { + var buffer = options.buffer(); + + String content; + if (options.tagType == TagType.SECTION) { + content = options.fn().toString(); + } else { + content = context.toString(); + } + + buffer.append(content.replace("\n", "
")); + return buffer; + } +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/render/output/AppendStrategy.java b/src/main/java/ru/alkoleft/bsl/doc/render/output/AppendStrategy.java new file mode 100644 index 0000000..cfb799b --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/render/output/AppendStrategy.java @@ -0,0 +1,10 @@ +package ru.alkoleft.bsl.doc.render.output; + +import java.nio.file.Path; + +public class AppendStrategy extends OutputStrategy { + @Override + public boolean needRender(Path location) { + return manualContent.isNotContains(location); + } +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/render/output/MergeStrategy.java b/src/main/java/ru/alkoleft/bsl/doc/render/output/MergeStrategy.java new file mode 100644 index 0000000..1e8f89a --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/render/output/MergeStrategy.java @@ -0,0 +1,26 @@ +package ru.alkoleft.bsl.doc.render.output; + +import com.github.jknack.handlebars.internal.Files; +import lombok.SneakyThrows; +import ru.alkoleft.bsl.doc.content.processor.TitleProcessor; +import ru.alkoleft.bsl.doc.model.Page; + +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.util.regex.Pattern; + +public class MergeStrategy extends OutputStrategy { + private static final Pattern replacePattern = Pattern.compile("^.*generated_content.*$", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); + + @SneakyThrows + @Override + public Page save(Path itemPath, String content) { + if (manualContent.isNotContains(itemPath)) { + return super.save(itemPath, content); + } + var manualContent = Files.read(itemPath.toFile(), StandardCharsets.UTF_8); + content = TitleProcessor.getInstance().cleanTitle(content); + var result = replacePattern.matcher(manualContent).replaceFirst(content); + return super.save(itemPath, result); + } +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/render/output/OutputStrategy.java b/src/main/java/ru/alkoleft/bsl/doc/render/output/OutputStrategy.java new file mode 100644 index 0000000..e9db6c3 --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/render/output/OutputStrategy.java @@ -0,0 +1,69 @@ +package ru.alkoleft.bsl.doc.render.output; + +import lombok.Getter; +import lombok.Setter; +import lombok.SneakyThrows; +import ru.alkoleft.bsl.doc.bsl.helpers.Strings; +import ru.alkoleft.bsl.doc.content.processor.TitleProcessor; +import ru.alkoleft.bsl.doc.manual.ManualContent; +import ru.alkoleft.bsl.doc.model.ContentModel; +import ru.alkoleft.bsl.doc.model.Page; +import ru.alkoleft.bsl.doc.options.ManualMergeStrategy; +import ru.alkoleft.bsl.doc.options.OutputFormat; + +import java.nio.file.Files; +import java.nio.file.Path; + +@Getter +public class OutputStrategy { + @Setter + protected OutputFormat format; + @Setter + protected ManualContent manualContent; + @Setter + protected ContentModel contentModel; + + public boolean needRender(Path location) { + return true; + } + + protected Page addToContentModel(Path path, String content) { + var page = getContentModel().append(path); + + if (Strings.isNullOrEmpty(page.getTitle())) { + var title = TitleProcessor.getInstance().getTitle(content); + page.setTitle(title); + } + + return page; + } + + public static OutputStrategy create(ManualMergeStrategy strategy) { + OutputStrategy processor; + switch (strategy) { + case APPEND: + processor = new AppendStrategy(); + break; + case MERGE: + processor = new MergeStrategy(); + break; + default: + processor = new OutputStrategy(); + break; + } + return processor; + } + + public void init(OutputFormat format, ManualContent manualContent, ContentModel contentModel) { + this.format = format; + this.manualContent = manualContent; + this.contentModel = contentModel; + } + + @SneakyThrows + public Page save(Path itemPath, String content) { + Files.createDirectories(itemPath.getParent()); + Files.writeString(itemPath, content); + return addToContentModel(itemPath, content); + } +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/render/output/Writer.java b/src/main/java/ru/alkoleft/bsl/doc/render/output/Writer.java new file mode 100644 index 0000000..6ed0bac --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/render/output/Writer.java @@ -0,0 +1,13 @@ +package ru.alkoleft.bsl.doc.render.output; + +import ru.alkoleft.bsl.doc.options.OutputFormat; + +import java.nio.file.Path; + +public class Writer { + OutputFormat format; + + public void save(Path path, String content) { + + } +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/render/velocity/VelocityItemRender.java b/src/main/java/ru/alkoleft/bsl/doc/render/velocity/VelocityItemRender.java deleted file mode 100644 index b54d579..0000000 --- a/src/main/java/ru/alkoleft/bsl/doc/render/velocity/VelocityItemRender.java +++ /dev/null @@ -1,42 +0,0 @@ -package ru.alkoleft.bsl.doc.render.velocity; - -import org.apache.velocity.Template; -import org.apache.velocity.VelocityContext; -import ru.alkoleft.bsl.doc.render.ItemRender; - -import java.io.BufferedWriter; -import java.io.FileWriter; -import java.io.IOException; -import java.io.OutputStreamWriter; -import java.io.StringWriter; -import java.nio.file.Path; - -public class VelocityItemRender implements ItemRender { - private final Template template; - - VelocityItemRender(Template template) { - this.template = template; - } - - VelocityContext context = new VelocityContext(); - - public void put(String key, Object value) { - context.put(key, value); - } - - public void renderToFile(Path fileName) throws IOException { - try (FileWriter writer = new FileWriter(fileName.toFile())) { - template.merge(context, writer); - } - } - - public String renderToString() { - StringWriter writer = new StringWriter(); - template.merge(context, writer); - return writer.toString(); - } - - public void renderToConsole() { - template.merge(context, new BufferedWriter(new OutputStreamWriter(System.out))); - } -} diff --git a/src/main/java/ru/alkoleft/bsl/doc/render/velocity/VelocityRenderContext.java b/src/main/java/ru/alkoleft/bsl/doc/render/velocity/VelocityRenderContext.java deleted file mode 100644 index 2bfafb6..0000000 --- a/src/main/java/ru/alkoleft/bsl/doc/render/velocity/VelocityRenderContext.java +++ /dev/null @@ -1,44 +0,0 @@ -package ru.alkoleft.bsl.doc.render.velocity; - -import org.apache.velocity.Template; -import org.apache.velocity.app.VelocityEngine; -import ru.alkoleft.bsl.doc.bsl.BslContext; -import ru.alkoleft.bsl.doc.render.ItemRender; -import ru.alkoleft.bsl.doc.render.RenderContext; - -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.OutputStreamWriter; -import java.io.StringWriter; -import java.util.Properties; - -public class VelocityRenderContext implements RenderContext { - VelocityEngine velocityEngine; - String path; - - public VelocityRenderContext(String name) { - path = name; - - velocityEngine = new VelocityEngine(); - Properties properties = new Properties(); - properties.setProperty("resource.loaders", "file"); -// properties.setProperty("runtime.log.logsystem.class", "org.apache.velocity.runtime.log.AvalonLogChute"); - properties.setProperty("resource.loader.file.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader"); - velocityEngine.init(properties); - velocityEngine.init(); - } - - public Template getTemplate(String name) { - return velocityEngine.getTemplate(String.format("%s/%s.vm", path, name)); - } - - @Override - public ItemRender getRender(String name) throws IOException { - return new VelocityItemRender(getTemplate(name)); - } - - @Override - public void setContext(BslContext context) { - - } -} diff --git a/src/main/java/ru/alkoleft/bsl/doc/structure/Factory.java b/src/main/java/ru/alkoleft/bsl/doc/structure/Factory.java new file mode 100644 index 0000000..52f6492 --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/structure/Factory.java @@ -0,0 +1,44 @@ +package ru.alkoleft.bsl.doc.structure; + +import com.github._1c_syntax.bsl.mdo.MD; +import com.github._1c_syntax.bsl.mdo.ModuleOwner; +import com.github._1c_syntax.bsl.mdo.Subsystem; +import lombok.experimental.UtilityClass; +import ru.alkoleft.bsl.doc.bsl.BslContext; +import ru.alkoleft.bsl.doc.bsl.helpers.BslFilter; + +@UtilityClass +public class Factory { + public Item createSubSystemItem(Subsystem subsystem, BslContext context) { + var item = new SubsystemItem(subsystem); + fillChildrenSubsystems(item, context); + fillChildrenObjects(item, context); + return item; + } + + public Item createMDObjectItem(MD owner) { + var item = new MDObjectItem(owner); + if (owner instanceof ModuleOwner) { + ((ModuleOwner) owner).getModules() + .stream() + .filter(BslFilter::checkModule) + .map(ModuleItem::new) + .forEach(item.getChildren()::add); + } + return item; + } + + private void fillChildrenObjects(SubsystemItem item, BslContext context) { + context.getSubsystemObjects(item.getSubsystem()) + .map(Factory::createMDObjectItem) + .filter(it -> !it.getChildren().isEmpty()) + .forEach(item.getChildren()::add); + } + + private void fillChildrenSubsystems(SubsystemItem item, BslContext context) { + context.getChildrenSubsystems(item.getSubsystem()) + .map(it -> createSubSystemItem(it, context)) + .forEach(item.getChildren()::add); + } + +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/structure/FlatStructureBuilder.java b/src/main/java/ru/alkoleft/bsl/doc/structure/FlatStructureBuilder.java new file mode 100644 index 0000000..7c404b3 --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/structure/FlatStructureBuilder.java @@ -0,0 +1,16 @@ +package ru.alkoleft.bsl.doc.structure; + +import ru.alkoleft.bsl.doc.bsl.BslContext; + +import java.util.List; +import java.util.stream.Collectors; + +public class FlatStructureBuilder implements StructureBuilder { + + @Override + public List build(BslContext context) { + return context.getModules() + .map(ModuleItem::new) + .collect(Collectors.toList()); + } +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/structure/Item.java b/src/main/java/ru/alkoleft/bsl/doc/structure/Item.java new file mode 100644 index 0000000..9fb1d2f --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/structure/Item.java @@ -0,0 +1,33 @@ +package ru.alkoleft.bsl.doc.structure; + +import lombok.Getter; +import lombok.Setter; + +import java.util.ArrayList; +import java.util.List; + +@Getter +public abstract class Item { + private final Object object; + private final String name; + private final List children = new ArrayList<>(); + @Setter + private String pageName; + + public Item(Object object, String name) { + this.object = object; + this.name = name; + } + + public String getPresent() { + return name; + } + + public abstract void accept(StructureVisitor visitor, int index); + + public void accentChildren(StructureVisitor visitor) { + for (int i = 0; i < getChildren().size(); i++) { + getChildren().get(i).accept(visitor, i); + } + } +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/structure/MDObjectItem.java b/src/main/java/ru/alkoleft/bsl/doc/structure/MDObjectItem.java new file mode 100644 index 0000000..8cc6ddc --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/structure/MDObjectItem.java @@ -0,0 +1,24 @@ +package ru.alkoleft.bsl.doc.structure; + +import com.github._1c_syntax.bsl.mdo.MD; + +public class MDObjectItem extends Item { + public MDObjectItem(MD object) { + super(object, object.getName()); + } + + @Override + public String getPresent() { + var mdo = getMDObject(); + return String.format("%s.%s", mdo.getMdoType().name(), mdo.getName()); + } + + @Override + public void accept(StructureVisitor visitor, int index) { + visitor.visit(this, index); + } + + public MD getMDObject() { + return (MD) getObject(); + } +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/structure/ModuleItem.java b/src/main/java/ru/alkoleft/bsl/doc/structure/ModuleItem.java new file mode 100644 index 0000000..9d06374 --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/structure/ModuleItem.java @@ -0,0 +1,18 @@ +package ru.alkoleft.bsl.doc.structure; + +import com.github._1c_syntax.bsl.mdo.Module; + +public class ModuleItem extends Item { + public ModuleItem(Module module) { + super(module, module.getModuleType().name()); + } + + public Module getModule() { + return (Module) getObject(); + } + + @Override + public void accept(StructureVisitor visitor, int index) { + visitor.visit(this, index); + } +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/structure/StructureBuilder.java b/src/main/java/ru/alkoleft/bsl/doc/structure/StructureBuilder.java new file mode 100644 index 0000000..5c5dfe3 --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/structure/StructureBuilder.java @@ -0,0 +1,42 @@ +package ru.alkoleft.bsl.doc.structure; + +import ru.alkoleft.bsl.doc.bsl.BslContext; +import ru.alkoleft.bsl.doc.options.OutputOptions; + +import java.util.List; + +public interface StructureBuilder { + + List build(BslContext context); + + static StructureBuilder builder(OutputOptions options) { + if (options.isSubsystemHierarchy()) { + return new SubsystemsStructureBuilder(); + } else { + return new FlatStructureBuilder(); + } + } + + static void print(List structure) { + print(structure, ""); + } + + private static void print(List structure, String prefix) { + Item item; + for (int index = 0; index < structure.size(); index++) { + item = structure.get(index); + if (index == structure.size() - 1) { + System.out.printf("%s└── %s\n", prefix, item.getPresent()); + if (!item.getChildren().isEmpty()) { + print(item.getChildren(), prefix + " "); + } + } else { + System.out.printf("%s├── %s\n", prefix, item.getPresent()); + if (!item.getChildren().isEmpty()) { + print(item.getChildren(), prefix + "│   "); + } + } + } + + } +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/structure/StructureVisitor.java b/src/main/java/ru/alkoleft/bsl/doc/structure/StructureVisitor.java new file mode 100644 index 0000000..861ce98 --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/structure/StructureVisitor.java @@ -0,0 +1,9 @@ +package ru.alkoleft.bsl.doc.structure; + +public interface StructureVisitor { + void visit(SubsystemItem item, int index); + + void visit(ModuleItem item, int index); + + void visit(MDObjectItem item, int index); +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/structure/SubsystemItem.java b/src/main/java/ru/alkoleft/bsl/doc/structure/SubsystemItem.java new file mode 100644 index 0000000..debd118 --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/structure/SubsystemItem.java @@ -0,0 +1,18 @@ +package ru.alkoleft.bsl.doc.structure; + +import com.github._1c_syntax.bsl.mdo.Subsystem; + +public class SubsystemItem extends Item { + public SubsystemItem(Subsystem subsystem) { + super(subsystem, subsystem.getName()); + } + + @Override + public void accept(StructureVisitor visitor, int index) { + visitor.visit(this, index); + } + + public Subsystem getSubsystem() { + return (Subsystem) getObject(); + } +} diff --git a/src/main/java/ru/alkoleft/bsl/doc/structure/SubsystemsStructureBuilder.java b/src/main/java/ru/alkoleft/bsl/doc/structure/SubsystemsStructureBuilder.java new file mode 100644 index 0000000..687a9b4 --- /dev/null +++ b/src/main/java/ru/alkoleft/bsl/doc/structure/SubsystemsStructureBuilder.java @@ -0,0 +1,16 @@ +package ru.alkoleft.bsl.doc.structure; + +import ru.alkoleft.bsl.doc.bsl.BslContext; + +import java.util.List; +import java.util.stream.Collectors; + +public class SubsystemsStructureBuilder implements StructureBuilder { + + public List build(BslContext context) { + + return context.getRootSubsystems(true) + .map(it -> Factory.createSubSystemItem(it, context)) + .collect(Collectors.toList()); + } +} diff --git a/src/main/resources/confluence-md/module.hbs b/src/main/resources/confluence-md/module.hbs new file mode 100644 index 0000000..8646cb3 --- /dev/null +++ b/src/main/resources/confluence-md/module.hbs @@ -0,0 +1,43 @@ +# {{moduleType}} {{#unless isCommonModule}}{{ownerType}}.{{/unless}}{{name}} + +{{~#if description}} + +{{links description}} + +{{~/if}} + +{{~#each methods}} + +###### {{callExample}} + +{{#if description}}{{links description}}{{/if}} +{{~#if parameters}} +{{#each parameters as | parameter|}} +* `{{parameter.name}}`{{#if required}} (**Обязательный**){{/if}} + {{~#eq parameter.types.size 1~}} + {{~#each parameter.types as | type typeIndex|}} - {{#with type~}}{{#shift 1}}{{#block "value-definition"}}{{/block}}{{/shift}}{{~/with}} + {{~else}} - {{links description}} + {{~/each}} + {{~else~}} +{{~#each parameter.types as | type typeIndex|}} + * {{#with type}}{{#shift 1}}{{#block "value-definition"}}{{/block}}{{/shift}}{{~/with}} + {{~else}} - {{links description}} +{{~/each}} + {{~/eq}} +{{~/each}} + {{~/if}} +{{~#if returnedValue}} + +*Возвращаемое значение* +{{#with returnedValue~}}{{#block "value-definition"}}{{/block}}{{~/with}} +{{~/if}} +{{~#if examples}} +Примеры: + +```bsl +{{~#each examples}} +{{this}} +{{~/each}} +``` +{{/if}} +{{~/each}} \ No newline at end of file diff --git a/src/main/resources/confluence-md/subsystem.hbs b/src/main/resources/confluence-md/subsystem.hbs new file mode 100644 index 0000000..7553a66 --- /dev/null +++ b/src/main/resources/confluence-md/subsystem.hbs @@ -0,0 +1,16 @@ +# {{#great level 2}}Подсистема {{/great}}{{present}} +{{~#if description}} +{{description}} +{{~/if}} +{{~#if constants}} + +## Константы +{{#each constants as | item|}} +* {{mdo-present item}} ({{item.name}}) +{{~/each}} +{{~/if}} + +## Содержимое +{{#each childrenPages as | item|}} +* [{{item.title}}]({{page-link item}}) +{{~/each}} diff --git a/src/main/resources/confluence-md/value-definition.hbs b/src/main/resources/confluence-md/value-definition.hbs new file mode 100644 index 0000000..221172c --- /dev/null +++ b/src/main/resources/confluence-md/value-definition.hbs @@ -0,0 +1,11 @@ +{{~#if link~}} +{{links link}} +{{~/if}} +{{~#if parameters}} +`{{name}}` - {{description}} + +{{#each parameters as |parameter| }}{{#with parameter}} +{{~#shift}}* `{{name}}` - {{#each types as | type|~}}{{#with type}}{{#block "value-definition"}}{{/block}}{{/with}}{{~/each}}{{/shift}} +{{/with}}{{/each}} +{{~else}}`{{name}}` - {{#links description}}{{#block "value-definition"}}{{/block}}{{/links}} +{{~/if}} \ No newline at end of file diff --git a/src/main/resources/docusaurus/module.hbs b/src/main/resources/docusaurus/module.hbs index 9ed483f..46e2bc2 100644 --- a/src/main/resources/docusaurus/module.hbs +++ b/src/main/resources/docusaurus/module.hbs @@ -12,20 +12,23 @@ title: {{name}} {{~/if}} ## Методы модуля - -{{~#each methods}} - +{{#each methods}} --- -### `{{name}}` +### `{{name}}`{{#debug}}Формирование описания метода {{name}}{{/debug}} + +{{#if deprecated~}} +:::caution Устаревший +::: +{{~/if}} {{#if description}}{{links description}}{{/if}} {{~#if parameters}} **Параметры метода** {{#each parameters as | parameter|}} -* `{{parameter.name}}` +* `{{parameter.name}}`{{#debug}}Формирование описания параметра {{parameter.name}}{{/debug}} {{~#each parameter.types as | type typeIndex|}} - * `{{type.name}}` - {{links type.description}} + * {{#with type}}{{#shift 3}}{{#block "docusaurus/value-definition"}}{{/block}}{{/shift}}{{~/with}} {{~else}} - {{links description}} {{~/each}} {{~/each}} @@ -48,4 +51,4 @@ title: {{name}} ``` {{/if}} -{{~/each}} +{{/each}} diff --git a/src/main/resources/docusaurus/value-definition.hbs b/src/main/resources/docusaurus/value-definition.hbs index 793e2c4..ee882b0 100644 --- a/src/main/resources/docusaurus/value-definition.hbs +++ b/src/main/resources/docusaurus/value-definition.hbs @@ -1,17 +1,16 @@ {{~#if link~}} {{links link}} {{~/if}} -{{~#if parameters}}
{{description}} ({{name}}) -{{~else}}`{{name}}` - {{links description}} -{{~/if}} -{{~#if parameters}} -{{/if}} +{{~#if parameters}} +
-{{~#each parameters}} -{{#shift}}* `{{name}}` - {{#each types~}}{{#block "docusaurus/value-definition"}}{{/block}}{{~/each}}{{/shift}} -{{~/each}} +`{{name}}` - {{description}} -{{~#if parameters}} + +{{#each parameters as |parameter| }}{{#with parameter}} +{{~#shift}}* `{{name}}` - {{#each types as | type|~}}{{#with type}}{{#block "docusaurus/value-definition"}}{{/block}}{{/with}}{{~/each}}{{/shift}} +{{/with}}{{/each}}
-{{/if}} \ No newline at end of file +{{~else}}`{{name}}` - {{#links description}}{{#block "docusaurus/value-definition"}}{{/block}}{{/links}} +{{~/if}} \ No newline at end of file diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml new file mode 100644 index 0000000..59dc38f --- /dev/null +++ b/src/main/resources/logback.xml @@ -0,0 +1,11 @@ + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + \ No newline at end of file diff --git a/src/main/resources/md/module.hbs b/src/main/resources/md/module.hbs index 7daf3c6..e3dbe55 100644 --- a/src/main/resources/md/module.hbs +++ b/src/main/resources/md/module.hbs @@ -1,6 +1,4 @@ -# {{present}} ({{name}}) - -## Методы модуля +# Программный интерфейс: {{#unless isCommonModule}}{{type}}.{{/unless}}{{present}} {{~#each methods}} @@ -9,13 +7,11 @@ {{#if description}}{{description}}{{/if}} {{~#if parameters}} -Параметры метода: - | Имя | Тип | Описание | |-----|-----|---------| {{~#each parameters as | parameter|}} {{~#each parameter.types as | type typeIndex|}} -| {{#unless typeIndex}}`{{parameter.name}}`{{/unless}} | `{{type.name}}` | {{type.description}} | +| {{#unless typeIndex}}`{{parameter.name}}`{{/unless}} | `{{type.name}}` | {{#single-line}}{{links type.description}}{{/single-line}} | {{~else}} | {{name}} | | {{description}} | {{~/each}} @@ -23,7 +19,7 @@ {{~/if}} {{~#if returnedValue}} -Возвращает: +Возвращаемое значение {{#if returnedValue.link}} [{{returnedValue.link}}]({{returnedValue.link}}) diff --git a/src/main/resources/md/module.vm b/src/main/resources/md/module.vm deleted file mode 100644 index 3506296..0000000 --- a/src/main/resources/md/module.vm +++ /dev/null @@ -1,18 +0,0 @@ -#set( $H = '#' ) -$H $present ($name) - -$H$H Методы модуля -#foreach( $method in $methods) - -$H$H$H $method.name - -$method.description -#if (!$method.parameters.empty) - -**Параметры метода** -#foreach( $parameter in $method.parameters) - -* $parameter.name - $parameter.description -#end -#end -#end \ No newline at end of file diff --git a/src/main/resources/md/subsystem.hbs b/src/main/resources/md/subsystem.hbs new file mode 100644 index 0000000..9dec684 --- /dev/null +++ b/src/main/resources/md/subsystem.hbs @@ -0,0 +1,8 @@ +# {{#great level 1}}Подсистема {{/great}}{{present}} + +{{description}} + +Содержимое: +{{#each children as | item|}} +* [{{item}}]({{item}}) +{{/each}} \ No newline at end of file diff --git a/src/test/java/ru/alkoleft/bsl/doc/commands/RenderCommandTest.java b/src/test/java/ru/alkoleft/bsl/doc/commands/RenderCommandTest.java new file mode 100644 index 0000000..04366eb --- /dev/null +++ b/src/test/java/ru/alkoleft/bsl/doc/commands/RenderCommandTest.java @@ -0,0 +1,45 @@ +package ru.alkoleft.bsl.doc.commands; + +import lombok.SneakyThrows; +import org.junit.jupiter.api.Test; +import ru.alkoleft.bsl.doc.bsl.symbols.RegionSymbol; +import ru.alkoleft.bsl.doc.options.ManualMergeStrategy; +import ru.alkoleft.bsl.doc.options.OutputFormat; + +import java.nio.file.Path; +import java.util.List; + +class RenderCommandTest { + + @Test + void run() { + RenderCommand.builder() + .sources(getResource("configuration")) + .destination(Path.of("/tmp/bsl-doc-fixture")) + .format(OutputFormat.ConfluenceMarkdown) + .onlySubsystems(List.of("ППИ")) + .regions(List.of(RegionSymbol.PUBLIC_REGION_RU)) + .manualDocumentation(getResource("docs")) + .manualMergeStrategy(ManualMergeStrategy.MERGE) + .build() + .run(); + } + + @Test + void runYaxUnit() { + RenderCommand.builder() + .sources(Path.of("/home/alko/develop/bia/orais/yaxunit/exts/yaxunit")) + .destination(Path.of("/tmp/bsl-doc-yaxunit")) + .format(OutputFormat.ConfluenceMarkdown) + .onlySubsystems(List.of("ЮТДвижок")) + .regions(List.of(RegionSymbol.PUBLIC_REGION_RU)) + .manualMergeStrategy(ManualMergeStrategy.MERGE) + .build() + .run(); + } + + @SneakyThrows + private Path getResource(String name) { + return Path.of(getClass().getClassLoader().getResource(name).toURI()); + } +} \ No newline at end of file diff --git a/src/test/resources/configuration/.project b/src/test/resources/configuration/.project new file mode 100644 index 0000000..84e659a --- /dev/null +++ b/src/test/resources/configuration/.project @@ -0,0 +1,18 @@ + + + BslDoc + + + + + + org.eclipse.xtext.ui.shared.xtextBuilder + + + + + + org.eclipse.xtext.ui.shared.xtextNature + com._1c.g5.v8.dt.core.V8ConfigurationNature + + diff --git a/src/test/resources/configuration/.settings/com.e1c.v8codestyle.autosort.prefs b/src/test/resources/configuration/.settings/com.e1c.v8codestyle.autosort.prefs new file mode 100644 index 0000000..23b0625 --- /dev/null +++ b/src/test/resources/configuration/.settings/com.e1c.v8codestyle.autosort.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +topObjects=true diff --git a/src/test/resources/configuration/.settings/com.e1c.v8codestyle.bsl.prefs b/src/test/resources/configuration/.settings/com.e1c.v8codestyle.bsl.prefs new file mode 100644 index 0000000..ac5ba52 --- /dev/null +++ b/src/test/resources/configuration/.settings/com.e1c.v8codestyle.bsl.prefs @@ -0,0 +1,3 @@ +addModuleStrictTypesAnnotation=false +createModuleStructure=false +eclipse.preferences.version=1 diff --git a/src/test/resources/configuration/.settings/com.e1c.v8codestyle.prefs b/src/test/resources/configuration/.settings/com.e1c.v8codestyle.prefs new file mode 100644 index 0000000..9e9b57e --- /dev/null +++ b/src/test/resources/configuration/.settings/com.e1c.v8codestyle.prefs @@ -0,0 +1,3 @@ +commonChecks=true +eclipse.preferences.version=1 +standardChecks=true diff --git a/src/test/resources/configuration/.settings/org.eclipse.core.resources.prefs b/src/test/resources/configuration/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..99f26c0 --- /dev/null +++ b/src/test/resources/configuration/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/=UTF-8 diff --git a/src/test/resources/configuration/DT-INF/PROJECT.PMF b/src/test/resources/configuration/DT-INF/PROJECT.PMF new file mode 100644 index 0000000..e2a2031 --- /dev/null +++ b/src/test/resources/configuration/DT-INF/PROJECT.PMF @@ -0,0 +1,2 @@ +Manifest-Version: 1.0 +Runtime-Version: 8.3.21 diff --git "a/src/test/resources/configuration/src/Catalogs/\320\241\320\277\321\200\320\260\320\262\320\276\321\207\320\275\320\270\320\2721/ManagerModule.bsl" "b/src/test/resources/configuration/src/Catalogs/\320\241\320\277\321\200\320\260\320\262\320\276\321\207\320\275\320\270\320\2721/ManagerModule.bsl" new file mode 100644 index 0000000..4765a70 --- /dev/null +++ "b/src/test/resources/configuration/src/Catalogs/\320\241\320\277\321\200\320\260\320\262\320\276\321\207\320\275\320\270\320\2721/ManagerModule.bsl" @@ -0,0 +1,13 @@ +#Область ПрограммныйИнтерфейс + +// Процедура1. +// Устаревший. +// +// Параметры: +// П1 П1 +// П2 П2 +Процедура Процедура1(П1, П2) Экспорт + +КонецПроцедуры + +#КонецОбласти \ No newline at end of file diff --git "a/src/test/resources/configuration/src/Catalogs/\320\241\320\277\321\200\320\260\320\262\320\276\321\207\320\275\320\270\320\2721/\320\241\320\277\321\200\320\260\320\262\320\276\321\207\320\275\320\270\320\2721.mdo" "b/src/test/resources/configuration/src/Catalogs/\320\241\320\277\321\200\320\260\320\262\320\276\321\207\320\275\320\270\320\2721/\320\241\320\277\321\200\320\260\320\262\320\276\321\207\320\275\320\270\320\2721.mdo" new file mode 100644 index 0000000..8ad2ff6 --- /dev/null +++ "b/src/test/resources/configuration/src/Catalogs/\320\241\320\277\321\200\320\260\320\262\320\276\321\207\320\275\320\270\320\2721/\320\241\320\277\321\200\320\260\320\262\320\276\321\207\320\275\320\270\320\2721.mdo" @@ -0,0 +1,33 @@ + + + + + + + + + + Справочник1 + + ru + Справочник1 + + true + Catalog.Справочник1.StandardAttribute.Code + Catalog.Справочник1.StandardAttribute.Description + DontUse + Use + Managed + Use + 2 + true + 9 + 25 + String + Variable + true + true + AsDescription + InDialog + BothWays + diff --git "a/src/test/resources/configuration/src/Catalogs/\320\241\320\277\321\200\320\260\320\262\320\276\321\207\320\275\320\270\320\2722/ObjectModule.bsl" "b/src/test/resources/configuration/src/Catalogs/\320\241\320\277\321\200\320\260\320\262\320\276\321\207\320\275\320\270\320\2722/ObjectModule.bsl" new file mode 100644 index 0000000..4765a70 --- /dev/null +++ "b/src/test/resources/configuration/src/Catalogs/\320\241\320\277\321\200\320\260\320\262\320\276\321\207\320\275\320\270\320\2722/ObjectModule.bsl" @@ -0,0 +1,13 @@ +#Область ПрограммныйИнтерфейс + +// Процедура1. +// Устаревший. +// +// Параметры: +// П1 П1 +// П2 П2 +Процедура Процедура1(П1, П2) Экспорт + +КонецПроцедуры + +#КонецОбласти \ No newline at end of file diff --git "a/src/test/resources/configuration/src/Catalogs/\320\241\320\277\321\200\320\260\320\262\320\276\321\207\320\275\320\270\320\2722/\320\241\320\277\321\200\320\260\320\262\320\276\321\207\320\275\320\270\320\2722.mdo" "b/src/test/resources/configuration/src/Catalogs/\320\241\320\277\321\200\320\260\320\262\320\276\321\207\320\275\320\270\320\2722/\320\241\320\277\321\200\320\260\320\262\320\276\321\207\320\275\320\270\320\2722.mdo" new file mode 100644 index 0000000..c6caceb --- /dev/null +++ "b/src/test/resources/configuration/src/Catalogs/\320\241\320\277\321\200\320\260\320\262\320\276\321\207\320\275\320\270\320\2722/\320\241\320\277\321\200\320\260\320\262\320\276\321\207\320\275\320\270\320\2722.mdo" @@ -0,0 +1,33 @@ + + + + + + + + + + Справочник2 + + ru + Справочник2 + + true + Catalog.Справочник2.StandardAttribute.Code + Catalog.Справочник2.StandardAttribute.Description + DontUse + Use + Managed + Use + 2 + true + 9 + 25 + String + Variable + true + true + AsDescription + InDialog + BothWays + diff --git "a/src/test/resources/configuration/src/CommonModules/\320\237\321\200\320\265\320\276\320\261\321\200\320\260\320\267\320\276\320\262\320\260\320\275\320\270\321\217/Module.bsl" "b/src/test/resources/configuration/src/CommonModules/\320\237\321\200\320\265\320\276\320\261\321\200\320\260\320\267\320\276\320\262\320\260\320\275\320\270\321\217/Module.bsl" new file mode 100644 index 0000000..130f397 --- /dev/null +++ "b/src/test/resources/configuration/src/CommonModules/\320\237\321\200\320\265\320\276\320\261\321\200\320\260\320\267\320\276\320\262\320\260\320\275\320\270\321\217/Module.bsl" @@ -0,0 +1,35 @@ +#Область ПрограммныйИнтерфейс + +// ЗначениеВСтроку +// Преобразует переданное значение в строку +// +// Параметры: +// Значение - Произвольный - значение для преобразования в строковое представление +// ФорматнаяСтрока - Строка - формат получаемой строки для примитивных типов +// Кешировать - Булево - признак необходимости кэширования результата +// +// Возвращаемое значение: +// Строка - результат преобразования значения +// +Функция ЗначениеВСтроку(Значение, ФорматнаяСтрока = "", Кешировать = Ложь) Экспорт + +КонецФункции + +// ЧислоИзОднойСистемыВДругую +// Возвращает представление числа, преобразованного из одной системы счисления в другую. +// +// Параметры: +// ПредставлениеЧисла - Строка - представление числа. +// - Число - Преобразуемое число +// ОснованиеЧисла - Число - основание системы счисления переданного представления числа (1-32). +// ОснованиеРезультата - Число - основание системы счисления результата (1-32). +// ДлинаРезультата - Число - количество символов в возвращаемом представлении, если результат меньшей длины - будет дополнен нулями слева. +// ТекстОшибки - Строка - в этот параметр будет помещен текст возникшей ошибки. +// +// Возвращаемое значение: +// Строка - представление числа в требуемой системе счисления, "0" при ошибке. +Функция ЧислоИзОднойСистемыВДругую(ПредставлениеЧисла, ОснованиеЧисла, ОснованиеРезультата, ДлинаРезультата = 1, ТекстОшибки = "") Экспорт + +КонецФункции + +#КонецОбласти \ No newline at end of file diff --git "a/src/test/resources/configuration/src/CommonModules/\320\237\321\200\320\265\320\276\320\261\321\200\320\260\320\267\320\276\320\262\320\260\320\275\320\270\321\217/\320\237\321\200\320\265\320\276\320\261\321\200\320\260\320\267\320\276\320\262\320\260\320\275\320\270\321\217.mdo" "b/src/test/resources/configuration/src/CommonModules/\320\237\321\200\320\265\320\276\320\261\321\200\320\260\320\267\320\276\320\262\320\260\320\275\320\270\321\217/\320\237\321\200\320\265\320\276\320\261\321\200\320\260\320\267\320\276\320\262\320\260\320\275\320\270\321\217.mdo" new file mode 100644 index 0000000..0dc6fb9 --- /dev/null +++ "b/src/test/resources/configuration/src/CommonModules/\320\237\321\200\320\265\320\276\320\261\321\200\320\260\320\267\320\276\320\262\320\260\320\275\320\270\321\217/\320\237\321\200\320\265\320\276\320\261\321\200\320\260\320\267\320\276\320\262\320\260\320\275\320\270\321\217.mdo" @@ -0,0 +1,9 @@ + + + Преобразования + + ru + Преобразования + + true + diff --git "a/src/test/resources/configuration/src/CommonModules/\320\241\321\202\321\200\320\276\320\272\320\276\320\262\321\213\320\265\320\244\321\203\320\275\320\272\321\206\320\270\320\270/Module.bsl" "b/src/test/resources/configuration/src/CommonModules/\320\241\321\202\321\200\320\276\320\272\320\276\320\262\321\213\320\265\320\244\321\203\320\275\320\272\321\206\320\270\320\270/Module.bsl" new file mode 100644 index 0000000..1cde5fd --- /dev/null +++ "b/src/test/resources/configuration/src/CommonModules/\320\241\321\202\321\200\320\276\320\272\320\276\320\262\321\213\320\265\320\244\321\203\320\275\320\272\321\206\320\270\320\270/Module.bsl" @@ -0,0 +1,77 @@ +#Область ПрограммныйИнтерфейс + +// ПолучитьСтрокуИзКоллекцииПодстрок +// Устаревший +// Возвращает строку, полученную из массива элементов, списка значений или таблицы значений, разделенных символом разделителя +// +// Параметры: +// Коллекция - ФиксированныйМассив, Массив, СписокЗначений, ТаблицаЗначений - коллекция элементов из +// которых необходимо получить строку +// Разделитель - Строка - любой набор символов, +// который будет использован как разделитель между элементами в строке +// Колонки - Строка - Имена колонок таблицы +// значений, разделенные ";" или "*" если необходимо вывести все колонки +// ИгнорироватьОшибки - Булево - Если установлен в Истина, +// то неверные имена колонок игнорируются, в противном случае будет выдана ошибка, содержащая неверные колонки +// +// Возвращаемое значение: +// Строка - строка, полученная из коллекции элементов, разделенных символом разделителя +// +Функция ПолучитьСтрокуИзКоллекцииПодстрок(Коллекция, Разделитель = ",", Колонки = Неопределено, ИгнорироватьОшибки = Ложь) Экспорт + +КонецФункции + +// ПолучитьСтрокуИзКоллекцииПодстрок +// Устаревший +// Возвращает строку, полученную из массива элементов, списка значений или таблицы значений, разделенных символом разделителя +// +// Параметры: +// Коллекция - ФиксированныйМассив, Массив, СписокЗначений, ТаблицаЗначений - коллекция элементов из +// которых необходимо получить строку +// Разделитель - Строка - любой набор символов, +// который будет использован как разделитель между элементами в строке +// Колонки - Строка - Имена колонок таблицы +// значений, разделенные ";" или "*" если необходимо вывести все колонки +// ИгнорироватьОшибки - Булево - Если установлен в Истина, +// то неверные имена колонок игнорируются, в противном случае будет выдана ошибка, содержащая неверные колонки +// +// Возвращаемое значение: +// Строка - строка, полученная из коллекции элементов, разделенных символом разделителя +// +Функция ПолучитьСтрокуИзКоллекцииПодстрок2(Коллекция, Разделитель = ",", Колонки = Неопределено, ИгнорироватьОшибки = Ложь) Экспорт + +КонецФункции + +// РазложитьСтрокуВКоллекцию +// раскладывает строку с разделителями в указанную коллекцию +// +// Параметры: +// ВходнаяСтрока - Строка - строка с разделителями +// ВидКоллекции - Строка - имя коллекции +// доступные варианты "Массив", "ФиксированныйМассив", "СписокЗначений" +// Разделитель - Строка - разделитель входной строки +// УдалятьКонцевыеПробелы - Булево - удаление концевых пробелов разложенных строк +// +// Возвращаемое значение: +// Массив, СписокЗначений, ФиксированныйМассив - "заказанная" коллекция +// +Функция РазложитьСтрокуВКоллекцию(Знач ВходнаяСтрока, ВидКоллекции = "Массив", Разделитель = ",", УдалятьКонцевыеПробелы = Ложь) Экспорт + +КонецФункции // РазложитьСтрокуВКоллекцию + +// ПолучитьПараметрыВхожденияСтроки +// Производит поиск в исходной строке вхождений искомой строки +// +// Параметры: +// ИсходнаяСтрока - Строка - Анализируемая строка +// СтрокаПоиска - Строка - Искомая строка +// +// Возвращаемое значение: +// Массив Из Структура - Результат метода: +// * НомерСимвола - Число - начало строки вхождения +// * ДлинаСтроки - Число - длина строки вхождения +// +Функция ПолучитьПараметрыВхожденияСтроки(ИсходнаяСтрока, СтрокаПоиска) Экспорт +КонецФункции + +#КонецОбласти diff --git "a/src/test/resources/configuration/src/CommonModules/\320\241\321\202\321\200\320\276\320\272\320\276\320\262\321\213\320\265\320\244\321\203\320\275\320\272\321\206\320\270\320\270/\320\241\321\202\321\200\320\276\320\272\320\276\320\262\321\213\320\265\320\244\321\203\320\275\320\272\321\206\320\270\320\270.mdo" "b/src/test/resources/configuration/src/CommonModules/\320\241\321\202\321\200\320\276\320\272\320\276\320\262\321\213\320\265\320\244\321\203\320\275\320\272\321\206\320\270\320\270/\320\241\321\202\321\200\320\276\320\272\320\276\320\262\321\213\320\265\320\244\321\203\320\275\320\272\321\206\320\270\320\270.mdo" new file mode 100644 index 0000000..4f360c6 --- /dev/null +++ "b/src/test/resources/configuration/src/CommonModules/\320\241\321\202\321\200\320\276\320\272\320\276\320\262\321\213\320\265\320\244\321\203\320\275\320\272\321\206\320\270\320\270/\320\241\321\202\321\200\320\276\320\272\320\276\320\262\321\213\320\265\320\244\321\203\320\275\320\272\321\206\320\270\320\270.mdo" @@ -0,0 +1,9 @@ + + + СтроковыеФункции + + ru + Строковые функции + + true + diff --git a/src/test/resources/configuration/src/Configuration/CommandInterface.cmi b/src/test/resources/configuration/src/Configuration/CommandInterface.cmi new file mode 100644 index 0000000..0cf6de8 --- /dev/null +++ b/src/test/resources/configuration/src/Configuration/CommandInterface.cmi @@ -0,0 +1,2 @@ + + diff --git a/src/test/resources/configuration/src/Configuration/Configuration.mdo b/src/test/resources/configuration/src/Configuration/Configuration.mdo new file mode 100644 index 0000000..69a0b86 --- /dev/null +++ b/src/test/resources/configuration/src/Configuration/Configuration.mdo @@ -0,0 +1,50 @@ + + + BslDoc + + ru + Bsl doc + + + + + + + + + 8.3.21 + ManagedApplication + PersonalComputer + Russian + + + true + + + OSBackup + true + + + Language.Русский + Managed + NotAutoFree + DontUse + DontUse + 8.3.21 + + Русский + + ru + Русский + + ru + + Subsystem.ППИ + CommonModule.Преобразования + CommonModule.СтроковыеФункции + Constant.Константа + Constant.Константа1 + Constant.Константа2 + Catalog.Справочник1 + Catalog.Справочник2 + diff --git a/src/test/resources/configuration/src/Configuration/MainSectionCommandInterface.cmi b/src/test/resources/configuration/src/Configuration/MainSectionCommandInterface.cmi new file mode 100644 index 0000000..0cf6de8 --- /dev/null +++ b/src/test/resources/configuration/src/Configuration/MainSectionCommandInterface.cmi @@ -0,0 +1,2 @@ + + diff --git "a/src/test/resources/configuration/src/Constants/\320\232\320\276\320\275\321\201\321\202\320\260\320\275\321\202\320\260/\320\232\320\276\320\275\321\201\321\202\320\260\320\275\321\202\320\260.mdo" "b/src/test/resources/configuration/src/Constants/\320\232\320\276\320\275\321\201\321\202\320\260\320\275\321\202\320\260/\320\232\320\276\320\275\321\201\321\202\320\260\320\275\321\202\320\260.mdo" new file mode 100644 index 0000000..c5cfc4a --- /dev/null +++ "b/src/test/resources/configuration/src/Constants/\320\232\320\276\320\275\321\201\321\202\320\260\320\275\321\202\320\260/\320\232\320\276\320\275\321\201\321\202\320\260\320\275\321\202\320\260.mdo" @@ -0,0 +1,23 @@ + + + + + + + + Константа + + ru + Константа + + + String + + 10 + + + true + + + Managed + diff --git "a/src/test/resources/configuration/src/Constants/\320\232\320\276\320\275\321\201\321\202\320\260\320\275\321\202\320\2601/\320\232\320\276\320\275\321\201\321\202\320\260\320\275\321\202\320\2601.mdo" "b/src/test/resources/configuration/src/Constants/\320\232\320\276\320\275\321\201\321\202\320\260\320\275\321\202\320\2601/\320\232\320\276\320\275\321\201\321\202\320\260\320\275\321\202\320\2601.mdo" new file mode 100644 index 0000000..34a3141 --- /dev/null +++ "b/src/test/resources/configuration/src/Constants/\320\232\320\276\320\275\321\201\321\202\320\260\320\275\321\202\320\2601/\320\232\320\276\320\275\321\201\321\202\320\260\320\275\321\202\320\2601.mdo" @@ -0,0 +1,23 @@ + + + + + + + + Константа1 + + ru + Константа 1 + + + String + + 10 + + + true + + + Managed + diff --git "a/src/test/resources/configuration/src/Constants/\320\232\320\276\320\275\321\201\321\202\320\260\320\275\321\202\320\2602/\320\232\320\276\320\275\321\201\321\202\320\260\320\275\321\202\320\2602.mdo" "b/src/test/resources/configuration/src/Constants/\320\232\320\276\320\275\321\201\321\202\320\260\320\275\321\202\320\2602/\320\232\320\276\320\275\321\201\321\202\320\260\320\275\321\202\320\2602.mdo" new file mode 100644 index 0000000..53b83bd --- /dev/null +++ "b/src/test/resources/configuration/src/Constants/\320\232\320\276\320\275\321\201\321\202\320\260\320\275\321\202\320\2602/\320\232\320\276\320\275\321\201\321\202\320\260\320\275\321\202\320\2602.mdo" @@ -0,0 +1,23 @@ + + + + + + + + Константа2 + + ru + Константа 2 + + + String + + 10 + + + true + + + Managed + diff --git "a/src/test/resources/configuration/src/Subsystems/\320\237\320\237\320\230/CommandInterface.cmi" "b/src/test/resources/configuration/src/Subsystems/\320\237\320\237\320\230/CommandInterface.cmi" new file mode 100644 index 0000000..0cf6de8 --- /dev/null +++ "b/src/test/resources/configuration/src/Subsystems/\320\237\320\237\320\230/CommandInterface.cmi" @@ -0,0 +1,2 @@ + + diff --git "a/src/test/resources/configuration/src/Subsystems/\320\237\320\237\320\230/Subsystems/\320\237\321\200\320\270\320\272\320\273\320\260\320\264\320\275\321\213\320\265/CommandInterface.cmi" "b/src/test/resources/configuration/src/Subsystems/\320\237\320\237\320\230/Subsystems/\320\237\321\200\320\270\320\272\320\273\320\260\320\264\320\275\321\213\320\265/CommandInterface.cmi" new file mode 100644 index 0000000..0cf6de8 --- /dev/null +++ "b/src/test/resources/configuration/src/Subsystems/\320\237\320\237\320\230/Subsystems/\320\237\321\200\320\270\320\272\320\273\320\260\320\264\320\275\321\213\320\265/CommandInterface.cmi" @@ -0,0 +1,2 @@ + + diff --git "a/src/test/resources/configuration/src/Subsystems/\320\237\320\237\320\230/Subsystems/\320\237\321\200\320\270\320\272\320\273\320\260\320\264\320\275\321\213\320\265/Subsystems/\320\224\320\276\320\272\321\203\320\274\320\265\320\275\321\202\321\213/CommandInterface.cmi" "b/src/test/resources/configuration/src/Subsystems/\320\237\320\237\320\230/Subsystems/\320\237\321\200\320\270\320\272\320\273\320\260\320\264\320\275\321\213\320\265/Subsystems/\320\224\320\276\320\272\321\203\320\274\320\265\320\275\321\202\321\213/CommandInterface.cmi" new file mode 100644 index 0000000..0cf6de8 --- /dev/null +++ "b/src/test/resources/configuration/src/Subsystems/\320\237\320\237\320\230/Subsystems/\320\237\321\200\320\270\320\272\320\273\320\260\320\264\320\275\321\213\320\265/Subsystems/\320\224\320\276\320\272\321\203\320\274\320\265\320\275\321\202\321\213/CommandInterface.cmi" @@ -0,0 +1,2 @@ + + diff --git "a/src/test/resources/configuration/src/Subsystems/\320\237\320\237\320\230/Subsystems/\320\237\321\200\320\270\320\272\320\273\320\260\320\264\320\275\321\213\320\265/Subsystems/\320\224\320\276\320\272\321\203\320\274\320\265\320\275\321\202\321\213/\320\224\320\276\320\272\321\203\320\274\320\265\320\275\321\202\321\213.mdo" "b/src/test/resources/configuration/src/Subsystems/\320\237\320\237\320\230/Subsystems/\320\237\321\200\320\270\320\272\320\273\320\260\320\264\320\275\321\213\320\265/Subsystems/\320\224\320\276\320\272\321\203\320\274\320\265\320\275\321\202\321\213/\320\224\320\276\320\272\321\203\320\274\320\265\320\275\321\202\321\213.mdo" new file mode 100644 index 0000000..ff1e502 --- /dev/null +++ "b/src/test/resources/configuration/src/Subsystems/\320\237\320\237\320\230/Subsystems/\320\237\321\200\320\270\320\272\320\273\320\260\320\264\320\275\321\213\320\265/Subsystems/\320\224\320\276\320\272\321\203\320\274\320\265\320\275\321\202\321\213/\320\224\320\276\320\272\321\203\320\274\320\265\320\275\321\202\321\213.mdo" @@ -0,0 +1,11 @@ + + + Документы + + ru + Документы + + true + true + Subsystem.ППИ.Subsystem.Прикладные + diff --git "a/src/test/resources/configuration/src/Subsystems/\320\237\320\237\320\230/Subsystems/\320\237\321\200\320\270\320\272\320\273\320\260\320\264\320\275\321\213\320\265/Subsystems/\320\241\320\277\321\200\320\260\320\262\320\276\321\207\320\275\320\270\320\272\320\270/CommandInterface.cmi" "b/src/test/resources/configuration/src/Subsystems/\320\237\320\237\320\230/Subsystems/\320\237\321\200\320\270\320\272\320\273\320\260\320\264\320\275\321\213\320\265/Subsystems/\320\241\320\277\321\200\320\260\320\262\320\276\321\207\320\275\320\270\320\272\320\270/CommandInterface.cmi" new file mode 100644 index 0000000..0cf6de8 --- /dev/null +++ "b/src/test/resources/configuration/src/Subsystems/\320\237\320\237\320\230/Subsystems/\320\237\321\200\320\270\320\272\320\273\320\260\320\264\320\275\321\213\320\265/Subsystems/\320\241\320\277\321\200\320\260\320\262\320\276\321\207\320\275\320\270\320\272\320\270/CommandInterface.cmi" @@ -0,0 +1,2 @@ + + diff --git "a/src/test/resources/configuration/src/Subsystems/\320\237\320\237\320\230/Subsystems/\320\237\321\200\320\270\320\272\320\273\320\260\320\264\320\275\321\213\320\265/Subsystems/\320\241\320\277\321\200\320\260\320\262\320\276\321\207\320\275\320\270\320\272\320\270/\320\241\320\277\321\200\320\260\320\262\320\276\321\207\320\275\320\270\320\272\320\270.mdo" "b/src/test/resources/configuration/src/Subsystems/\320\237\320\237\320\230/Subsystems/\320\237\321\200\320\270\320\272\320\273\320\260\320\264\320\275\321\213\320\265/Subsystems/\320\241\320\277\321\200\320\260\320\262\320\276\321\207\320\275\320\270\320\272\320\270/\320\241\320\277\321\200\320\260\320\262\320\276\321\207\320\275\320\270\320\272\320\270.mdo" new file mode 100644 index 0000000..860a5b2 --- /dev/null +++ "b/src/test/resources/configuration/src/Subsystems/\320\237\320\237\320\230/Subsystems/\320\237\321\200\320\270\320\272\320\273\320\260\320\264\320\275\321\213\320\265/Subsystems/\320\241\320\277\321\200\320\260\320\262\320\276\321\207\320\275\320\270\320\272\320\270/\320\241\320\277\321\200\320\260\320\262\320\276\321\207\320\275\320\270\320\272\320\270.mdo" @@ -0,0 +1,14 @@ + + + Справочники + + ru + Справочники + + true + true + Catalog.Справочник1 + Catalog.Справочник2 + Constant.Константа + Subsystem.ППИ.Subsystem.Прикладные + diff --git "a/src/test/resources/configuration/src/Subsystems/\320\237\320\237\320\230/Subsystems/\320\237\321\200\320\270\320\272\320\273\320\260\320\264\320\275\321\213\320\265/\320\237\321\200\320\270\320\272\320\273\320\260\320\264\320\275\321\213\320\265.mdo" "b/src/test/resources/configuration/src/Subsystems/\320\237\320\237\320\230/Subsystems/\320\237\321\200\320\270\320\272\320\273\320\260\320\264\320\275\321\213\320\265/\320\237\321\200\320\270\320\272\320\273\320\260\320\264\320\275\321\213\320\265.mdo" new file mode 100644 index 0000000..4049130 --- /dev/null +++ "b/src/test/resources/configuration/src/Subsystems/\320\237\320\237\320\230/Subsystems/\320\237\321\200\320\270\320\272\320\273\320\260\320\264\320\275\321\213\320\265/\320\237\321\200\320\270\320\272\320\273\320\260\320\264\320\275\321\213\320\265.mdo" @@ -0,0 +1,15 @@ + + + Прикладные + + ru + Прикладные объекты + + true + true + Constant.Константа1 + Constant.Константа2 + Документы + Справочники + Subsystem.ППИ + diff --git "a/src/test/resources/configuration/src/Subsystems/\320\237\320\237\320\230/Subsystems/\320\241\320\265\321\200\320\262\320\270\321\201\320\275\321\213\320\265/CommandInterface.cmi" "b/src/test/resources/configuration/src/Subsystems/\320\237\320\237\320\230/Subsystems/\320\241\320\265\321\200\320\262\320\270\321\201\320\275\321\213\320\265/CommandInterface.cmi" new file mode 100644 index 0000000..0cf6de8 --- /dev/null +++ "b/src/test/resources/configuration/src/Subsystems/\320\237\320\237\320\230/Subsystems/\320\241\320\265\321\200\320\262\320\270\321\201\320\275\321\213\320\265/CommandInterface.cmi" @@ -0,0 +1,2 @@ + + diff --git "a/src/test/resources/configuration/src/Subsystems/\320\237\320\237\320\230/Subsystems/\320\241\320\265\321\200\320\262\320\270\321\201\320\275\321\213\320\265/\320\241\320\265\321\200\320\262\320\270\321\201\320\275\321\213\320\265.mdo" "b/src/test/resources/configuration/src/Subsystems/\320\237\320\237\320\230/Subsystems/\320\241\320\265\321\200\320\262\320\270\321\201\320\275\321\213\320\265/\320\241\320\265\321\200\320\262\320\270\321\201\320\275\321\213\320\265.mdo" new file mode 100644 index 0000000..690fea9 --- /dev/null +++ "b/src/test/resources/configuration/src/Subsystems/\320\237\320\237\320\230/Subsystems/\320\241\320\265\321\200\320\262\320\270\321\201\320\275\321\213\320\265/\320\241\320\265\321\200\320\262\320\270\321\201\320\275\321\213\320\265.mdo" @@ -0,0 +1,13 @@ + + + Сервисные + + ru + Сервисные методы + + true + true + CommonModule.Преобразования + CommonModule.СтроковыеФункции + Subsystem.ППИ + diff --git "a/src/test/resources/configuration/src/Subsystems/\320\237\320\237\320\230/\320\237\320\237\320\230.mdo" "b/src/test/resources/configuration/src/Subsystems/\320\237\320\237\320\230/\320\237\320\237\320\230.mdo" new file mode 100644 index 0000000..cc6b7e4 --- /dev/null +++ "b/src/test/resources/configuration/src/Subsystems/\320\237\320\237\320\230/\320\237\320\237\320\230.mdo" @@ -0,0 +1,12 @@ + + + ППИ + + ru + ППИ + + true + true + Прикладные + Сервисные + diff --git a/src/test/resources/docs/Hello.md b/src/test/resources/docs/Hello.md new file mode 100644 index 0000000..b2468c7 --- /dev/null +++ b/src/test/resources/docs/Hello.md @@ -0,0 +1 @@ +# Hi \ No newline at end of file diff --git "a/src/test/resources/docs/\320\237\321\200\320\270\320\272\320\273\320\260\320\264\320\275\321\213\320\265/index.md" "b/src/test/resources/docs/\320\237\321\200\320\270\320\272\320\273\320\260\320\264\320\275\321\213\320\265/index.md" new file mode 100644 index 0000000..5a84a5a --- /dev/null +++ "b/src/test/resources/docs/\320\237\321\200\320\270\320\272\320\273\320\260\320\264\320\275\321\213\320\265/index.md" @@ -0,0 +1,5 @@ +# Прикладные объекты + +Основной раздел системы + + \ No newline at end of file