All files / packages/adapters/home-assistant/src yaml.ts

100% Statements 14/14
100% Branches 6/6
100% Functions 5/5
100% Lines 14/14

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62                      2x         2x         2x   2x                 14083x       6x 6x 4x   2x           14195x 9x   14186x         14176x         14072x    
// SPDX-License-Identifier: MIT
/**
 * Minimal, dependency-free YAML rendering helpers for the Home Assistant emitter.
 *
 * Only the tiny subset needed to emit Home Assistant themes is implemented:
 * double-quoted scalar values and (optionally) plain-scalar mapping keys.
 */
 
// A name is safe as an unquoted (plain) YAML mapping key when it starts with an
// alphanumeric (any Unicode letter/number) and contains only alphanumerics,
// spaces, and punctuation that carries no meaning in YAML plain scalars.
const SAFE_PLAIN_KEY = /^[\p{L}\p{N}][\p{L}\p{N} ()./-]*$/u;
 
// Plain scalars that YAML 1.1 loaders (e.g. pyyaml, which Home Assistant uses)
// resolve to booleans or null even in mapping-key position. These must always be
// double-quoted to survive as string keys.
const YAML11_RESERVED = new Set(["true", "false", "yes", "no", "on", "off", "null", "y", "n", "~"]);
 
// C0 control characters and DEL, which are not representable literally inside a
// YAML double-quoted scalar.
// eslint-disable-next-line no-control-regex
const CONTROL_CHARS = /[\x00-\x1f\x7f]/g;
 
const CONTROL_SHORTHAND: Record<string, string> = {
  "\t": "\\t",
  "\n": "\\n",
  "\r": "\\r",
  "\0": "\\0",
};
 
/** Escape a string for use inside a YAML double-quoted scalar. */
export function escapeDoubleQuoted(value: string): string {
  return value
    .replace(/\\/g, "\\\\")
    .replace(/"/g, '\\"')
    .replace(CONTROL_CHARS, (char) => {
      const shorthand = CONTROL_SHORTHAND[char];
      if (shorthand) {
        return shorthand;
      }
      return `\\x${char.charCodeAt(0).toString(16).padStart(2, "0")}`;
    });
}
 
/** Whether a mapping key can be emitted as an unquoted YAML plain scalar. */
export function isSafePlainKey(name: string): boolean {
  if (YAML11_RESERVED.has(name.toLowerCase())) {
    return false;
  }
  return SAFE_PLAIN_KEY.test(name);
}
 
/** Render a mapping key, quoting only when it is not a safe plain scalar. */
export function renderKey(name: string): string {
  return isSafePlainKey(name) ? name : `"${escapeDoubleQuoted(name)}"`;
}
 
/** Render a value as a YAML double-quoted scalar. */
export function renderValue(value: string): string {
  return `"${escapeDoubleQuoted(value)}"`;
}