1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package gov.nist.secauto.metaschema.core.datatype.markup.flexmark;
28
29 import com.vladsch.flexmark.ast.AutoLink;
30 import com.vladsch.flexmark.ast.BlockQuote;
31 import com.vladsch.flexmark.ast.BulletList;
32 import com.vladsch.flexmark.ast.Code;
33 import com.vladsch.flexmark.ast.CodeBlock;
34 import com.vladsch.flexmark.ast.Emphasis;
35 import com.vladsch.flexmark.ast.FencedCodeBlock;
36 import com.vladsch.flexmark.ast.HardLineBreak;
37 import com.vladsch.flexmark.ast.Heading;
38 import com.vladsch.flexmark.ast.HtmlBlock;
39 import com.vladsch.flexmark.ast.HtmlCommentBlock;
40 import com.vladsch.flexmark.ast.HtmlEntity;
41 import com.vladsch.flexmark.ast.HtmlInline;
42 import com.vladsch.flexmark.ast.Image;
43 import com.vladsch.flexmark.ast.IndentedCodeBlock;
44 import com.vladsch.flexmark.ast.Link;
45 import com.vladsch.flexmark.ast.LinkRef;
46 import com.vladsch.flexmark.ast.ListItem;
47 import com.vladsch.flexmark.ast.MailLink;
48 import com.vladsch.flexmark.ast.OrderedList;
49 import com.vladsch.flexmark.ast.Paragraph;
50 import com.vladsch.flexmark.ast.Reference;
51 import com.vladsch.flexmark.ast.SoftLineBreak;
52 import com.vladsch.flexmark.ast.StrongEmphasis;
53 import com.vladsch.flexmark.ast.Text;
54 import com.vladsch.flexmark.ast.TextBase;
55 import com.vladsch.flexmark.ast.ThematicBreak;
56 import com.vladsch.flexmark.ext.gfm.strikethrough.Subscript;
57 import com.vladsch.flexmark.ext.superscript.Superscript;
58 import com.vladsch.flexmark.ext.tables.TableBlock;
59 import com.vladsch.flexmark.ext.typographic.TypographicQuotes;
60 import com.vladsch.flexmark.ext.typographic.TypographicSmarts;
61 import com.vladsch.flexmark.util.ast.Block;
62 import com.vladsch.flexmark.util.ast.Document;
63 import com.vladsch.flexmark.util.ast.Node;
64
65 import gov.nist.secauto.metaschema.core.datatype.markup.flexmark.InsertAnchorExtension.InsertAnchorNode;
66 import gov.nist.secauto.metaschema.core.util.ObjectUtils;
67
68 import edu.umd.cs.findbugs.annotations.NonNull;
69 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
70
71
72
73
74
75
76
77
78
79
80 @SuppressFBWarnings("THROWS_METHOD_THROWS_CLAUSE_THROWABLE")
81 public class MarkupVisitor<T, E extends Throwable> implements IMarkupVisitor<T, E> {
82 private final boolean handleBlockElements;
83
84 public MarkupVisitor(boolean handleBlockElements) {
85 this.handleBlockElements = handleBlockElements;
86 }
87
88 protected boolean isHandleBlockElements() {
89 return handleBlockElements;
90 }
91
92 @Override
93 public void visitDocument(Document document, IMarkupWriter<T, E> writer) throws E {
94 visitChildren(document, writer);
95 }
96
97 protected void visitChildren(@NonNull Node parentNode, @NonNull IMarkupWriter<T, E> writer) throws E {
98 for (Node node : parentNode.getChildren()) {
99 assert node != null;
100 visit(node, writer);
101 }
102 }
103
104 protected void visit(@NonNull Node node, @NonNull IMarkupWriter<T, E> writer) throws E {
105 boolean handled = processInlineElements(node, writer);
106 if (!handled && node instanceof Block) {
107 if (isHandleBlockElements()) {
108 handled = processBlockElements(node, writer);
109 } else {
110 visitChildren(node, writer);
111 handled = true;
112 }
113 }
114
115 if (!handled) {
116 throw new UnsupportedOperationException(
117 String.format("Node '%s' not handled. AST: %s", node.getNodeName(), node.toAstString(true)));
118 }
119 }
120
121 protected boolean processInlineElements(
122 @NonNull Node node,
123 @NonNull IMarkupWriter<T, E> writer) throws E {
124 boolean retval = true;
125 if (node instanceof Text) {
126 writer.writeText((Text) node);
127 } else if (node instanceof TextBase) {
128 writer.writeText((TextBase) node);
129 } else if (node instanceof HtmlEntity) {
130 writer.writeHtmlEntity((HtmlEntity) node);
131 } else if (node instanceof TypographicSmarts) {
132 writer.writeHtmlEntity((TypographicSmarts) node);
133 } else if (node instanceof TypographicQuotes) {
134 writer.writeTypographicQuotes((TypographicQuotes) node, this::visit);
135 } else if (node instanceof Code) {
136 writer.writeCode((Code) node, this::visit);
137 } else if (node instanceof StrongEmphasis) {
138 writer.writeElement("strong", node, this::visit);
139 } else if (node instanceof Emphasis) {
140 writer.writeElement("em", node, this::visit);
141 } else if (node instanceof ListItem) {
142 writer.writeElement("li", node, this::visit);
143 } else if (node instanceof Link) {
144 writer.writeLink((Link) node, this::visit);
145 } else if (node instanceof AutoLink) {
146 writer.writeLink((AutoLink) node);
147 } else if (node instanceof MailLink) {
148 writer.writeLink((MailLink) node);
149 } else if (node instanceof Subscript) {
150 writer.writeElement("sub", node, this::visit);
151 } else if (node instanceof Superscript) {
152 writer.writeElement("sup", node, this::visit);
153 } else if (node instanceof Image) {
154 writer.writeImage((Image) node);
155 } else if (node instanceof InsertAnchorNode) {
156 writer.writeInsertAnchor((InsertAnchorNode) node);
157 } else if (node instanceof SoftLineBreak) {
158 writer.writeText("\n");
159 } else if (node instanceof HardLineBreak) {
160 writer.writeBreak((HardLineBreak) node);
161 } else if (node instanceof HtmlInline) {
162 writer.writeInlineHtml((HtmlInline) node);
163 } else if (node instanceof LinkRef || node instanceof Reference) {
164 throw new UnsupportedOperationException(
165 String.format(
166 "Link references are not supported by Metaschema."
167 + " Perhaps you have an unescaped bracket in the following string? %s",
168 ObjectUtils.notNull(node.getParent()).getChars()));
169 } else {
170 retval = false;
171 }
172 return retval;
173 }
174
175 protected boolean processBlockElements(
176 @NonNull Node node,
177 @NonNull IMarkupWriter<T, E> writer) throws E {
178 boolean retval = true;
179 if (node instanceof Paragraph) {
180 writer.writeParagraph((Paragraph) node, this::visit);
181 } else if (node instanceof Heading) {
182 writer.writeHeading((Heading) node, this::visit);
183 } else if (node instanceof OrderedList) {
184 writer.writeList("ol", (OrderedList) node, this::visit);
185 } else if (node instanceof BulletList) {
186 writer.writeList("ul", (BulletList) node, this::visit);
187 } else if (node instanceof TableBlock) {
188 writer.writeTable((TableBlock) node, this::visit);
189 } else if (node instanceof HtmlBlock) {
190 writer.writeBlockHtml((HtmlBlock) node);
191 } else if (node instanceof HtmlCommentBlock) {
192 writer.writeComment((HtmlCommentBlock) node);
193 } else if (node instanceof IndentedCodeBlock) {
194 writer.writeCodeBlock((IndentedCodeBlock) node, this::visit);
195 } else if (node instanceof FencedCodeBlock) {
196 writer.writeCodeBlock((FencedCodeBlock) node, this::visit);
197 } else if (node instanceof CodeBlock) {
198 writer.writeCodeBlock((CodeBlock) node, this::visit);
199 } else if (node instanceof BlockQuote) {
200 writer.writeBlockQuote((BlockQuote) node, this::visit);
201 } else if (node instanceof ThematicBreak) {
202 writer.writeBreak((ThematicBreak) node);
203 } else {
204 retval = false;
205 }
206
207
208
209
210 return retval;
211 }
212 }