github.com/tomwright/dasel@v1.27.3/selector.go (about)

     1  package dasel
     2  
     3  import (
     4  	"errors"
     5  	"strings"
     6  )
     7  
     8  // ErrDynamicSelectorBracketMismatch is returned when the number of opening brackets doesn't equal that
     9  // of the closing brackets.
    10  var ErrDynamicSelectorBracketMismatch = errors.New("dynamic selector bracket mismatch")
    11  
    12  // ExtractNextSelector returns the next selector from the given input.
    13  func ExtractNextSelector(input string) (string, int) {
    14  	escapedIndex := -1
    15  	res := ""
    16  	i := 0
    17  	read := 0
    18  	for k, v := range input {
    19  		curRuneStr := string(v)
    20  		curRuneLength := len(curRuneStr)
    21  		if escapedIndex == k-1 && k != 0 {
    22  			// last character was escape character
    23  			res += curRuneStr
    24  			read += curRuneLength
    25  			continue
    26  		}
    27  
    28  		if v == '(' || v == '[' {
    29  			i++
    30  		} else if v == ')' || v == ']' {
    31  			i--
    32  		}
    33  
    34  		if v == '\\' {
    35  			escapedIndex = k
    36  			read += curRuneLength
    37  			continue
    38  		}
    39  
    40  		if i == 0 && v == '.' && k != 0 {
    41  			break
    42  		}
    43  		res += curRuneStr
    44  		read += curRuneLength
    45  	}
    46  	return res, read
    47  }
    48  
    49  // DynamicSelectorToGroups takes a dynamic selector and splits it into groups.
    50  func DynamicSelectorToGroups(selector string) ([]string, error) {
    51  	i := 0
    52  	tmp := ""
    53  	res := make([]string, 0)
    54  	for k, v := range selector {
    55  		if v == '(' {
    56  			if i > 0 {
    57  				tmp += string(v)
    58  			} else {
    59  				tmp = ""
    60  			}
    61  			i++
    62  		} else if v == ')' {
    63  			i--
    64  			if i == 0 {
    65  				res = append(res, tmp)
    66  				tmp = ""
    67  			} else {
    68  				tmp += string(v)
    69  			}
    70  		} else if v == '.' && i == 0 && k != 0 {
    71  			return res, nil
    72  		} else {
    73  			tmp += string(v)
    74  		}
    75  	}
    76  	if i != 0 {
    77  		return nil, ErrDynamicSelectorBracketMismatch
    78  	}
    79  	return res, nil
    80  }
    81  
    82  // DynamicSelectorParts contains the parts for a dynamic selector.
    83  type DynamicSelectorParts struct {
    84  	Key        string
    85  	Comparison string
    86  	Value      string
    87  }
    88  
    89  var comparisons = []string{
    90  	"=",
    91  	"!=",
    92  	"<",
    93  	"<=",
    94  	">",
    95  	">=",
    96  }
    97  
    98  func isBuildingComparison(comparison string) bool {
    99  	for _, c := range comparisons {
   100  		if strings.HasPrefix(c, comparison) {
   101  			return true
   102  		}
   103  	}
   104  	return false
   105  }
   106  
   107  func isValidComparison(comparison string) bool {
   108  	for _, c := range comparisons {
   109  		if comparison == c {
   110  			return true
   111  		}
   112  	}
   113  	return false
   114  }
   115  
   116  // FindDynamicSelectorParts extracts the parts from the dynamic selector given.
   117  func FindDynamicSelectorParts(selector string) DynamicSelectorParts {
   118  	i := 0
   119  	parts := DynamicSelectorParts{}
   120  	for _, v := range selector {
   121  		switch {
   122  
   123  		// Start of a group
   124  		case v == '(':
   125  			if parts.Comparison == "" {
   126  				parts.Key += string(v)
   127  			} else {
   128  				parts.Value += string(v)
   129  			}
   130  			i++
   131  
   132  		// End of a group
   133  		case v == ')':
   134  			i--
   135  			if parts.Comparison == "" {
   136  				parts.Key += string(v)
   137  			} else {
   138  				parts.Value += string(v)
   139  			}
   140  
   141  		// Matches a comparison operator
   142  		case i == 0 && isValidComparison(parts.Comparison+string(v)):
   143  			parts.Comparison += string(v)
   144  
   145  		// Is building a comparison character
   146  		case i == 0 && isBuildingComparison(parts.Comparison+string(v)):
   147  			parts.Comparison += string(v)
   148  
   149  		// Add to key or value based on comparison existence
   150  		default:
   151  			if parts.Comparison == "" {
   152  				parts.Key += string(v)
   153  			} else {
   154  				parts.Value += string(v)
   155  			}
   156  		}
   157  	}
   158  	return parts
   159  }