Repository: opentofu/opentofu
File: internal/command/jsonformat/jsondiff/diff.go (Go)

Code before:
		// It's actually really difficult to render the diffs when some indices
		// within a list are relevant and others aren't. To make this simpler
		// we just treat all children of a relevant list as also relevant, so we
		// ignore the relevant attributes field.
		//
		// Interestingly the tofu plan builder also agrees with this, and
		// never sets relevant attributes beneath lists or sets. We're just
		// going to enforce this logic here as well. If the list is relevant
		// (decided elsewhere), then every element in the list is also relevant.
		return opts.Transform(change.GetChild(beforeIx, afterIx))
	}

	// This callback is used to determine if we should diff the elements in the slices instead of marking them as deleted and created.
	shouldDiffElement := func(a, b interface{}) bool {
		isMultilineString := false
		tA, tB := GetType(a), GetType(b)
		// If the values are both string, we check if one of them contains newlines to determine if we should diff them,
		if tA == String && tB == String {
			isMultilineString = strings.Contains(a.(string), "\n") || strings.Contains(b.(string), "\n")
		}
		// Only in case the strings have a common line we should diff them,
		if isMultilineString {
			linesA := strings.Split(a.(string), "\n")
			linesB := strings.Split(b.(string), "\n")
			for _, line := range linesA {
				for _, lineB := range linesB {
					if line == lineB {
						return true
					}
				}
			}
		}
		// If we haven't retuned at this point, we don't diff the strings and only care if both values are objects.
		return tA == Object && tB == Object
	}

	return opts.Array(collections.TransformSlice(change.Before, change.After, processIndices, shouldDiffElement))
}

func (opts JsonOpts) processObject(change structured.ChangeMap) computed.Diff {
	return opts.Object(collections.TransformMap(change.Before, change.After, change.AllKeys(), func(key string) computed.Diff {
		child := change.GetChild(key)
		if !child.RelevantAttributes.MatchesPartial() {
			child = child.AsNoOp()
		}

		return opts.Transform(child)
	}))
}

func (opts JsonOpts) processUnknown(change structured.Change) (computed.Diff, bool) {

Review comment (refactor):
I think we can simplify this nested loop with 

```
bStr := b.(string)
for _, line := range linesA {
   if ok := strings.Contains(bStr, line) {
     return true
   }
}
```

WDYT?

Code after:
		// we just treat all children of a relevant list as also relevant, so we
		// ignore the relevant attributes field.
		//
		// Interestingly the tofu plan builder also agrees with this, and
		// never sets relevant attributes beneath lists or sets. We're just
		// going to enforce this logic here as well. If the list is relevant
		// (decided elsewhere), then every element in the list is also relevant.
		return opts.Transform(change.GetChild(beforeIx, afterIx))
	}

	// This callback is used to determine if we should diff the elements in the slices instead of marking them as deleted and created.
	shouldDiffElement := func(a, b interface{}) bool {
		return (GetType(a) == Object && GetType(b) == Object) || ShouldDiffMultilineStrings(a, b)
	}

	return opts.Array(collections.TransformSlice(change.Before, change.After, processIndices, shouldDiffElement))
}

func (opts JsonOpts) processObject(change structured.ChangeMap) computed.Diff {
	return opts.Object(collections.TransformMap(change.Before, change.After, change.AllKeys(), func(key string) computed.Diff {
		child := change.GetChild(key)
		if !child.RelevantAttributes.MatchesPartial() {
			child = child.AsNoOp()
		}

		return opts.Transform(child)
	}))
}

func (opts JsonOpts) processUnknown(change structured.Change) (computed.Diff, bool) {
	return change.CheckForUnknown(
		false,
		func(current structured.Change) computed.Diff {
			return opts.Unknown(computed.Diff{}, plans.Create)
		}, func(current structured.Change, before structured.Change) computed.Diff {
			return opts.Unknown(opts.Transform(before), plans.Update)
		},
	)
}

func (opts JsonOpts) processSensitive(change structured.Change) (computed.Diff, bool) {
	return change.CheckForSensitive(opts.Transform, func(inner computed.Diff, beforeSensitive, afterSensitive bool, action plans.Action) computed.Diff {
		return opts.Sensitive(inner, beforeSensitive, afterSensitive, action)
	})
}