Skip to content

Commit 1a36552

Browse files
committed
Fix linewrapping, add tests
1 parent 3c637c6 commit 1a36552

File tree

7 files changed

+199
-34
lines changed

7 files changed

+199
-34
lines changed

codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsDocConverter.java

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,19 @@
44
*/
55
package software.amazon.smithy.python.aws.codegen;
66

7-
import software.amazon.smithy.model.shapes.Shape;
8-
import software.amazon.smithy.model.traits.DocumentationTrait;
9-
import software.amazon.smithy.python.codegen.PythonSettings;
10-
import software.amazon.smithy.python.codegen.integrations.PythonIntegration;
11-
import software.amazon.smithy.utils.SmithyInternalApi;
12-
import software.amazon.smithy.model.Model;
13-
import software.amazon.smithy.model.transform.ModelTransformer;
147
import org.jsoup.Jsoup;
158
import org.jsoup.nodes.Document;
169
import org.jsoup.nodes.Element;
1710
import org.jsoup.nodes.Node;
1811
import org.jsoup.nodes.TextNode;
1912
import org.jsoup.select.NodeVisitor;
13+
import software.amazon.smithy.model.Model;
14+
import software.amazon.smithy.model.shapes.Shape;
15+
import software.amazon.smithy.model.traits.DocumentationTrait;
16+
import software.amazon.smithy.model.transform.ModelTransformer;
17+
import software.amazon.smithy.python.codegen.PythonSettings;
18+
import software.amazon.smithy.python.codegen.integrations.PythonIntegration;
19+
import software.amazon.smithy.utils.SmithyInternalApi;
2020

2121
/**
2222
* Add a runtime plugin to convert the HTML docs that are provided by services into
@@ -41,7 +41,7 @@ public Model preprocessModel(Model model, PythonSettings settings) {
4141
});
4242
}
4343

44-
private String convertHtmlToRst(String html) {
44+
String convertHtmlToRst(String html) {
4545
Document document = Jsoup.parse(html);
4646
RstNodeVisitor visitor = new RstNodeVisitor();
4747
document.body().traverse(visitor);
@@ -60,8 +60,8 @@ public void head(Node node, int depth) {
6060
String text = textNode.text();
6161
if (!text.trim().isEmpty()) {
6262
sb.append(text);
63-
// Account for services making a paragraph tag that's empty except
64-
// for a newline
63+
// Account for services making a paragraph tag that's empty except
64+
// for a newline
6565
} else if (node.parent() instanceof Element && ((Element) node.parent()).tagName().equals("p")) {
6666
sb.append(text.replaceAll("[ \\t]+", ""));
6767
}
@@ -98,6 +98,11 @@ public void head(Node node, int depth) {
9898
sb.append(" ".repeat(listDepth - 1)).append("* ");
9999
}
100100
break;
101+
case "h1":
102+
sb.append("\n");
103+
break;
104+
default:
105+
break;
101106
}
102107
}
103108
}
@@ -108,7 +113,7 @@ public void tail(Node node, int depth) {
108113
Element element = (Element) node;
109114
switch (element.tagName()) {
110115
case "a":
111-
sb.append(" <").append(element.attr("href")).append(">`_ ");
116+
sb.append(" <").append(element.attr("href")).append(">`_");
112117
break;
113118
case "b":
114119
case "strong":
@@ -122,15 +127,28 @@ public void tail(Node node, int depth) {
122127
sb.append("``");
123128
break;
124129
case "important":
125-
case "note", "p", "li":
130+
case "note", "p":
126131
sb.append("\n");
127132
break;
128133
case "ul":
129134
listDepth--;
130135
if (listDepth == 0) {
131136
inList = false;
132137
}
133-
sb.append("\n\n");
138+
if (sb.charAt(sb.length() - 1) != '\n') {
139+
sb.append("\n\n");
140+
}
141+
break;
142+
case "li":
143+
if (sb.charAt(sb.length() - 1) != '\n') {
144+
sb.append("\n\n");
145+
}
146+
break;
147+
case "h1":
148+
String title = element.text();
149+
sb.append("\n").append("=".repeat(title.length())).append("\n");
150+
break;
151+
default:
134152
break;
135153
}
136154
}
@@ -141,4 +159,4 @@ public String toString() {
141159
return sb.toString();
142160
}
143161
}
144-
}
162+
}

codegen/aws/core/src/main/java/software/amazon/smithy/python/aws/codegen/AwsRstDocFileGenerator.java

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
*/
55
package software.amazon.smithy.python.aws.codegen;
66

7+
import static software.amazon.smithy.python.codegen.SymbolProperties.OPERATION_METHOD;
8+
9+
import java.util.List;
710
import software.amazon.smithy.model.traits.InputTrait;
811
import software.amazon.smithy.model.traits.OutputTrait;
912
import software.amazon.smithy.python.codegen.GenerationContext;
@@ -13,9 +16,6 @@
1316
import software.amazon.smithy.utils.CodeInterceptor;
1417
import software.amazon.smithy.utils.CodeSection;
1518

16-
import java.util.ArrayList;
17-
import java.util.List;
18-
1919
public class AwsRstDocFileGenerator implements PythonIntegration {
2020

2121
@Override
@@ -27,8 +27,7 @@ public List<? extends CodeInterceptor<? extends CodeSection, PythonWriter>> inte
2727
new StructureGenerationInterceptor(context),
2828
new ErrorGenerationInterceptor(context),
2929
new UnionGenerationInterceptor(context),
30-
new UnionMemberGenerationInterceptor(context)
31-
);
30+
new UnionMemberGenerationInterceptor(context));
3231
}
3332

3433
/**
@@ -38,7 +37,7 @@ public List<? extends CodeInterceptor<? extends CodeSection, PythonWriter>> inte
3837
* @return A formatted header string.
3938
*/
4039
private static String generateHeader(String title) {
41-
return String.format("%s\n%s\n\n", title, "=".repeat(title.length()));
40+
return String.format("%s%n%s%n%n", title, "=".repeat(title.length()));
4241
}
4342

4443
private static final class OperationGenerationInterceptor
@@ -58,7 +57,7 @@ public Class<OperationSection> sectionType() {
5857
@Override
5958
public void append(PythonWriter pythonWriter, OperationSection section) {
6059
var operation = section.operation();
61-
var operationSymbol = context.symbolProvider().toSymbol(operation);
60+
var operationSymbol = context.symbolProvider().toSymbol(operation).expectProperty(OPERATION_METHOD);
6261
var input = context.model().expectShape(operation.getInputShape());
6362
var inputSymbol = context.symbolProvider().toSymbol(input);
6463
var output = context.model().expectShape(operation.getOutputShape());
@@ -158,12 +157,12 @@ public Class<UnionSection> sectionType() {
158157
@Override
159158
public void append(PythonWriter pythonWriter, UnionSection section) {
160159
String parentName = section.parentName();
161-
ArrayList<String> memberNames = section.memberNames();
162160
String docsFileName = String.format("docs/models/%s.rst", parentName);
163161
context.writerDelegator().useFileWriter(docsFileName, "", writer -> {
164162
writer.write(".. _" + parentName + ":\n\n");
165163
writer.write(generateHeader(parentName));
166-
writer.write(".. autodata:: " + context.symbolProvider().toSymbol(section.unionShape()).toString() + " \n");
164+
writer.write(
165+
".. autodata:: " + context.symbolProvider().toSymbol(section.unionShape()).toString() + " \n");
167166
});
168167
}
169168
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
package software.amazon.smithy.python.aws.codegen;
6+
7+
import static org.junit.jupiter.api.Assertions.assertEquals;
8+
9+
import org.junit.jupiter.api.BeforeEach;
10+
import org.junit.jupiter.api.Test;
11+
12+
public class AwsDocConverterTest {
13+
14+
private AwsDocConverter awsDocConverter;
15+
16+
@BeforeEach
17+
public void setUp() {
18+
awsDocConverter = new AwsDocConverter();
19+
}
20+
21+
@Test
22+
public void testConvertHtmlToRstWithTitleAndParagraph() {
23+
String html = "<html><body><h1>Title</h1><p>Paragraph</p></body></html>";
24+
String expected = "\n\nTitle\n=====\nParagraph\n";
25+
String result = awsDocConverter.convertHtmlToRst(html);
26+
assertEquals(expected, result);
27+
}
28+
29+
@Test
30+
public void testConvertHtmlToRstWithImportantNote() {
31+
String html = "<html><body><important>Important note</important></body></html>";
32+
String expected = "\n\n.. important::\n Important note\n";
33+
String result = awsDocConverter.convertHtmlToRst(html);
34+
assertEquals(expected, result);
35+
}
36+
37+
@Test
38+
public void testConvertHtmlToRstWithList() {
39+
String html = "<html><body><ul><li>Item 1</li><li>Item 2</li></ul></body></html>";
40+
String expected = "\n\n* Item 1\n\n* Item 2\n\n";
41+
String result = awsDocConverter.convertHtmlToRst(html);
42+
assertEquals(expected, result);
43+
}
44+
45+
@Test
46+
public void testConvertHtmlToRstWithMixedElements() {
47+
String html = "<html><body><h1>Title</h1><p>Paragraph</p><ul><li>Item 1</li><li>Item 2</li></ul></body></html>";
48+
String expected = "\n\nTitle\n=====\nParagraph\n\n* Item 1\n\n* Item 2\n\n";
49+
String result = awsDocConverter.convertHtmlToRst(html);
50+
assertEquals(expected, result);
51+
}
52+
53+
@Test
54+
public void testConvertHtmlToRstWithNestedElements() {
55+
String html = "<html><body><h1>Title</h1><p>Paragraph with <strong>bold</strong> text</p></body></html>";
56+
String expected = "\n\nTitle\n=====\nParagraph with **bold** text\n";
57+
String result = awsDocConverter.convertHtmlToRst(html);
58+
assertEquals(expected, result);
59+
}
60+
61+
@Test
62+
public void testConvertHtmlToRstWithAnchorTag() {
63+
String html = "<html><body><a href='https://example.com'>Link</a></body></html>";
64+
String expected = "\n`Link <https://example.com>`_";
65+
String result = awsDocConverter.convertHtmlToRst(html);
66+
assertEquals(expected, result);
67+
}
68+
69+
@Test
70+
public void testConvertHtmlToRstWithBoldTag() {
71+
String html = "<html><body><b>Bold text</b></body></html>";
72+
String expected = "\n**Bold text**";
73+
String result = awsDocConverter.convertHtmlToRst(html);
74+
assertEquals(expected, result);
75+
}
76+
77+
@Test
78+
public void testConvertHtmlToRstWithItalicTag() {
79+
String html = "<html><body><i>Italic text</i></body></html>";
80+
String expected = "\n*Italic text*";
81+
String result = awsDocConverter.convertHtmlToRst(html);
82+
assertEquals(expected, result);
83+
}
84+
85+
@Test
86+
public void testConvertHtmlToRstWithCodeTag() {
87+
String html = "<html><body><code>code snippet</code></body></html>";
88+
String expected = "\n``code snippet``";
89+
String result = awsDocConverter.convertHtmlToRst(html);
90+
assertEquals(expected, result);
91+
}
92+
93+
@Test
94+
public void testConvertHtmlToRstWithNoteTag() {
95+
String html = "<html><body><note>Note text</note></body></html>";
96+
String expected = "\n\n.. note::\n Note text\n";
97+
String result = awsDocConverter.convertHtmlToRst(html);
98+
assertEquals(expected, result);
99+
}
100+
101+
@Test
102+
public void testConvertHtmlToRstWithNestedList() {
103+
String html = "<html><body><ul><li>Item 1<ul><li>Subitem 1</li></ul></li><li>Item 2</li></ul></body></html>";
104+
String expected = "\n\n* Item 1\n * Subitem 1\n\n* Item 2\n\n";
105+
String result = awsDocConverter.convertHtmlToRst(html);
106+
assertEquals(expected, result);
107+
}
108+
}

codegen/core/src/main/java/software/amazon/smithy/python/codegen/PythonDependency.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,10 @@ public enum Type {
6060
DEPENDENCY("dependency"),
6161

6262
/** A dependency only used for testing purposes. */
63-
TEST_DEPENDENCY("testDependency");
63+
TEST_DEPENDENCY("testDependency"),
64+
65+
/** A dependency only used for docs generation. */
66+
DOCS_DEPENDENCY("docsDependency");
6467

6568
private final String type;
6669

codegen/core/src/main/java/software/amazon/smithy/python/codegen/SmithyPythonDependency.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,24 @@ public final class SmithyPythonDependency {
102102
Type.TEST_DEPENDENCY,
103103
false);
104104

105+
/**
106+
* library used for documentation generation
107+
*/
108+
public static final PythonDependency SPHINX = new PythonDependency(
109+
"sphinx",
110+
">=8.2.3",
111+
Type.DOCS_DEPENDENCY,
112+
false);
113+
114+
/**
115+
* sphinx theme
116+
*/
117+
public static final PythonDependency SPHINX_PYDATA_THEME = new PythonDependency(
118+
"pydata-sphinx-theme",
119+
">=0.16.1",
120+
Type.DOCS_DEPENDENCY,
121+
false);
122+
105123
private SmithyPythonDependency() {}
106124

107125
/**

codegen/core/src/main/java/software/amazon/smithy/python/codegen/generators/SetupGenerator.java

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,7 @@
2020
import software.amazon.smithy.model.traits.DocumentationTrait;
2121
import software.amazon.smithy.model.traits.StringTrait;
2222
import software.amazon.smithy.model.traits.TitleTrait;
23-
import software.amazon.smithy.python.codegen.GenerationContext;
24-
import software.amazon.smithy.python.codegen.PythonDependency;
25-
import software.amazon.smithy.python.codegen.PythonSettings;
26-
import software.amazon.smithy.python.codegen.SymbolProperties;
23+
import software.amazon.smithy.python.codegen.*;
2724
import software.amazon.smithy.python.codegen.sections.PyprojectSection;
2825
import software.amazon.smithy.python.codegen.sections.ReadmeSection;
2926
import software.amazon.smithy.python.codegen.writer.PythonWriter;
@@ -42,10 +39,10 @@ public static void generateSetup(
4239
PythonSettings settings,
4340
GenerationContext context
4441
) {
42+
writeDocsSkeleton(settings, context);
4543
var dependencies = gatherDependencies(context.writerDelegator().getDependencies().stream());
4644
writePyproject(settings, context.writerDelegator(), dependencies);
4745
writeReadme(settings, context);
48-
writeDocsSkeleton(settings, context);
4946
}
5047

5148
/**
@@ -150,9 +147,24 @@ private static void writePyproject(
150147
writer.openBlock("dependencies = [", "]", () -> writeDependencyList(writer, deps.values()));
151148
});
152149

153-
Optional.ofNullable(dependencies.get(PythonDependency.Type.TEST_DEPENDENCY.getType())).ifPresent(deps -> {
150+
Optional<Collection<SymbolDependency>> testDeps =
151+
Optional.ofNullable(dependencies.get(PythonDependency.Type.TEST_DEPENDENCY.getType()))
152+
.map(Map::values);
153+
154+
Optional<Collection<SymbolDependency>> docsDeps =
155+
Optional.ofNullable(dependencies.get(PythonDependency.Type.DOCS_DEPENDENCY.getType()))
156+
.map(Map::values);
157+
158+
if (testDeps.isPresent() || docsDeps.isPresent()) {
154159
writer.write("[project.optional-dependencies]");
155-
writer.openBlock("tests = [", "]", () -> writeDependencyList(writer, deps.values()));
160+
}
161+
162+
testDeps.ifPresent(deps -> {
163+
writer.openBlock("tests = [", "]", () -> writeDependencyList(writer, deps));
164+
});
165+
166+
docsDeps.ifPresent(deps -> {
167+
writer.openBlock("docs = [", "]", () -> writeDependencyList(writer, deps));
156168
});
157169

158170
// TODO: remove the pyright global suppressions after the serde redo is done
@@ -254,7 +266,14 @@ private static void writeReadme(
254266
/**
255267
* Write the files required for sphinx doc generation
256268
*/
257-
private static void writeDocsSkeleton(PythonSettings settings, GenerationContext context) {
269+
private static void writeDocsSkeleton(
270+
PythonSettings settings,
271+
GenerationContext context
272+
) {
273+
context.writerDelegator().useFileWriter("pyproject.toml", "", writer -> {
274+
writer.addDependency(SmithyPythonDependency.SPHINX);
275+
writer.addDependency(SmithyPythonDependency.SPHINX_PYDATA_THEME);
276+
});
258277
writeConf(settings, context);
259278
writeMakeBat(context);
260279
writeMakeFile(context);

codegen/core/src/main/java/software/amazon/smithy/python/codegen/writer/PythonWriter.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -191,9 +191,9 @@ private static int findWrapPosition(String line, int maxLineLength) {
191191
// Ensure we don't break a link
192192
int linkStart = line.lastIndexOf("`", wrapAt);
193193
int linkEnd = line.indexOf("`_", wrapAt);
194-
if (linkStart != -1 && (linkEnd == -1 || linkEnd < linkStart)) {
194+
if (linkStart != -1 && (linkEnd != -1 && linkEnd > linkStart)) {
195195
linkEnd = line.indexOf("`_", linkStart);
196-
if (linkEnd != -1 && linkEnd <= maxLineLength) {
196+
if (linkEnd != -1) {
197197
wrapAt = linkEnd + 2;
198198
} else {
199199
// No matching `_` found, keep the original wrap position

0 commit comments

Comments
 (0)