Skip to content

Commit

Permalink
fix: Fixes description indenting (springwolf#691)
Browse files Browse the repository at this point in the history
* fix: Fixes description indenting

When the description field includes a long description it may not be properly rendered, mainly in Kotlin, where the way of managing the text-blocks is different.

 This PR improves the way descriptions are managed by:

 - Removes empty lines at the beginning of the text-block
 - Removes indention due to alignment, but keeps indention in the lines that need it

* Minor documentation improvements

* Renamed DescriptionUtil to TextUtils

* Replaced some algorithms by StringUtils methods

* Replaced some algorithms by StringUtils methods.

Remove unneeded methods

* Added tests. Test coverage to 100%
  • Loading branch information
ctasada authored Apr 19, 2024
1 parent 5f9a5bd commit d7e3175
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import io.github.springwolf.core.asyncapi.scanners.common.payload.PayloadClassExtractor;
import io.github.springwolf.core.asyncapi.scanners.common.utils.AnnotationScannerUtil;
import io.github.springwolf.core.asyncapi.scanners.common.utils.AsyncAnnotationUtil;
import io.github.springwolf.core.asyncapi.scanners.common.utils.TextUtils;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand Down Expand Up @@ -67,6 +68,8 @@ protected Operation buildOperation(AsyncOperation asyncOperation, Method method,
String description = this.resolver.resolveStringValue(asyncOperation.description());
if (!StringUtils.hasText(description)) {
description = "Auto-generated description";
} else {
description = TextUtils.trimIndent(description);
}

String operationTitle = channelName + "_" + this.asyncAnnotationProvider.getOperationType().type;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ public static void processAsyncMessageAnnotation(
StringValueResolver resolver) {
String annotationMessageDescription = resolver.resolveStringValue(asyncMessage.description());
if (StringUtils.hasText(annotationMessageDescription)) {
annotationMessageDescription = TextUtils.trimIndent(annotationMessageDescription);
messageBuilder.description(annotationMessageDescription);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// SPDX-License-Identifier: Apache-2.0
package io.github.springwolf.core.asyncapi.scanners.common.utils;

import org.apache.commons.lang3.StringUtils;

import java.util.Arrays;

/**
* Auxiliary class to manage Description or long texts.
*/
public class TextUtils {
private TextUtils() {}

/**
* This method removes the smallest common indentation from all the lines in the input string,
* and removes it.
* Any leading empty line will be also removed.
*
* @param text The original string with possible leading indentation.
* @return The string with leading indentation removed from each line.
*/
public static String trimIndent(String text) {
if (text == null) {
return null;
}
final String newLine = System.lineSeparator();
String[] lines = text.split(newLine);
int firstNonEmptyLine = findFirstNonEmptyIndex(lines);
if (firstNonEmptyLine == -1) {
return text;
}
lines = Arrays.copyOfRange(lines, firstNonEmptyLine, lines.length);
int minIndent = resolveMinIndent(lines);
var result = Arrays.stream(lines)
.map(line -> line.substring(Math.min(line.length(), minIndent)))
.reduce((a, b) -> a + newLine + b)
.orElse(StringUtils.EMPTY);

if (StringUtils.endsWith(text, "\n")) {
result = result.concat(newLine);
}

return result;
}

/**
* @return The index of the first non-empty line, or {@code -1} if all lines are empty
*/
private static int findFirstNonEmptyIndex(String[] lines) {
for (int i = 0; i < lines.length; i++) {
if (!lines[i].trim().isEmpty()) {
return i;
}
}
return -1;
}

private static int resolveMinIndent(String[] lines) {
return Arrays.stream(lines)
.filter(line -> !line.trim().isEmpty())
.mapToInt(line -> StringUtils.indexOfAnyBut(line, ' '))
.filter(i -> i >= 0)
.min()
.orElse(0);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// SPDX-License-Identifier: Apache-2.0
package io.github.springwolf.core.asyncapi.scanners.common.utils;

import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;

class TextUtilsTest {

@Test
void textWithoutIndentShouldBeUntouched() {
var description = """
This is a string
with two lines
""";

var result = TextUtils.trimIndent(description);

assertThat(result).isEqualTo("This is a string\nwith two lines\n");
}

@Test
void textWithSingleIndentShouldBeUntouched() {
var description = """
This is a string
with two lines
""";

var result = TextUtils.trimIndent(description);

assertThat(result).isEqualTo(" This is a string\nwith two lines\n");
}

@Test
void removeIndent() {
var description =
"""
This is a string
with two lines
""";

var result = TextUtils.trimIndent(description);

assertThat(result).isEqualTo("This is a string\nwith two lines\n");
}

@Test
void simpleTextWithoutIndentShouldBeUntouched() {
var description = "This is a string\nwith two lines";
var result = TextUtils.trimIndent(description);

assertThat(result).isEqualTo("This is a string\nwith two lines");
}

@Test
void removeEmptyLinesUntilTextIsFound() {
var description =
"""
This is a string
with two lines
""";
var result = TextUtils.trimIndent(description);

assertThat(result).isEqualTo("This is a string\n\nwith two lines\n");
}

@Test
void onlyEmptyLinesShouldBeUntouched() {
var description = "\n\n\n";
var result = TextUtils.trimIndent(description);

assertThat(result).isEqualTo("\n\n\n");
}

@Test
void nullTextShouldNotFail() {
String nullDescription = null;
var result = TextUtils.trimIndent(nullDescription);
assertThat(result).isNull();
}
}

0 comments on commit d7e3175

Please sign in to comment.