All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.amihaiemil.eoyaml.RtYamlPrinter Maven / Gradle / Ivy

/**
 * Copyright (c) 2016-2023, Mihai Emil Andronache
 * All rights reserved.
 * 

* Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ package com.amihaiemil.eoyaml; import java.io.IOException; import java.io.Writer; import java.util.Iterator; import java.util.List; /** * Base implementation of YamlPrinter. "Rt" stands for "Runtime". * @checkstyle ExecutableStatementCount (400 lines) * @checkstyle CyclomaticComplexity (400 lines) * @author Mihai Andronache ([email protected]) * @version $Id: 90b06106eb678a89747f11644ad24b4b73fa124b $ * @since 4.3.1 */ final class RtYamlPrinter implements YamlPrinter { /** * Writer where the given YAML will be printed. */ private final Writer writer; /** * Constructor. * @param writer Destination writer. */ RtYamlPrinter(final Writer writer) { this.writer = writer; } @Override public void print(final YamlNode node) throws IOException { try { if (node instanceof Scalar) { this.writer.append("---").append(CompatibilityWrapper.lineSeparator()); this.printPossibleComment(node, ""); this.printScalar((Scalar) node, 0); this.writer.append(CompatibilityWrapper.lineSeparator()).append("..."); } else if (node instanceof YamlSequence) { boolean documentComment = this.printPossibleComment(node, ""); if(documentComment) { this.writer.append("---").append(CompatibilityWrapper.lineSeparator()); } this.printSequence((YamlSequence) node, 0); } else if (node instanceof YamlMapping) { boolean documentComment = this.printPossibleComment(node, ""); if(documentComment) { this.writer.append("---").append(CompatibilityWrapper.lineSeparator()); } this.printMapping((YamlMapping) node, 0); } else if (node instanceof YamlStream) { this.printStream((YamlStream) node, 0); } } finally { this.writer.close(); } } /** * Print a YAML Stream of documents. * @param stream Given YamlStream. * @param indentation Level of indentation of the printed stream. * @throws IOException If an I/O problem occurs. */ private void printStream( final YamlStream stream, final int indentation ) throws IOException { final String newLine = CompatibilityWrapper.lineSeparator(); int spaces = indentation; final StringBuilder indent = new StringBuilder(); while (spaces > 0) { indent.append(" "); spaces--; } final Iterator valuesIt = stream.values().iterator(); while(valuesIt.hasNext()) { final YamlNode document = valuesIt.next(); this.writer .append(indent) .append("---"); this.printNode(document, true, indentation + 2); if(valuesIt.hasNext()) { this.writer.append(newLine); } } } /** * Print a YAML Mapping. * @param mapping Given YamlMapping. * @param indentation Level of indentation of the printed mapping. * @throws IOException If an I/O problem occurs. */ private void printMapping( final YamlMapping mapping, final int indentation ) throws IOException { final String newLine = CompatibilityWrapper.lineSeparator(); int spaces = indentation; final StringBuilder alignment = new StringBuilder(); while (spaces > 0) { alignment.append(" "); spaces--; } final Iterator keysIt = mapping.keys().iterator(); while(keysIt.hasNext()) { final YamlNode key = keysIt.next(); final YamlNode value = mapping.value(key); this.printPossibleComment(value, alignment.toString()); this.writer.append(alignment); if(key instanceof Scalar) { this.writer.append( this.indent( new Escaped((Scalar) key).value(), 0 ) ); this.writer .append(":"); } else { this.writer .append("?"); this.printNode(key, true, indentation + 2); this.writer.append(newLine) .append(alignment) .append(":"); } if (value instanceof Scalar) { this.printNode(value, false, indentation); } else { this.printNode(value, true, indentation + 2); } if(keysIt.hasNext()) { this.writer.append(newLine); } } } /** * Print a YAML Sequence. * @param sequence Given YamlSequence. * @param indentation Level of indentation of the printed Scalar. * @throws IOException If an I/O problem occurs. */ private void printSequence( final YamlSequence sequence, final int indentation ) throws IOException { final String newLine = CompatibilityWrapper.lineSeparator(); int spaces = indentation; final StringBuilder alignment = new StringBuilder(); while (spaces > 0) { alignment.append(" "); spaces--; } final Iterator valuesIt = sequence.values().iterator(); while(valuesIt.hasNext()) { final YamlNode node = valuesIt.next(); this.printPossibleComment(node, alignment.toString()); this.writer .append(alignment) .append("-"); if (node instanceof Scalar) { this.printNode(node, false, 0); } else { this.printNode(node, true, indentation + 2); } if(valuesIt.hasNext()) { this.writer.append(newLine); } } } /** * Print a YAML Scalar. * @param scalar Given Scalar. * @param indentation Level of indentation of the printed Scalar. * @throws IOException If an I/O problem occurs. */ private void printScalar( final Scalar scalar, final int indentation ) throws IOException { if (scalar instanceof BaseFoldedScalar) { final BaseFoldedScalar foldedScalar = (BaseFoldedScalar) scalar; this.writer.append(">"); if(!scalar.comment().value().isEmpty()) { this.writer.append(" # ").append(scalar.comment().value()); } this.writer.append(CompatibilityWrapper.lineSeparator()); final List unfolded = foldedScalar.unfolded(); for(int idx = 0; idx < unfolded.size(); idx++) { this.writer.append( this.indent( unfolded.get(idx).trim(), indentation + 2 ) ); if(idx < unfolded.size() - 1) { this.writer.append(CompatibilityWrapper.lineSeparator()); } } } else if (scalar instanceof RtYamlScalarBuilder.BuiltLiteralBlockScalar || scalar instanceof ReadLiteralBlockScalar ) { this.writer.append("|"); if(!scalar.comment().value().isEmpty()) { this.writer.append(" # ").append(scalar.comment().value()); } this.writer .append(CompatibilityWrapper.lineSeparator()) .append( this.indent(scalar.value(), indentation + 2) ); } else { final Comment comment = scalar.comment(); if(comment instanceof ScalarComment) { this.writer.append( this.indent( new Escaped(scalar).value(), 0 ) ); final ScalarComment scalarComment = (ScalarComment) comment; if(!scalarComment.inline().value().isEmpty()) { this.writer.append(" # ").append( scalarComment.inline().value() ); } } } } /** * This method should be used when printing children * nodes of a complex Node (mapping, scalar, stream etc). * @param node YAML Node to print. * @param onNewLine Should the child node be printed on a new line? * @param indentation Indentation of the print. * @throws IOException If any I/O error occurs. */ private void printNode( final YamlNode node, final boolean onNewLine, final int indentation ) throws IOException { if (node == null || node.isEmpty()) { if (node instanceof EmptyYamlSequence) { this.writer.append(" ").append("[]"); } else if (node instanceof EmptyYamlMapping) { this.writer.append(" ").append("{}"); } else { this.writer.append(" ").append("null"); } } else { if (onNewLine) { this.writer.append(CompatibilityWrapper.lineSeparator()); } else { this.writer.append(" "); } if (node instanceof Scalar) { this.printScalar((Scalar) node, indentation); } else if (node instanceof YamlSequence) { this.printSequence((YamlSequence) node, indentation); } else if (node instanceof YamlMapping) { this.printMapping((YamlMapping) node, indentation); } else if (node instanceof YamlStream) { this.printStream((YamlStream) node, indentation); } } } /** * Print a comment. Make sure to split the lines if there are more * lines separated by NewLine and also add a '# ' in front of each * line. * @param node Node containing the Comment. * @param alignment Indentation. * @return True if a comment was printed, false otherwise. * @throws IOException If any I/O problem occurs. */ private boolean printPossibleComment( final YamlNode node, final String alignment ) throws IOException { boolean printed = false; if(node != null && node.comment() != null) { final Comment tmpComment; if(node.comment() instanceof ScalarComment) { tmpComment = ((ScalarComment) node.comment()).above(); } else { tmpComment = node.comment(); } final String com = tmpComment.value(); if (com.trim().length() != 0) { String[] lines = com.split(CompatibilityWrapper.lineSeparator()); for (final String line : lines) { this.writer .append(alignment) .append("# ") .append(line) .append(CompatibilityWrapper.lineSeparator()); } printed = true; } } return printed; } /** * Indent a given String value. If the String has multiple lines, * they will all be indented together. * @param value String to indent. * @param indentation Indentation level. * @return Indented String. */ private String indent(final String value, final int indentation) { StringBuilder alignment = new StringBuilder(); int spaces = indentation; while (spaces > 0) { alignment.append(" "); spaces--; } String[] lines = value.split(CompatibilityWrapper.lineSeparator()); StringBuilder printed = new StringBuilder(); for(int idx = 0; idx < lines.length; idx++) { printed.append(alignment); printed.append(lines[idx]); if(idx < lines.length - 1) { printed.append(CompatibilityWrapper.lineSeparator()); } } return printed.toString(); } /** * A scalar which escapes its value. * @author Mihai Andronache ([email protected]) * @version $Id: 90b06106eb678a89747f11644ad24b4b73fa124b $ * @since 4.3.1 */ static class Escaped extends BaseScalar { /** * Original unescaped scalar. */ private final Scalar original; /** * Ctor. * @param original Unescaped scalar. */ Escaped(final Scalar original) { this.original = original; } @Override public String value() { final String value = this.original.value(); String escaped = value; boolean quoted = (value.startsWith("'") && value.endsWith("'")) || (value.startsWith("\"") && value.endsWith("\"")); if (!quoted && value.matches(".*[?\\-#:>|$%&{}\\[\\]]+.*|[ ]+")) { if(value.contains("\"")) { escaped = "'" + value + "'"; } else { escaped = "\"" + value + "\""; } } return escaped; } @Override public Comment comment() { return this.original.comment(); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy