stripSafeHeredocSubstitutions function

String? stripSafeHeredocSubstitutions(
  1. String command
)

Strip safe $(cat <<'DELIM'...DELIM) heredoc substitutions from a command. Returns the command with heredocs stripped, or null if none found.

Implementation

String? stripSafeHeredocSubstitutions(String command) {
  if (!_heredocInSubstitution.hasMatch(command)) return null;

  final heredocPattern = RegExp(
    r"""\$\(cat[ \t]*<<(-?)[ \t]*(?:'+([A-Za-z_]\w*)'+|\\([A-Za-z_]\w*))""",
  );
  var result = command;
  var found = false;
  final ranges = <({int start, int end})>[];

  for (final match in heredocPattern.allMatches(command)) {
    if (match.start > 0 && command[match.start - 1] == r'\') continue;
    final delimiter = match.group(2) ?? match.group(3);
    if (delimiter == null) continue;
    final isDash = match.group(1) == '-';
    final operatorEnd = match.start + match.group(0)!.length;

    final afterOperator = command.substring(operatorEnd);
    final openLineEnd = afterOperator.indexOf('\n');
    if (openLineEnd == -1) continue;
    if (!RegExp(
      r'^[ \t]*$',
    ).hasMatch(afterOperator.substring(0, openLineEnd))) {
      continue;
    }

    final bodyStart = operatorEnd + openLineEnd + 1;
    final bodyLines = command.substring(bodyStart).split('\n');
    for (var i = 0; i < bodyLines.length; i++) {
      final rawLine = bodyLines[i];
      final line = isDash ? rawLine.replaceFirst(RegExp(r'^\t*'), '') : rawLine;
      if (line.startsWith(delimiter)) {
        final after = line.substring(delimiter.length);
        var closePos = -1;
        if (RegExp(r'^[ \t]*\)').hasMatch(after)) {
          final lineStart =
              bodyStart +
              bodyLines.sublist(0, i).join('\n').length +
              (i > 0 ? 1 : 0);
          closePos = command.indexOf(')', lineStart);
        } else if (after.isEmpty) {
          final nextLine = i + 1 < bodyLines.length ? bodyLines[i + 1] : null;
          if (nextLine != null && RegExp(r'^[ \t]*\)').hasMatch(nextLine)) {
            final nextLineStart =
                bodyStart + bodyLines.sublist(0, i + 1).join('\n').length + 1;
            closePos = command.indexOf(')', nextLineStart);
          }
        }
        if (closePos != -1) {
          ranges.add((start: match.start, end: closePos + 1));
          found = true;
        }
        break;
      }
    }
  }

  if (!found) return null;
  for (var i = ranges.length - 1; i >= 0; i--) {
    final r = ranges[i];
    result = result.substring(0, r.start) + result.substring(r.end);
  }
  return result;
}