001/*
002 * Portions of this software was developed by employees of the National Institute
003 * of Standards and Technology (NIST), an agency of the Federal Government and is
004 * being made available as a public service. Pursuant to title 17 United States
005 * Code Section 105, works of NIST employees are not subject to copyright
006 * protection in the United States. This software may be subject to foreign
007 * copyright. Permission in the United States and in foreign countries, to the
008 * extent that NIST may hold copyright, to use, copy, modify, create derivative
009 * works, and distribute this software and its documentation without fee is hereby
010 * granted on a non-exclusive basis, provided that this notice and disclaimer
011 * of warranty appears in all copies.
012 *
013 * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER
014 * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY
015 * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF
016 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM
017 * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE
018 * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE.  IN NO EVENT
019 * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT,
020 * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM,
021 * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY,
022 * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR
023 * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT
024 * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER.
025 */
026
027package gov.nist.secauto.metaschema.core.datatype.markup.flexmark;
028
029import com.vladsch.flexmark.ext.escaped.character.EscapedCharacterExtension;
030import com.vladsch.flexmark.ext.gfm.strikethrough.SubscriptExtension;
031import com.vladsch.flexmark.ext.superscript.SuperscriptExtension;
032import com.vladsch.flexmark.ext.tables.TablesExtension;
033import com.vladsch.flexmark.ext.typographic.TypographicExtension;
034import com.vladsch.flexmark.formatter.Formatter;
035import com.vladsch.flexmark.html.HtmlRenderer;
036import com.vladsch.flexmark.html2md.converter.FlexmarkHtmlConverter;
037import com.vladsch.flexmark.parser.Parser;
038import com.vladsch.flexmark.parser.ParserEmulationProfile;
039import com.vladsch.flexmark.util.data.DataHolder;
040import com.vladsch.flexmark.util.data.DataSet;
041import com.vladsch.flexmark.util.data.MutableDataSet;
042import com.vladsch.flexmark.util.format.options.ListBulletMarker;
043import com.vladsch.flexmark.util.misc.Extension;
044
045import java.util.List;
046import java.util.Map;
047import java.util.concurrent.ConcurrentHashMap;
048
049import edu.umd.cs.findbugs.annotations.NonNull;
050import edu.umd.cs.findbugs.annotations.Nullable;
051
052public final class FlexmarkConfiguration {
053
054  @NonNull
055  private static final ParserEmulationProfile PARSER_PROFILE = ParserEmulationProfile.COMMONMARK_0_29;
056
057  @NonNull
058  public static final DataSet FLEXMARK_CONFIG = initFlexmarkConfig();
059
060  @SuppressWarnings("null")
061  @NonNull
062  private static DataSet initFlexmarkConfig() {
063    MutableDataSet options = new MutableDataSet();
064    options.setFrom(PARSER_PROFILE);
065
066    List<Extension> extensions = List.of(
067        // Metaschema insert
068        InsertAnchorExtension.create(),
069        // q tag handling
070        HtmlQuoteTagExtension.create(),
071        TypographicExtension.create(),
072        TablesExtension.create(),
073        // fix for code handling
074        HtmlCodeRenderExtension.create(),
075        // to ensure that escaped characters are not lost
076        EscapedCharacterExtension.create(),
077        SuperscriptExtension.create(),
078        SubscriptExtension.create()
079    // AutolinkExtension.create()
080    );
081    Parser.EXTENSIONS.set(options, extensions);
082
083    // AST processing expects this
084    Parser.FENCED_CODE_CONTENT_BLOCK.set(options, true);
085    // Parser.CODE_SOFT_LINE_BREAKS.set(options, true);
086    // Parser.PARSE_INNER_HTML_COMMENTS.set(options, true);
087    // Parser.HTML_BLOCK_COMMENT_ONLY_FULL_LINE.set(options, true);
088    // Parser.HTML_COMMENT_BLOCKS_INTERRUPT_PARAGRAPH.set(options, true);
089
090    // disable the built in processor, since we are configuring a patched one
091    Parser.ASTERISK_DELIMITER_PROCESSOR.set(options, false);
092
093    // configure GitHub-flavored tables
094    TablesExtension.COLUMN_SPANS.set(options, false);
095    TablesExtension.APPEND_MISSING_COLUMNS.set(options, true);
096    TablesExtension.DISCARD_EXTRA_COLUMNS.set(options, true);
097    TablesExtension.HEADER_SEPARATOR_COLUMN_MATCH.set(options, true);
098
099    // TypographicExtension.ENABLE_QUOTES.set(options, true); // default
100    TypographicExtension.ENABLE_SMARTS.set(options, false);
101    TypographicExtension.SINGLE_QUOTE_UNMATCHED.set(options, "'");
102    TypographicExtension.DOUBLE_QUOTE_OPEN.set(options, "\"");
103    TypographicExtension.DOUBLE_QUOTE_CLOSE.set(options, "\"");
104
105    Map<String, String> typographicReplacementMap = new ConcurrentHashMap<>();
106    typographicReplacementMap.put("“", "\"");
107    typographicReplacementMap.put("”", "\"");
108    typographicReplacementMap.put("&ldquo;", "“");
109    typographicReplacementMap.put("&rdquo;", "”");
110    // typographicReplacementMap.put("‘", "'");
111    // typographicReplacementMap.put("’", "'");
112    typographicReplacementMap.put("&lsquo;", "‘");
113    typographicReplacementMap.put("&rsquo;", "’");
114    typographicReplacementMap.put("&apos;", "’");
115    // typographicReplacementMap.put("«", "<<");
116    typographicReplacementMap.put("&laquo;", "«");
117    // typographicReplacementMap.put("»", ">>");
118    typographicReplacementMap.put("&raquo;", "»");
119    // typographicReplacementMap.put("…", "...");
120    typographicReplacementMap.put("&hellip;", "…");
121    // typographicReplacementMap.put("–", "--");
122    typographicReplacementMap.put("&endash;", "–");
123    // typographicReplacementMap.put("—", "---");
124    typographicReplacementMap.put("&emdash;", "—");
125
126    FlexmarkHtmlConverter.TYPOGRAPHIC_REPLACEMENT_MAP.set(options, typographicReplacementMap);
127    FlexmarkHtmlConverter.OUTPUT_UNKNOWN_TAGS.set(options, true);
128    FlexmarkHtmlConverter.SETEXT_HEADINGS.set(options, false); // disable
129    // needed to ensure extra empty paragraphs are ignored
130    FlexmarkHtmlConverter.BR_AS_EXTRA_BLANK_LINES.set(options, false);
131
132    // FlexmarkHtmlConverter.RENDER_COMMENTS.set(options, true);
133    // FlexmarkHtmlConverter.ADD_TRAILING_EOL.set(options, false); // default
134
135    Formatter.MAX_TRAILING_BLANK_LINES.set(options, -1);
136    Formatter.LIST_BULLET_MARKER.set(options, ListBulletMarker.DASH);
137
138    HtmlRenderer.MAX_TRAILING_BLANK_LINES.set(options, -1);
139    HtmlRenderer.UNESCAPE_HTML_ENTITIES.set(options, true);
140    HtmlRenderer.PERCENT_ENCODE_URLS.set(options, true);
141    // HtmlRenderer.ESCAPE_HTML_COMMENT_BLOCKS.set(options, false); // default
142    // HtmlRenderer.SUPPRESS_HTML_COMMENT_BLOCKS.set(options, false); // default
143    // HtmlRenderer.SUPPRESS_INLINE_HTML_COMMENTS.set(options, false); // default
144    // HtmlRenderer.HARD_BREAK.set(options,"<br/>");
145
146    return options.toImmutable();
147  }
148
149  public static DataSet newFlexmarkConfig(@Nullable DataHolder options) {
150    return options == null ? FLEXMARK_CONFIG : DataSet.merge(FLEXMARK_CONFIG, options);
151  }
152
153  private FlexmarkConfiguration() {
154    // disable construction
155  }
156
157}