Skip to content

Commit fa9664b

Browse files
committed
- better implementation for summary/description doc
- Add GET adoc function shortcut for operation
1 parent 66c7594 commit fa9664b

File tree

9 files changed

+372
-41
lines changed

9 files changed

+372
-41
lines changed

modules/jooby-openapi/src/main/java/io/jooby/internal/openapi/asciidoc/Functions.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,19 @@
1515
import io.pebbletemplates.pebble.template.PebbleTemplate;
1616

1717
public enum Functions implements Function {
18+
GET {
19+
@Override
20+
public List<String> getArgumentNames() {
21+
return List.of("pattern");
22+
}
23+
24+
@Override
25+
public Object execute(
26+
Map<String, Object> args, PebbleTemplate self, EvaluationContext context, int lineNumber) {
27+
args.put("identifier", name());
28+
return operation.execute(args, self, context, lineNumber);
29+
}
30+
},
1831
operation {
1932
@Override
2033
public List<String> getArgumentNames() {

modules/jooby-openapi/src/main/java/io/jooby/internal/openapi/asciidoc/OperationFilters.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ protected String doApply(
146146
});
147147
}
148148
},
149-
httpRequest {
149+
request {
150150
@Override
151151
protected String doApply(
152152
SnippetResolver resolver,
@@ -191,7 +191,7 @@ protected String doApply(
191191
return resolver.apply(id(), snippetContext);
192192
}
193193
},
194-
httpResponse {
194+
response {
195195
@Override
196196
protected String doApply(
197197
SnippetResolver resolver,
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
/*
2+
* Jooby https://jooby.io
3+
* Apache License Version 2.0 https://jooby.io/LICENSE.txt
4+
* Copyright 2014 Edgar Espina
5+
*/
6+
package io.jooby.internal.openapi.javadoc;
7+
8+
public class ContentSplitter {
9+
10+
public record ContentResult(String summary, String description) {}
11+
12+
public static ContentResult split(String text) {
13+
if (text == null || text.isEmpty()) {
14+
return new ContentResult("", "");
15+
}
16+
17+
int len = text.length();
18+
int splitIndex = -1;
19+
20+
// State trackers
21+
int parenDepth = 0; // ( )
22+
int bracketDepth = 0; // [ ]
23+
int braceDepth = 0; // { }
24+
boolean inHtmlDef = false; // < ... >
25+
boolean inCodeBlock = false; // <pre>...</pre> or <code>...</code>
26+
27+
for (int i = 0; i < len; i++) {
28+
char c = text.charAt(i);
29+
30+
// 1. Handle HTML Tags start
31+
if (c == '<') {
32+
// Check for <p> (Paragraph Split - Exclusive)
33+
if (!inCodeBlock && !inHtmlDef && isTag(text, i, "p")) {
34+
splitIndex = i;
35+
break;
36+
}
37+
// Check for Protected Blocks (<pre>, <code>)
38+
if (!inCodeBlock && (isTag(text, i, "pre") || isTag(text, i, "code"))) {
39+
inCodeBlock = true;
40+
}
41+
// Check for end of Protected Blocks
42+
if (inCodeBlock && (isCloseTag(text, i, "pre") || isCloseTag(text, i, "code"))) {
43+
inCodeBlock = false;
44+
}
45+
inHtmlDef = true;
46+
continue;
47+
}
48+
49+
// 2. Handle HTML Tags end
50+
if (c == '>') {
51+
inHtmlDef = false;
52+
continue;
53+
}
54+
55+
// 3. Handle Nesting & Split
56+
if (!inHtmlDef && !inCodeBlock) {
57+
if (c == '(') {
58+
parenDepth++;
59+
} else if (c == ')') {
60+
if (parenDepth > 0) parenDepth--;
61+
} else if (c == '[') {
62+
bracketDepth++;
63+
} else if (c == ']') {
64+
if (bracketDepth > 0) bracketDepth--;
65+
} else if (c == '{') {
66+
braceDepth++;
67+
} else if (c == '}') {
68+
if (braceDepth > 0) braceDepth--;
69+
}
70+
// 4. Check for Period
71+
else if (c == '.') {
72+
if (parenDepth == 0 && bracketDepth == 0 && braceDepth == 0) {
73+
splitIndex = i + 1;
74+
break;
75+
}
76+
}
77+
}
78+
}
79+
80+
String summary;
81+
String description;
82+
83+
if (splitIndex == -1) {
84+
summary = text.trim();
85+
description = "";
86+
} else {
87+
summary = text.substring(0, splitIndex).trim();
88+
description = text.substring(splitIndex).trim();
89+
}
90+
91+
// Clean up: Strip <p> tags without using Regex
92+
return new ContentResult(stripParagraphTags(summary), stripParagraphTags(description));
93+
}
94+
95+
/**
96+
* Removes
97+
*
98+
* <p>and tags (and their attributes) from the text. Keeps content inside the tags.
99+
*/
100+
private static String stripParagraphTags(String text) {
101+
if (text.isEmpty()) return text;
102+
103+
StringBuilder sb = new StringBuilder(text.length());
104+
int len = text.length();
105+
106+
for (int i = 0; i < len; i++) {
107+
char c = text.charAt(i);
108+
109+
if (c == '<') {
110+
// Detect <p...> or </p...>
111+
if (isTag(text, i, "p") || isCloseTag(text, i, "p")) {
112+
// Fast-forward until we find the closing '>'
113+
while (i < len && text.charAt(i) != '>') {
114+
i++;
115+
}
116+
// We are now at '>', loop increment will move past it
117+
continue;
118+
}
119+
}
120+
sb.append(c);
121+
}
122+
return sb.toString().trim();
123+
}
124+
125+
// --- Helper Methods ---
126+
127+
private static boolean isTag(String text, int i, String tagName) {
128+
int len = tagName.length();
129+
if (i + 1 + len > text.length()) return false;
130+
131+
// Match tagName (case insensitive)
132+
for (int k = 0; k < len; k++) {
133+
char c = text.charAt(i + 1 + k);
134+
if (Character.toLowerCase(c) != tagName.charAt(k)) return false;
135+
}
136+
137+
// Check delimiter (must be '>' or whitespace or end of string)
138+
if (i + 1 + len == text.length()) return true;
139+
char delimiter = text.charAt(i + 1 + len);
140+
return delimiter == '>' || Character.isWhitespace(delimiter);
141+
}
142+
143+
private static boolean isCloseTag(String text, int i, String tagName) {
144+
int len = tagName.length();
145+
if (i + 2 + len > text.length()) return false;
146+
if (text.charAt(i + 1) != '/') return false;
147+
148+
// Match tagName (case insensitive)
149+
for (int k = 0; k < len; k++) {
150+
char c = text.charAt(i + 2 + k);
151+
if (Character.toLowerCase(c) != tagName.charAt(k)) return false;
152+
}
153+
154+
// Check delimiter
155+
char delimiter = text.charAt(i + 2 + len);
156+
return delimiter == '>' || Character.isWhitespace(delimiter);
157+
}
158+
}

modules/jooby-openapi/src/main/java/io/jooby/internal/openapi/javadoc/JavaDocNode.java

Lines changed: 10 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -55,42 +55,17 @@ public Map<String, Object> getExtensions() {
5555
}
5656

5757
public String getSummary() {
58-
var builder = new StringBuilder();
59-
for (var node : forward(javadoc, JAVADOC_TAG).toList()) {
60-
if (node.getType() == JavadocCommentsTokenTypes.TEXT) {
61-
var text = node.getText();
62-
var trimmed = text.trim();
63-
if (trimmed.isEmpty()) {
64-
if (!builder.isEmpty()) {
65-
builder.append(text);
66-
}
67-
} else {
68-
builder.append(text);
69-
}
70-
} else if (node.getType() == JavadocCommentsTokenTypes.NEWLINE && !builder.isEmpty()) {
71-
break;
72-
}
73-
var index = builder.indexOf(".");
74-
if (index > 0) {
75-
builder.setLength(index + 1);
76-
break;
77-
}
78-
}
79-
var string = builder.toString().trim();
80-
return string.isEmpty() ? null : string;
58+
var summary = ContentSplitter.split(getText()).summary();
59+
return summary.isEmpty() ? null : summary;
8160
}
8261

8362
public List<Tag> getTags() {
8463
return tags;
8564
}
8665

8766
public String getDescription() {
88-
var text = getText();
89-
var summary = getSummary();
90-
if (summary == null) {
91-
return text;
92-
}
93-
return summary.equals(text) ? null : text.replaceAll(summary, "").trim();
67+
var description = ContentSplitter.split(getText()).description();
68+
return description.isEmpty() ? null : description;
9469
}
9570

9671
public String getText() {
@@ -143,7 +118,12 @@ protected static String getText(List<DetailNode> nodes, boolean stripLeading) {
143118
if (next != null && next.getType() != JavadocCommentsTokenTypes.LEADING_ASTERISK) {
144119
builder.append(next.getText());
145120
visited.add(next);
146-
// visited.add(next.getNextSibling());
121+
}
122+
} else if (node.getType() == JavadocCommentsTokenTypes.TAG_NAME) {
123+
// <p>?
124+
if (node.getText().equals("p")) {
125+
// keep so we can split summary from description
126+
builder.append("<p>");
147127
}
148128
}
149129
}

modules/jooby-openapi/src/main/resources/io/jooby/openapi/templates/asciidoc/default-http-request.snippet renamed to modules/jooby-openapi/src/main/resources/io/jooby/openapi/templates/asciidoc/default-request.snippet

File renamed without changes.

modules/jooby-openapi/src/main/resources/io/jooby/openapi/templates/asciidoc/default-http-response.snippet renamed to modules/jooby-openapi/src/main/resources/io/jooby/openapi/templates/asciidoc/default-response.snippet

File renamed without changes.

modules/jooby-openapi/src/test/java/io/jooby/internal/openapi/asciidoc/FilterTest.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,7 @@ public void curl() {
394394
@Test
395395
public void httpRequest() {
396396
assertThat(
397-
httpRequest.apply(
397+
request.apply(
398398
operation("GET", "/api/library/{isbn}").build(),
399399
args(),
400400
template(),
@@ -409,7 +409,7 @@ public void httpRequest() {
409409
""");
410410

411411
assertThat(
412-
httpRequest.apply(
412+
request.apply(
413413
operation("GET", "/api/library/{isbn}").produces("application/json").build(),
414414
args(),
415415
template(),
@@ -425,7 +425,7 @@ public void httpRequest() {
425425
""");
426426

427427
assertThat(
428-
httpRequest.apply(
428+
request.apply(
429429
operation("POST", "/api/library").body(new Book(), "application/json").build(),
430430
args(),
431431
template(),
@@ -445,7 +445,7 @@ public void httpRequest() {
445445
@Test
446446
public void httpResponse() {
447447
assertThat(
448-
httpResponse.apply(
448+
response.apply(
449449
operation("GET", "/api/library/{isbn}").defaultResponse().build(),
450450
args(),
451451
template(),
@@ -460,7 +460,7 @@ public void httpResponse() {
460460
""");
461461

462462
assertThat(
463-
httpResponse.apply(
463+
response.apply(
464464
operation("GET", "/api/library/{isbn}")
465465
.defaultResponse()
466466
.produces("application/json")
@@ -479,7 +479,7 @@ public void httpResponse() {
479479
""");
480480

481481
assertThat(
482-
httpResponse.apply(
482+
response.apply(
483483
operation("POST", "/api/library")
484484
.produces("application/json")
485485
.response(new Book(), StatusCode.CREATED, "application/json")
@@ -499,7 +499,7 @@ public void httpResponse() {
499499
""");
500500

501501
assertThat(
502-
httpResponse.apply(
502+
response.apply(
503503
operation("POST", "/api/library")
504504
.produces("application/json")
505505
.response(new Book(), StatusCode.CREATED, "application/json")
@@ -519,7 +519,7 @@ public void httpResponse() {
519519
""");
520520

521521
assertThat(
522-
httpResponse.apply(
522+
response.apply(
523523
operation("POST", "/api/library")
524524
.produces("application/json")
525525
.response(new Book(), StatusCode.CREATED, "application/json")

0 commit comments

Comments
 (0)