chromium/chrome/browser/resources/key_value_pair_viewer_shared/key_value_pair_parser.ts

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import type {KeyValuePairEntry} from './key_value_pair_entry.js';

// Contents of lines that act as delimiters for multi-line values.
const DELIM_START = '---------- START ----------';
const DELIM_END = '---------- END ----------';

/**
 * Convert text-based log into list of name-value pairs.
 * @param text The raw text of a log.
 * @return The parse result or null if any parsing error occurred.
 */
export function parseKeyValuePairEntry(text: string): KeyValuePairEntry[]|null {
  const details = [];
  const lines = text.split('\n');
  for (let i = 0, len = lines.length; i < len; i++) {
    // Skip empty lines.
    if (!lines[i]) {
      continue;
    }

    const delimiter = lines[i]!.indexOf('=');
    if (delimiter <= 0) {
      if (i === lines.length - 1) {
        break;
      }
      // If '=' is missing here, format is wrong.
      return null;
    }

    const name = lines[i]!.substring(0, delimiter);
    let value = '';
    // Set value if non-empty
    if (lines[i]!.length > delimiter + 1) {
      value = lines[i]!.substring(delimiter + 1);
    }

    // Delimiters are based on kMultilineIndicatorString, kMultilineStartString,
    // and kMultilineEndString in components/feedback/feedback_data.cc.
    // If these change, we should check for both the old and new versions.
    if (value === '<multiline>') {
      // Skip start delimiter.
      if (i === len - 1 || lines[++i]!.indexOf(DELIM_START) === -1) {
        return null;
      }

      ++i;
      value = '';
      // Append lines between start and end delimiters.
      while (i < len && lines[i] !== DELIM_END) {
        value += lines[i++] + '\n';
      }

      // Remove trailing newline.
      if (value) {
        value = value.substr(0, value.length - 1);
      }
    }
    details.push({key: name, value: value});
  }

  return details;
}