private static String convertElementsToText(final List<ElementInfo> elementInfoList) {
        final String elementsText = elementInfoList.stream()
                .sorted(Comparator.comparing(ElementInfo::type))
                .map(elementInfo -> {

                    final String descriptionText = elementInfo.description != null
                            ? elementInfo.description
                            : "> TODO - Add description";

                    // Add the &nbsp; at the end so the markdown processor treats the line as a <p>
                    final String iconText = elementInfo.iconFilename != null
                            ? LogUtil.message("""
                            {{< pipe-elm "{}" >}}&nbsp;""", elementInfo.type)
                            : "";

                    final String rolesText = buildRolesText(elementInfo.roles);
//                    final String rolesText = !elementInfo.roles.isEmpty()
//                            ? ("\n\n**Roles:**\n" + elementInfo.roles
//                            .stream()
//                            .sorted()
//                            .map(WordUtils::capitalize)
//                            .map(role -> "\n* " + role)
//                            .collect(Collectors.joining()))
//                            : "";

                    final String propsText;
                    if (!elementInfo.propertyInfoList.isEmpty()) {
                        propsText = "\n\n**Element properties:**\n\n" + AsciiTable.builder(elementInfo.propertyInfoList)
                                .withColumn(Column.builder("Name", PropertyInfo::name)
                                        .build())
                                .withColumn(Column.builder("Description", PropertyInfo::description)
                                        .build())
                                .withColumn(Column.builder("Default Value", (PropertyInfo propInfo) ->
                                                propInfo.defaultValue().isEmpty()
                                                        ? "-"
                                                        : propInfo.defaultValue())
                                        .build())
                                .withColumn(Column.builder("Value Type", (PropertyInfo propInfo) ->
                                                propInfo.argTypeStr().isEmpty()
                                                        ? "-"
                                                        : propInfo.argTypeStr())
                                        .build())
                                .build();
                    } else {
                        propsText = "";
                    }

                    final String template = """
                            ### {}

                            {}

                            {}{}

                            """;

                    return LogUtil.message(
                            template,
                            elementInfo.type(),
                            iconText,
                            descriptionText,
//                            elementInfo.category.getDisplayValue(),
//                            rolesText,
                            propsText
                    );
                })
                .collect(Collectors.joining("\n"));
        return elementsText;
    }
This will modify the content of the file
{@code [this repo]/../stroom-docs/layouts/shortcodes/pipe-elm.html}
stroom-app/src/test/java/stroom/app/docs/GeneratePipelineElementsDoc.java