acceptMarksInPlace function

MarksInPlaceResult acceptMarksInPlace(
  1. String yamlText,
  2. SomMetaTree tree, {
  3. String? under,
})

Accepts the inline change marks of yamlText (decoded against tree) in place, only inside the section under when given (/-separated section ids); see the file comment.

Throws MarksSectionNotFound when under names no section.

Implementation

MarksInPlaceResult acceptMarksInPlace(
  String yamlText,
  SomMetaTree tree, {
  String? under,
}) {
  final orig = _snapshot(SpecDocumentYaml.decode(yamlText, tree).document);
  final expected = SpecDocumentYaml.decode(yamlText, tree).document;
  final report = SpecReviewAnnotations(expected).acceptAllMarks();
  final lines = yamlText.split('\n');
  var from = 0, to = lines.length;
  String? sectionLines;
  if (under != null) {
    for (final id in under.split('/')) {
      final re = RegExp('^( *)${RegExp.escape(id)}( [A-Za-z0-9]+)?:');
      var k = from;
      while (k < to && re.firstMatch(lines[k]) == null) {
        k++;
      }
      if (k >= to) throw MarksSectionNotFound(id, lines[from]);
      final ind = re.firstMatch(lines[k])!.group(1)!.length;
      var e = k + 1;
      while (e < to &&
          (lines[e].isEmpty ||
              lines[e].length - lines[e].trimLeft().length > ind)) {
        e++;
      }
      from = k;
      to = e;
    }
    sectionLines = '${from + 1}-$to';
  }
  final out = <String>[];
  var changed = 0;
  var i = 0;
  while (i < lines.length) {
    final l = lines[i];
    if (i < from || i >= to) {
      out.add(l);
      i++;
      continue;
    }
    final q = RegExp(
      r'^(\s*[A-Za-z][A-Za-z0-9]*: )"(\{~~[^"~]*~>([^"~]*)~~\})"\s*$',
    ).firstMatch(l);
    if (q != null) {
      out.add('${q.group(1)}"${q.group(3)}"');
      changed++;
      i++;
      continue;
    }
    out.add(l);
    i++;
    if (!l.endsWith(': |2-')) continue;
    final col =
        l.length -
        l.trimLeft().length +
        (l.trimLeft().startsWith('- ') ? 2 : 0);
    final ind = ' ' * (col + 2);
    var j = i;
    var lastBody = i - 1;
    while (j < lines.length && (lines[j].isEmpty || lines[j].startsWith(ind))) {
      if (lines[j].isNotEmpty) lastBody = j;
      j++;
    }
    final body = lines.sublist(i, lastBody + 1);
    final value = body
        .map((s) => s.isEmpty ? '' : s.substring(ind.length))
        .join('\n');
    final nv = applyInlineMarksText(value, accept: true);
    if (nv != value) {
      changed++;
      if (nv.isNotEmpty) {
        out.addAll(nv.split('\n').map((s) => s.isEmpty ? '' : '$ind$s'));
      }
    } else {
      out.addAll(body);
    }
    i = lastBody + 1;
  }
  final result = out.join('\n');
  final got = SpecDocumentYaml.decode(result, tree).document;
  final a = _snapshot(expected), b = _snapshot(got);
  final differences = <String>[];
  var count = 0;
  String clip(String? v) =>
      v == null ? 'null' : v.substring(0, v.length.clamp(0, 200));
  for (final k in {...a.keys, ...b.keys}) {
    String n(String? v) => v ?? '';
    if (n(a[k]) != n(b[k]) && (under == null || n(orig[k]) != n(b[k]))) {
      if (count++ < 10) {
        differences.add(
          'DIFF $k\n  runtime: ${clip(a[k])}\n  file:    ${clip(b[k])}',
        );
      }
    }
  }
  return MarksInPlaceResult(
    text: result,
    applied: report.applied.length,
    malformed: report.malformed.length,
    changedValues: changed,
    differences: differences,
    differenceCount: count,
    marksLeft: SpecReviewAnnotations(got).counts().toJson(),
    sectionLines: sectionLines,
  );
}