Class ConfigDocument

java.lang.Object
com.ultikits.ultitools.config.document.ConfigDocument

@Internal public final class ConfigDocument extends Object
One config file as a document: SnakeYAML's own node tree (comments, quoting and layout as they are in the file) plus the plain-data view of its values, addressed by key arrays.

Reading. The text is composed with SnakeYAML's node API using the options Bukkit's YamlConfiguration uses (aliases and code points unlimited, nesting depth 100) with comment processing on. Values are constructed with a SafeConstructor, so a global tag such as !!java.util.UUID is refused, and a map key's identity is String.valueOf of its constructed value, exactly the rule Bukkit's YamlConfiguration#fromNodeTree applies: yes: is the key "true", 1: the key "1"; a duplicate key's last value wins; merge keys (<<) are flattened. Unlike Bukkit, a key is never split at .: "o.O" and wave. are single keys. A key's original node is kept, so it is written back with its original text. Values YAML itself types outside plain data (a timestamp reads as a java.util.Date, !!binary as a byte[], !!set as a Set) are returned as they are; the binding layer reports them.

Writing. set(List, Object) accepts plain data only (see PlainData) and changes only what differs: an equal value keeps its node, a changed map is merged key by key, a same-size list element by element, a changed string keeps its quote style, and every replaced node keeps its comments. render() serializes the whole node tree through SnakeYAML, preserving content, comments and document style; the rendering itself may normalize operator spacing. Comments on individual list items are kept only while the list keeps its length - the same as Bukkit, which keeps none. A document holding an anchor, an alias or a merge key is re-rendered from its plain data once changed (every value equal, anchors expanded, the comments of keys that still exist carried over), as Bukkit renders every file.

No caller publishes a rendering as it is: every write to a configuration file goes through OperatorFileWriter, which refuses a rendering that would change any byte outside the keys the write owns (so normalized spacing or an expanded anchor is never written) and never writes an anchored file.

Comments. SnakeYAML attaches a comment to the node after it. Two placements are adjusted when the file is read, without changing the rendered text: the file header (the comment lines before the first key, up to the last blank line among them, Bukkit's own rule) belongs to the document rather than to the first key; and a comment indented deeper than the key it precedes is the trailing comment of the previous section, and is kept there. The framework writes a comment only through setFrameworkComment(List, List).

Instances are not thread-safe; the entity that owns a document confines it.

Since:
6.3.0
  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Class
    Description
    (package private) static final class 
    One comment line to re-indent: where the reader found it, and what must be there for the move to apply.
    private static final class 
    The two comment placements adjusted on read (see the class description).
    private static final class 
    A section left with no value that a set(java.util.List<java.lang.String>, java.lang.Object) made a section again, and the comment lines indented under it.
    (package private) static final class 
    A SafeConstructor that constructs single nodes and flattens merge keys on request.
    private static final class 
    Builds the plain-data view of a composed tree with Bukkit's key and value rules.
    private static final class 
    Builds new nodes for plain values.
  • Field Summary

    Fields
    Modifier and Type
    Field
    Description
    private final boolean
     
    Sections left with no value that this document made sections again, with the comment lines indented under them.
     
    private boolean
     
    (package private) static final int
    Bukkit's YamlConfiguration nesting limit, kept for compatibility.
    private final Map<String,Object>
     
    private org.yaml.snakeyaml.nodes.MappingNode
     
    private final String
     
    private final DocumentStyle
     
    private static final Pattern
     
    private static final Pattern
     
  • Constructor Summary

    Constructors
    Modifier
    Constructor
    Description
    private
    ConfigDocument(String source, org.yaml.snakeyaml.nodes.MappingNode root, Map<String,Object> plain, DocumentStyle style, boolean anchored)
     
  • Method Summary

    Modifier and Type
    Method
    Description
    private static void
    appendMappingEnds(org.yaml.snakeyaml.nodes.MappingNode mapping, List<org.yaml.snakeyaml.comments.CommentLine> ends)
     
    Returns the comment lines directly above the key at path: each line's text after # with one leading space removed, and null for a blank line.
    Returns the comment lines directly above the key at path in the byte form they are written in: for a line at the key's own column, "#" followed by everything after the # up to the line break (a framework line reads "# " + text, or "#" for an empty line); null for a blank line.
    private static void
    carryComments(org.yaml.snakeyaml.nodes.Node from, org.yaml.snakeyaml.nodes.Node to)
     
    private static void
    carryPresentation(org.yaml.snakeyaml.nodes.Node from, org.yaml.snakeyaml.nodes.Node to)
     
    private static boolean
    Whether dropping the emitted text's final line break (a file without one keeps that style) would change a value: only a block scalar running to the end of the document can be changed, e.g.
    private org.yaml.snakeyaml.nodes.MappingNode
    childMapping(org.yaml.snakeyaml.nodes.MappingNode mapping, String key, Object child)
     
    private static Map<String,Object>
     
    private static void
    claimCommentOccurrences(org.yaml.snakeyaml.nodes.Node node, Set<org.yaml.snakeyaml.nodes.Node> seen, Set<org.yaml.snakeyaml.comments.CommentLine> claimed)
    An expanded alias may carry the same physical comment object to several fresh nodes.
    private static void
    collectDescendantEnds(org.yaml.snakeyaml.nodes.Node node, List<org.yaml.snakeyaml.comments.CommentLine> ends, Set<org.yaml.snakeyaml.nodes.Node> seen)
     
    private static void
    collectEnds(org.yaml.snakeyaml.nodes.Node node, List<org.yaml.snakeyaml.comments.CommentLine> ends, Set<org.yaml.snakeyaml.nodes.Node> seen)
     
    private static void
    collectReadings(Object node, String[] parts, int from, List<String> prefix, List<List<String>> found)
     
    private static org.yaml.snakeyaml.nodes.Node
     
    boolean
    Returns whether the file holds a value (possibly null) at path.
    private static boolean
    containsSame(List<org.yaml.snakeyaml.comments.CommentLine> lines, org.yaml.snakeyaml.comments.CommentLine line)
     
    private static org.yaml.snakeyaml.DumperOptions
     
    private static String
    emit(org.yaml.snakeyaml.nodes.Node out, DocumentStyle style)
    The emitter's text for out, comments realigned and whitespace-only lines emptied.
    Returns an empty document, as for a file that does not exist yet, in the default style.
    private org.yaml.snakeyaml.nodes.Node
     
    private org.yaml.snakeyaml.nodes.MappingNode
    The mapping node holding the last key of path, or null.
    private Map<String,Object>
     
    private static List<org.yaml.snakeyaml.comments.CommentLine>
    The comment lines the framework writes for lines: split at YAML line breaks, made printable.
    get(List<String> path)
    Returns the plain value at path, or null when the path is absent (use contains(List) to tell an absent key from an explicit null).
    private static boolean
    hasAnchors(org.yaml.snakeyaml.nodes.Node node, Set<org.yaml.snakeyaml.nodes.Node> seen)
     
    heldSections(String dottedPath)
    Where a declared setting this document does not hold belongs (#614): the readings (readings(String)) of the longest proper prefix of dottedPath that this document holds as a section - a mapping, or a key with no value.
    private static boolean
    holdsAsValue(org.yaml.snakeyaml.nodes.MappingNode parent, org.yaml.snakeyaml.nodes.Node value)
     
    private int
    indexOf(org.yaml.snakeyaml.nodes.MappingNode mapping, String key)
    Index of the last tuple whose key identity equals key (the last duplicate wins, as on read).
    private static boolean
    isBlockCollection(org.yaml.snakeyaml.nodes.Node node)
     
    private String
    keyIdentity(org.yaml.snakeyaml.nodes.Node keyNode)
     
    load(Path file)
    Reads a config file.
    (package private) static ConfigLoadResult
     
    (package private) static org.yaml.snakeyaml.LoaderOptions
     
    private static ConfigLoadResult
     
    private void
    merge(org.yaml.snakeyaml.nodes.MappingNode old, Map<?,?> oldPlain, Map<?,?> value)
     
    (package private) static String
    Re-indents comment lines of text; every other character is copied unchanged.
    private static void
    moveInLineCommentsToKey(org.yaml.snakeyaml.nodes.Node from, org.yaml.snakeyaml.nodes.Node key)
     
    private org.yaml.snakeyaml.nodes.Node
    newNode(Object plainValue)
     
    (package private) static String
    normalizeEscapes(String text, boolean upper, boolean latin1AsU)
    Rewrites the escapes inside every double-quoted scalar into the file's own form: \xHH as \u00HH when latin1AsU, and hex digits in upper case when upper.
    private static org.yaml.snakeyaml.nodes.Node
    normalizeMultilineStrings(org.yaml.snakeyaml.nodes.Node node, Map<org.yaml.snakeyaml.nodes.Node,org.yaml.snakeyaml.nodes.Node> normalized, boolean preserveNoEof)
    Escapes preserve NEL (which the scanner normalizes) and no-EOF multiline string content.
    parse(String text)
    Parses a config file's text.
    private List<Runnable>
    For a render only: moves each recorded run of comment lines indented under an expanded section to the end of the section's last value - where the reader puts such lines once the section holds keys, and where the emitter writes them at the section's own indentation, byte for byte as the operator wrote them when their column is that one - and returns how to undo it, so the document's comments stay as read (the write gate's comment ownership is computed on them).
    private static void
    prependEnds(org.yaml.snakeyaml.nodes.Node recipient, List<org.yaml.snakeyaml.comments.CommentLine> ends)
     
    private static String
    Keeps the characters YAML allows in a stream (the YAML 1.1 printable set, tab included).
    private static List<int[]>
    Each line's {start, end of content} in text, with SnakeYAML's reader's line breaks.
    readings(String dottedPath)
    Returns every place this document holds a declared setting path: each way of splitting dottedPath at its dots into keys the document holds, the last one present (an explicit null included).
    static List<List<String>>
    readings(Map<?,?> tree, String dottedPath)
    readings(String) over a plain-data tree, such as a copy of a document taken at load.
    private static String
    realignCommentsAfterBlankLines(String text, List<org.yaml.snakeyaml.events.Event> events)
    Puts back every comment line SnakeYAML's emitter misplaces after a blank line (17-64 review round 1 R1-01, route change (i)).
    private void
    recordExpansion(List<org.yaml.snakeyaml.nodes.MappingNode> parents, List<String> keys, org.yaml.snakeyaml.nodes.MappingNode section)
    Records a section left with no value that this document made a section again (keys is its key path, parents the mappings holding each of those keys, from the top level), together with the comment lines indented under its line in the file - the lines a commented-out child leaves (#620).
    boolean
    Removes the key at path together with its own comment lines.
    private static void
    removeTuples(org.yaml.snakeyaml.nodes.MappingNode mapping, Predicate<org.yaml.snakeyaml.nodes.NodeTuple> removed)
    Every tuple deletion uses the same post-order preservation of section end comments.
    Serializes the document in the file's own style.
    private String
    renderFrom(org.yaml.snakeyaml.nodes.MappingNode out)
     
    void
    replaceFrameworkComment(List<String> path, int owned, List<String> lines)
    Replaces only the last owned comment lines of the key at path - the run the framework identified as its own comment - with lines, rendered and sanitized exactly as setFrameworkComment(List, List) renders them.
    private static org.yaml.snakeyaml.representer.Representer
     
    private static void
     
    private org.yaml.snakeyaml.nodes.MappingNode
     
    private static void
    retainDescendantEnds(org.yaml.snakeyaml.nodes.Node from, org.yaml.snakeyaml.nodes.Node to)
     
    private static boolean
    sameComments(List<org.yaml.snakeyaml.comments.CommentLine> a, List<org.yaml.snakeyaml.comments.CommentLine> b)
     
    private static List<org.yaml.snakeyaml.events.Event>
    serialize(org.yaml.snakeyaml.nodes.Node out, Writer writer, DocumentStyle style)
    Serializes out exactly as Yaml#serialize(Node, Writer) does (the same Serializer, Emitter, options and resolver), recording every event the emitter receives, so the comment lines it writes can be located afterwards by position (17-64 route change (i)).
    void
    set(List<String> path, Object value)
    Stores a plain value at path, creating missing mappings on the way.
    void
    Replaces the comment of the key at path - the only way the framework writes a comment.
    private void
    setHeldComments(org.yaml.snakeyaml.nodes.Node holder, List<org.yaml.snakeyaml.comments.CommentLine> lines)
     
    (package private) static String
    sha256(byte[] bytes)
     
    private static boolean
    startsWithSame(List<org.yaml.snakeyaml.comments.CommentLine> lines, List<org.yaml.snakeyaml.comments.CommentLine> prefix)
     
    Returns a copy of the whole document as plain data, in file order.
    private void
    transplantComments(org.yaml.snakeyaml.nodes.MappingNode from, org.yaml.snakeyaml.nodes.MappingNode to, Set<org.yaml.snakeyaml.nodes.Node> retained)
     
    private void
    transplantNode(org.yaml.snakeyaml.nodes.Node from, org.yaml.snakeyaml.nodes.Node to, Set<org.yaml.snakeyaml.nodes.Node> retained)
    Carries all comment positions and the collection presentation that makes them emit correctly.
    private static List<org.yaml.snakeyaml.comments.CommentLine>
    unclaimedComments(List<org.yaml.snakeyaml.comments.CommentLine> comments, Set<org.yaml.snakeyaml.comments.CommentLine> claimed)
     
    private org.yaml.snakeyaml.nodes.Node
    update(org.yaml.snakeyaml.nodes.Node old, Object oldPlain, Object value)
     
    (package private) static boolean
    writtenWithNoValue(org.yaml.snakeyaml.nodes.Node value)
    Whether the operator wrote no value at all for the key holding value: nothing after the colon but, at most, a comment.

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Field Details

    • NESTING_DEPTH_LIMIT

      static final int NESTING_DEPTH_LIMIT
      Bukkit's YamlConfiguration nesting limit, kept for compatibility.
      See Also:
    • YAML_LINE_BREAK

      private static final Pattern YAML_LINE_BREAK
    • WHITESPACE_ONLY_LINE

      private static final Pattern WHITESPACE_ONLY_LINE
    • style

      private final DocumentStyle style
    • anchored

      private final boolean anchored
    • source

      private final String source
    • plain

      private final Map<String,Object> plain
    • keyConstructor

      private final ConfigDocument.NodeConstructor keyConstructor
    • root

      private org.yaml.snakeyaml.nodes.MappingNode root
    • modified

      private boolean modified
    • expansions

      private final List<ConfigDocument.Expansion> expansions
      Sections left with no value that this document made sections again, with the comment lines indented under them.
  • Constructor Details

  • Method Details

    • empty

      public static ConfigDocument empty()
      Returns an empty document, as for a file that does not exist yet, in the default style.
      Returns:
      a document without keys
    • parse

      public static ConfigDocument parse(String text) throws ConfigParseException
      Parses a config file's text.
      Parameters:
      text - the file's content
      Returns:
      the document
      Throws:
      ConfigParseException - if the text is not valid YAML, holds a tag this layer does not construct, is deeper than the nesting limit, or its top level is not a mapping
    • load

      public static ConfigLoadResult load(Path file)
      Reads a config file. Never throws: the result is ABSENT, LOADED (with the document and the SHA-256 of the bytes read), UNREADABLE (with the I/O failure) or UNPARSEABLE (with the parser's message). Temporary files an interrupted write left beside the file are deleted first (see AtomicConfigWriter).
      Parameters:
      file - the config file
      Returns:
      what was found
    • load

    • loadLocked

      private static ConfigLoadResult loadLocked(Path file, AtomicConfigWriter.FileOperations files)
    • get

      public Object get(List<String> path)
      Returns the plain value at path, or null when the path is absent (use contains(List) to tell an absent key from an explicit null).
      Parameters:
      path - the key path, one element per mapping level
      Returns:
      a copy of the value
    • contains

      public boolean contains(List<String> path)
      Returns whether the file holds a value (possibly null) at path.
      Parameters:
      path - the key path
      Returns:
      whether the path is present
    • readings

      public List<List<String>> readings(String dottedPath)
      Returns every place this document holds a declared setting path: each way of splitting dottedPath at its dots into keys the document holds, the last one present (an explicit null included). a.b.c is read as a -> b -> c, a.b -> c, a -> b.c or the single key a.b.c, the way Bukkit's YamlConfiguration - which splits every key at its dots - reads the same file, so a setting the operator wrote as a flat dotted key is that setting (#612). Keys inside the setting's value are not split: this addresses the setting itself, never an entry of a map it holds.
      Parameters:
      dottedPath - a declared setting path, such as features.chat
      Returns:
      the readings found, nested forms first; empty when the document does not hold the setting, two or more when it holds it in several forms
      Since:
      6.3.0
    • readings

      public static List<List<String>> readings(Map<?,?> tree, String dottedPath)
      readings(String) over a plain-data tree, such as a copy of a document taken at load.
      Parameters:
      tree - the top-level mapping
      dottedPath - a declared setting path
      Returns:
      the readings found, nested forms first
      Since:
      6.3.0
    • heldSections

      public List<List<String>> heldSections(String dottedPath)
      Where a declared setting this document does not hold belongs (#614): the readings (readings(String)) of the longest proper prefix of dottedPath that this document holds as a section - a mapping, or a key with no value. An insert goes below one of them, the rest of the path as nested keys, so a section the operator wrote in flat dotted form (a.b:) gets the setting in place and never a second, nested copy (a: b:), which Bukkit's YamlConfiguration would read as replacing the first. Each returned path joins with . to the same prefix.
      Parameters:
      dottedPath - a declared setting path
      Returns:
      the section readings of the longest held prefix, nested forms first; empty when no prefix is held as a section; two or more when the document holds that section in several forms
      Since:
      6.3.0
    • collectReadings

      private static void collectReadings(Object node, String[] parts, int from, List<String> prefix, List<List<String>> found)
    • toPlain

      public Map<String,Object> toPlain()
      Returns a copy of the whole document as plain data, in file order.
      Returns:
      the top-level mapping
    • set

      public void set(List<String> path, Object value)
      Stores a plain value at path, creating missing mappings on the way. A value equal to the current one (see PlainData.plainEquals(java.lang.Object, java.lang.Object)) changes nothing.
      Parameters:
      path - the key path, at least one key
      value - plain data; null is stored as an explicit YAML null
      Throws:
      IllegalArgumentException - if value is not plain data (the message names the key path and the class), the path is empty, or the path and value together nest deeper than the 100 levels a load accepts
    • remove

      public boolean remove(List<String> path)
      Removes the key at path together with its own comment lines.
      Parameters:
      path - the key path
      Returns:
      whether a key was removed
    • blockComment

      public List<String> blockComment(List<String> path)
      Returns the comment lines directly above the key at path: each line's text after # with one leading space removed, and null for a blank line. The file header is not part of the first key's comment.
      Parameters:
      path - the key path
      Returns:
      the lines, empty when the key has no comment or does not exist
    • blockCommentAsWritten

      public List<String> blockCommentAsWritten(List<String> path)
      Returns the comment lines directly above the key at path in the byte form they are written in: for a line at the key's own column, "#" followed by everything after the # up to the line break (a framework line reads "# " + text, or "#" for an empty line); null for a blank line. A line at any other column is reported as "@<offset>|#...", which never equals a line the framework writes, since the framework writes a key's comment at the key's column. A line added in memory (it has no position yet) is reported as it will be written. The file header is not part of the first key's comment.

      The framework identifies its own comment lines on this form (17-64 review round 1 R1-02): a line holding the framework's text in any other byte form was written by an operator.

      Parameters:
      path - the key path
      Returns:
      the lines, empty when the key has no comment or does not exist
    • setFrameworkComment

      public void setFrameworkComment(List<String> path, List<String> lines)
      Replaces the comment of the key at path - the only way the framework writes a comment. Blank lines directly above the comment are kept; the comment lines themselves are replaced by lines. Each line is split at every YAML line break (\r\n, \r, \n, U+0085, U+2028, U+2029) and characters YAML does not allow in a stream are dropped; a null line is a blank line.
      Parameters:
      path - the key path of an existing key
      lines - the new comment text, one element per line (an empty list removes the comment)
      Throws:
      IllegalArgumentException - if no key exists at path
    • replaceFrameworkComment

      public void replaceFrameworkComment(List<String> path, int owned, List<String> lines)
      Replaces only the last owned comment lines of the key at path - the run the framework identified as its own comment - with lines, rendered and sanitized exactly as setFrameworkComment(List, List) renders them. With owned zero the lines are appended below the key's existing comment.

      Why it cannot change an operator line. Every comment line above the run - an operator's note, a blank line, a framework comment the operator edited - is kept as the same comment object, in the same order, so it renders byte for byte as before; only the run's own lines are dropped. The run may not include a blank line and may not reach above the key's comment, so it can never take in a line the caller did not identify (maintainer decision 2026-10-04, "only the framework's own comments are rewritten", #604).

      Parameters:
      path - the key path of an existing key
      owned - how many of the key's last comment lines are the framework's (0 for none)
      lines - the new framework comment text, one element per line
      Throws:
      IllegalArgumentException - if no key exists at path, or the run is negative, longer than the key's comment, or includes a blank line
    • frameworkLines

      private static List<org.yaml.snakeyaml.comments.CommentLine> frameworkLines(List<String> lines)
      The comment lines the framework writes for lines: split at YAML line breaks, made printable.
    • render

      public String render()
      Serializes the document in the file's own style.
      Returns:
      the file text
    • renderFrom

      private String renderFrom(org.yaml.snakeyaml.nodes.MappingNode out)
    • emit

      private static String emit(org.yaml.snakeyaml.nodes.Node out, DocumentStyle style)
      The emitter's text for out, comments realigned and whitespace-only lines emptied.
    • changedByMissingFinalLineBreak

      private static boolean changedByMissingFinalLineBreak(String text)
      Whether dropping the emitted text's final line break (a file without one keeps that style) would change a value: only a block scalar running to the end of the document can be changed, e.g. | ending a file whose last value ends with a line break. Then every multi-line string is written double-quoted instead (the #592 measurement's adjacent finding: quoting every block scalar of such a file whenever it is written changed bytes no write owned, so the write gate refused every write to it).
    • serialize

      private static List<org.yaml.snakeyaml.events.Event> serialize(org.yaml.snakeyaml.nodes.Node out, Writer writer, DocumentStyle style)
      Serializes out exactly as Yaml#serialize(Node, Writer) does (the same Serializer, Emitter, options and resolver), recording every event the emitter receives, so the comment lines it writes can be located afterwards by position (17-64 route change (i)).
      Returns:
      the events, in the order the emitter wrote them
    • realignCommentsAfterBlankLines

      private static String realignCommentsAfterBlankLines(String text, List<org.yaml.snakeyaml.events.Event> events)
      Puts back every comment line SnakeYAML's emitter misplaces after a blank line (17-64 review round 1 R1-01, route change (i)). The emitter (Emitter#writeCommentLines, SnakeYAML 2.2) writes the first comment line after a blank line of a comment run at its current indentation plus the run's own column again - doubled indentation in a nested block - and every other line of the run at the run's column.

      Nothing is injected into the document's text: the lines are located by position. The comment events the emitter received (in order, each carrying its original line's position) are matched one to one with the comment events of the emitted text read back; when the two sequences differ in length, type or text (a blank line matches a blank line by type: in memory its text is empty, read back it is the line break), the emitted text is returned unchanged. Each misplaced line - a comment line right after a blank line, with an earlier comment line in the same run - is written at its own original column, or, for a line added in memory (it has no position), at the column of the run's first comment line as emitted. Lines are located with the reader's own line numbering (moveComments(java.lang.String, java.util.List<com.ultikits.ultitools.config.document.ConfigDocument.CommentMove>)), and every move is checked before any is applied, so a misalignment leaves the output as emitted (review round 3).

    • moveComments

      static String moveComments(String text, List<ConfigDocument.CommentMove> moves)
      Re-indents comment lines of text; every other character is copied unchanged. Lines are counted exactly as SnakeYAML's reader counts them - \r\n, \r, \n, U+0085, U+2028, U+2029 each end a line (review round 3 R3-01: the emitter writes U+2028 and U+2029 raw inside a value). Before any line is changed every move is checked: its line must hold, at the expected column, exactly # plus its comment, with only spaces before it; when one move fails the check, text is returned as it is, so a misalignment can never move a line it did not mean (review round 3 self-check).
      Parameters:
      text - the emitted text
      moves - the lines to re-indent
      Returns:
      the realigned text, or text unchanged
    • readerLines

      private static List<int[]> readerLines(String text)
      Each line's {start, end of content} in text, with SnakeYAML's reader's line breaks.
    • normalizeMultilineStrings

      private static org.yaml.snakeyaml.nodes.Node normalizeMultilineStrings(org.yaml.snakeyaml.nodes.Node node, Map<org.yaml.snakeyaml.nodes.Node,org.yaml.snakeyaml.nodes.Node> normalized, boolean preserveNoEof)
      Escapes preserve NEL (which the scanner normalizes) and no-EOF multiline string content.
    • carryPresentation

      private static void carryPresentation(org.yaml.snakeyaml.nodes.Node from, org.yaml.snakeyaml.nodes.Node to)
    • update

      private org.yaml.snakeyaml.nodes.Node update(org.yaml.snakeyaml.nodes.Node old, Object oldPlain, Object value)
    • merge

      private void merge(org.yaml.snakeyaml.nodes.MappingNode old, Map<?,?> oldPlain, Map<?,?> value)
    • newNode

      private org.yaml.snakeyaml.nodes.Node newNode(Object plainValue)
    • childMapping

      private org.yaml.snakeyaml.nodes.MappingNode childMapping(org.yaml.snakeyaml.nodes.MappingNode mapping, String key, Object child)
    • writtenWithNoValue

      static boolean writtenWithNoValue(org.yaml.snakeyaml.nodes.Node value)
      Whether the operator wrote no value at all for the key holding value: nothing after the colon but, at most, a comment. That is an empty plain null scalar without a token of its own, so its start and end marks coincide. A null written as ~ or null in any case, or with a tag (!!null, !<tag:yaml.org,2002:null>, !!null ''), is the operator's explicit value (maintainer decision 2026-10-06). A node built in memory has no marks and was not written by anyone, so it is not "no value" either.

      The one answer to this question for the write gate (OperatorFileWriter, which expands only a key with no value, #620) and for this document's own comment handling (set(java.util.List<java.lang.String>, java.lang.Object), merge, childMapping): gate-1 F1 of plan 17-75 found the two had separate predicates that disagreed on !!null.

      Parameters:
      value - a value node of a parsed document
      Returns:
      whether the operator wrote no value for it
    • moveInLineCommentsToKey

      private static void moveInLineCommentsToKey(org.yaml.snakeyaml.nodes.Node from, org.yaml.snakeyaml.nodes.Node key)
    • isBlockCollection

      private static boolean isBlockCollection(org.yaml.snakeyaml.nodes.Node node)
    • recordExpansion

      private void recordExpansion(List<org.yaml.snakeyaml.nodes.MappingNode> parents, List<String> keys, org.yaml.snakeyaml.nodes.MappingNode section)
      Records a section left with no value that this document made a section again (keys is its key path, parents the mappings holding each of those keys, from the top level), together with the comment lines indented under its line in the file - the lines a commented-out child leaves (#620). The reader attached them, as SnakeYAML does, to the next key in the file (or to the end of the document), where an unchanged render writes them at that key's column; they are the leading block comment lines of that key that start below the section line and at a column deeper than the section key.
    • placeExpansionComments

      private List<Runnable> placeExpansionComments()
      For a render only: moves each recorded run of comment lines indented under an expanded section to the end of the section's last value - where the reader puts such lines once the section holds keys, and where the emitter writes them at the section's own indentation, byte for byte as the operator wrote them when their column is that one - and returns how to undo it, so the document's comments stay as read (the write gate's comment ownership is computed on them). A run is moved only while the section is still in the tree, holds keys, and the next key still starts with exactly those lines.
    • setHeldComments

      private void setHeldComments(org.yaml.snakeyaml.nodes.Node holder, List<org.yaml.snakeyaml.comments.CommentLine> lines)
    • holdsAsValue

      private static boolean holdsAsValue(org.yaml.snakeyaml.nodes.MappingNode parent, org.yaml.snakeyaml.nodes.Node value)
    • startsWithSame

      private static boolean startsWithSame(List<org.yaml.snakeyaml.comments.CommentLine> lines, List<org.yaml.snakeyaml.comments.CommentLine> prefix)
    • containsSame

      private static boolean containsSame(List<org.yaml.snakeyaml.comments.CommentLine> lines, org.yaml.snakeyaml.comments.CommentLine line)
    • childPlainMapping

      private static Map<String,Object> childPlainMapping(Map<String,Object> mapping, String key)
    • findMapping

      private org.yaml.snakeyaml.nodes.MappingNode findMapping(List<String> path)
      The mapping node holding the last key of path, or null.
    • findPlainMapping

      private Map<String,Object> findPlainMapping(List<String> path)
    • findKey

      private org.yaml.snakeyaml.nodes.Node findKey(List<String> path)
    • indexOf

      private int indexOf(org.yaml.snakeyaml.nodes.MappingNode mapping, String key)
      Index of the last tuple whose key identity equals key (the last duplicate wins, as on read).
    • keyIdentity

      private String keyIdentity(org.yaml.snakeyaml.nodes.Node keyNode)
    • reRenderFromPlain

      private org.yaml.snakeyaml.nodes.MappingNode reRenderFromPlain()
    • transplantNode

      private void transplantNode(org.yaml.snakeyaml.nodes.Node from, org.yaml.snakeyaml.nodes.Node to, Set<org.yaml.snakeyaml.nodes.Node> retained)
      Carries all comment positions and the collection presentation that makes them emit correctly.
    • transplantComments

      private void transplantComments(org.yaml.snakeyaml.nodes.MappingNode from, org.yaml.snakeyaml.nodes.MappingNode to, Set<org.yaml.snakeyaml.nodes.Node> retained)
    • removeTuples

      private static void removeTuples(org.yaml.snakeyaml.nodes.MappingNode mapping, Predicate<org.yaml.snakeyaml.nodes.NodeTuple> removed)
      Every tuple deletion uses the same post-order preservation of section end comments.
    • retainDescendantEnds

      private static void retainDescendantEnds(org.yaml.snakeyaml.nodes.Node from, org.yaml.snakeyaml.nodes.Node to)
    • collectDescendantEnds

      private static void collectDescendantEnds(org.yaml.snakeyaml.nodes.Node node, List<org.yaml.snakeyaml.comments.CommentLine> ends, Set<org.yaml.snakeyaml.nodes.Node> seen)
    • collectEnds

      private static void collectEnds(org.yaml.snakeyaml.nodes.Node node, List<org.yaml.snakeyaml.comments.CommentLine> ends, Set<org.yaml.snakeyaml.nodes.Node> seen)
    • appendMappingEnds

      private static void appendMappingEnds(org.yaml.snakeyaml.nodes.MappingNode mapping, List<org.yaml.snakeyaml.comments.CommentLine> ends)
    • prependEnds

      private static void prependEnds(org.yaml.snakeyaml.nodes.Node recipient, List<org.yaml.snakeyaml.comments.CommentLine> ends)
    • claimCommentOccurrences

      private static void claimCommentOccurrences(org.yaml.snakeyaml.nodes.Node node, Set<org.yaml.snakeyaml.nodes.Node> seen, Set<org.yaml.snakeyaml.comments.CommentLine> claimed)
      An expanded alias may carry the same physical comment object to several fresh nodes.
    • unclaimedComments

      private static List<org.yaml.snakeyaml.comments.CommentLine> unclaimedComments(List<org.yaml.snakeyaml.comments.CommentLine> comments, Set<org.yaml.snakeyaml.comments.CommentLine> claimed)
    • sameComments

      private static boolean sameComments(List<org.yaml.snakeyaml.comments.CommentLine> a, List<org.yaml.snakeyaml.comments.CommentLine> b)
    • carryComments

      private static void carryComments(org.yaml.snakeyaml.nodes.Node from, org.yaml.snakeyaml.nodes.Node to)
    • requireKeys

      private static void requireKeys(List<String> path)
    • hasAnchors

      private static boolean hasAnchors(org.yaml.snakeyaml.nodes.Node node, Set<org.yaml.snakeyaml.nodes.Node> seen)
    • printable

      private static String printable(String text)
      Keeps the characters YAML allows in a stream (the YAML 1.1 printable set, tab included).
    • normalizeEscapes

      static String normalizeEscapes(String text, boolean upper, boolean latin1AsU)
      Rewrites the escapes inside every double-quoted scalar into the file's own form: \xHH as \u00HH when latin1AsU, and hex digits in upper case when upper.
    • sha256

      static String sha256(byte[] bytes)
    • compose

      private static org.yaml.snakeyaml.nodes.Node compose(String text) throws ConfigParseException
      Throws:
      ConfigParseException
    • loaderOptions

      static org.yaml.snakeyaml.LoaderOptions loaderOptions()
    • representer

      private static org.yaml.snakeyaml.representer.Representer representer()
    • dumperOptions

      private static org.yaml.snakeyaml.DumperOptions dumperOptions(DocumentStyle style)