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

net.sourceforge.plantuml.yaml.parser.YamlLine Maven / Gradle / Ivy

The newest version!
// THIS FILE HAS BEEN GENERATED BY A PREPROCESSOR.
/* +=======================================================================
 * |
 * |      PlantUML : a free UML diagram generator
 * |
 * +=======================================================================
 *
 * (C) Copyright 2009-2024, Arnaud Roques
 *
 * Project Info:  https://plantuml.com
 *
 * If you like this project or if you find it useful, you can support us at:
 *
 * https://plantuml.com/patreon (only 1$ per month!)
 * https://plantuml.com/liberapay (only 1€ per month!)
 * https://plantuml.com/paypal
 *
 *
 * PlantUML is free software; you can redistribute it and/or modify it
 * under the terms of the MIT License.
 *
 * See http://opensource.org/licenses/MIT
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
 * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * PlantUML can occasionally display sponsored or advertising messages. Those
 * messages are usually generated on welcome or error images and never on
 * functional diagrams.
 * See https://plantuml.com/professional if you want to remove them
 *
 * Images (whatever their format : PNG, SVG, EPS...) generated by running PlantUML
 * are owned by the author of their corresponding sources code (that is, their
 * textual description in PlantUML language). Those images are not covered by
 * this MIT license.
 *
 * The generated images can then be used without any reference to the MIT license.
 * It is not even necessary to stipulate that they have been generated with PlantUML,
 * although this will be appreciated by the PlantUML team.
 *
 * There is an exception : if the textual description in PlantUML language is also covered
 * by any license, then the generated images are logically covered
 * by the very same license.
 *
 * This is the IGY distribution (Install GraphViz by Yourself).
 * You have to install GraphViz and to setup the GRAPHVIZ_DOT environment variable
 * (see https://plantuml.com/graphviz-dot )
 *
 * Icons provided by OpenIconic :  https://useiconic.com/open
 * Archimate sprites provided by Archi :  http://www.archimatetool.com
 * Stdlib AWS provided by https://github.com/milo-minderbinder/AWS-PlantUML
 * Stdlib Icons provided https://github.com/tupadr3/plantuml-icon-font-sprites
 * ASCIIMathML (c) Peter Jipsen http://www.chapman.edu/~jipsen
 * ASCIIMathML (c) David Lippman http://www.pierce.ctc.edu/dlippman
 * CafeUndZopfli ported by Eugene Klyuchnikov https://github.com/eustas/CafeUndZopfli
 * Brotli (c) by the Brotli Authors https://github.com/google/brotli
 * Themes (c) by Brett Schwarz https://github.com/bschwarz/puml-themes
 * Twemoji (c) by Twitter at https://twemoji.twitter.com/
 *
 */
package net.sourceforge.plantuml.yaml.parser;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import net.sourceforge.plantuml.annotation.DuplicateCode;

public class YamlLine {

	private final int indent;
	private final String key;
	private final String value;
	private final List values;
	private final boolean listItem;
	private final YamlLineType type;

	public static YamlLine build(String line) {
		int count = 0;
		line = line.replaceAll("\t", "    ");
		while (count < line.length() && line.charAt(count) == ' ')
			count++;

		String trimmedLine = removeYamlComment(line.substring(count).trim());

		if (trimmedLine.isEmpty())
			return new YamlLine(YamlLineType.EMPTY_LINE, 0, null, null, null, false);

		if (trimmedLine.equals("-"))
			return new YamlLine(YamlLineType.PLAIN_DASH, count + 1, null, null, null, true);

		final boolean listItem = trimmedLine.startsWith("- ");

		if (listItem) {
			count += 2;
			trimmedLine = trimmedLine.substring(2);
		}

		final int colonIndex = trimmedLine.indexOf(':');
		if (colonIndex == -1)
			if (listItem)
				return new YamlLine(YamlLineType.PLAIN_ELEMENT_LIST, count, null, unquote(trimmedLine), null, listItem);
			else
				return new YamlLine(YamlLineType.NO_KEY_ONLY_TEXT, count, null, unquote(trimmedLine), null, false);

		final String rawKey = trimmedLine.substring(0, colonIndex).trim();
		final String rawValue = trimmedLine.substring(colonIndex + 1).trim();

		YamlLineType type = YamlLineType.KEY_AND_VALUE;

		if (rawValue.isEmpty())
			type = YamlLineType.KEY_ONLY;
		else if (rawValue.equals("|"))
			type = YamlLineType.KEY_AND_BLOCK_STYLE;
		else if (rawValue.equals(">"))
			type = YamlLineType.KEY_AND_FOLDED_STYLE;
		else if (rawValue.startsWith("[") && rawValue.endsWith("]"))
			return new YamlLine(YamlLineType.KEY_AND_FLOW_SEQUENCE, count, unquote(rawKey), null,
					toList(rawValue.substring(1, rawValue.length() - 1)), listItem);

		return new YamlLine(type, count, unquote(rawKey), unquote(rawValue), null, listItem);

	}

	private static List toList(String rawValue) {
		final List result = new ArrayList<>();

		final StringBuilder current = new StringBuilder();

		// Zero if we are not in a quoted state or
		// represents the quote character if we are in a quoted string
		char inQuotedString = '\0';

		// Indicates that the current field started with a quote
		boolean fieldStartWithQuote = false;

		for (int i = 0; i < rawValue.length(); i++) {
			final char c = rawValue.charAt(i);

			if (inQuotedString != '\0') {
				// Processing a quoted string
				if (c == '\\') {
					// Handle escaping: append the next character as is if it exists
					if (i + 1 < rawValue.length()) {
						current.append(rawValue.charAt(i + 1));
						i++; // Skip the escaped character
					}
				} else if (c == inQuotedString) {
					// End of the quoted string
					inQuotedString = '\0';
				} else {
					current.append(c);
				}
			} else {
				// We are not in a quoted string.
				// If the field contains only spaces and we encounter a quote,
				// we consider that the field actually starts with a quote.
				if (fieldStartWithQuote == false && current.toString().trim().isEmpty() && (c == '\'' || c == '"')) {
					inQuotedString = c;
					fieldStartWithQuote = true;
					current.setLength(0); // Clear any preliminary spaces
				} else if (c == ',') {
					// The field separator is encountered.
					// For a quoted field, keep the content as is,
					// otherwise apply trim.
					result.add(fieldStartWithQuote ? current.toString() : current.toString().trim());
					// Reset for the next field
					current.setLength(0);
					fieldStartWithQuote = false;
				} else if (c == '\\') {
					// Handle escaping outside of quotes
					if (i + 1 < rawValue.length()) {
						current.append(rawValue.charAt(i + 1));
						i++; // Skip the escaped character
					}
				} else {
					current.append(c);
				}
			}
		}
		// Add the last field (even if it's empty)
		result.add(fieldStartWithQuote ? current.toString() : current.toString().trim());

		return result;
	}

	private YamlLine(YamlLineType type, int indent, String key, String value, List values, boolean listItem) {
		this.type = type;
		this.indent = indent;
		this.key = key;
		this.value = value;
		this.values = values;
		this.listItem = listItem;
	}

	private static String unquote(String str) {
		if (str == null || str.length() < 2)
			return str;

		final char first = str.charAt(0);
		final char last = str.charAt(str.length() - 1);
		if ((first == '"' && last == '"') || (first == '\'' && last == '\''))
			return str.substring(1, str.length() - 1);

		return str;
	}

	public int getIndent() {
		return indent;
	}

	@DuplicateCode(reference = "YamlLines")
	private static String removeYamlComment(String s) {
		if (s == null || s.isEmpty())
			return s;

		char inQuoteChar = '\0';

		if (s.charAt(0) == '#')
			return "";

		for (int i = 0; i < s.length(); i++) {
			final char c = s.charAt(i);

			if (c == '\'' || c == '"')
				if (inQuoteChar == '\0')
					inQuoteChar = c;
				else if (c == inQuoteChar)
					inQuoteChar = '\0';

			if (inQuoteChar == '\0' && i < s.length() - 1 && c == ' ' && s.charAt(i + 1) == '#')
				return s.substring(0, i);

		}

		return s;
	}

	public String getKey() {
		return key;
	}

	public String getValue() {
		if (type == YamlLineType.KEY_AND_VALUE || type == YamlLineType.KEY_AND_FLOW_SEQUENCE
				|| type == YamlLineType.PLAIN_ELEMENT_LIST || type == YamlLineType.NO_KEY_ONLY_TEXT)
			return value;
		throw new IllegalStateException(type.name());
	}

	public boolean isListItem() {
		return listItem;
	}

	public YamlLineType getType() {
		return type;
	}

	public List getValues() {
		if (type == YamlLineType.KEY_AND_FLOW_SEQUENCE)
			return Collections.unmodifiableList(values);
		throw new IllegalStateException(type.name());
	}

	@Override
	public String toString() {
		return "YamlLine(" + type + " indent=" + indent + ", key=" + key + ", value=" + value + ")";
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy