github.com/evanw/esbuild@v0.21.4/internal/test/diff.go (about)

     1  package test
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"github.com/evanw/esbuild/internal/logger"
     8  )
     9  
    10  func diff(old string, new string, color bool) string {
    11  	return strings.Join(diffRec(nil, strings.Split(old, "\n"), strings.Split(new, "\n"), color), "\n")
    12  }
    13  
    14  // This is a simple recursive line-by-line diff implementation
    15  func diffRec(result []string, old []string, new []string, color bool) []string {
    16  	o, n, common := lcSubstr(old, new)
    17  
    18  	if common == 0 {
    19  		// Everything changed
    20  		for _, line := range old {
    21  			if color {
    22  				result = append(result, fmt.Sprintf("%s-%s%s", logger.TerminalColors.Red, line, logger.TerminalColors.Reset))
    23  			} else {
    24  				result = append(result, "-"+line)
    25  			}
    26  		}
    27  		for _, line := range new {
    28  			if color {
    29  				result = append(result, fmt.Sprintf("%s+%s%s", logger.TerminalColors.Green, line, logger.TerminalColors.Reset))
    30  			} else {
    31  				result = append(result, "+"+line)
    32  			}
    33  		}
    34  	} else {
    35  		// Something in the middle stayed the same
    36  		result = diffRec(result, old[:o], new[:n], color)
    37  		for _, line := range old[o : o+common] {
    38  			if color {
    39  				result = append(result, fmt.Sprintf("%s %s%s", logger.TerminalColors.Dim, line, logger.TerminalColors.Reset))
    40  			} else {
    41  				result = append(result, " "+line)
    42  			}
    43  		}
    44  		result = diffRec(result, old[o+common:], new[n+common:], color)
    45  	}
    46  
    47  	return result
    48  }
    49  
    50  // From: https://en.wikipedia.org/wiki/Longest_common_substring_problem
    51  func lcSubstr(S []string, T []string) (int, int, int) {
    52  	r := len(S)
    53  	n := len(T)
    54  	Lprev := make([]int, n)
    55  	Lnext := make([]int, n)
    56  	z := 0
    57  	retI := 0
    58  	retJ := 0
    59  
    60  	for i := 0; i < r; i++ {
    61  		for j := 0; j < n; j++ {
    62  			if S[i] == T[j] {
    63  				if j == 0 {
    64  					Lnext[j] = 1
    65  				} else {
    66  					Lnext[j] = Lprev[j-1] + 1
    67  				}
    68  				if Lnext[j] > z {
    69  					z = Lnext[j]
    70  					retI = i + 1
    71  					retJ = j + 1
    72  				}
    73  			} else {
    74  				Lnext[j] = 0
    75  			}
    76  		}
    77  		Lprev, Lnext = Lnext, Lprev
    78  	}
    79  
    80  	return retI - z, retJ - z, z
    81  }