Repository: nats-io/nats-server
Pull request #3303 (2022-07-28 23:35:16)

Revert direct changes to main
This reverts commit cf784c19f095fd1c0c8c58609de259c2daed0bd8.
This reverts commit c269a1ca095b099b66aed8582d4a9ff4fb234ce5.

(done using `git revert`)

Signed-off-by: Ivan Kozlovic <ivan@synadia.com>



Patch:
diff --git a/server/accounts.go b/server/accounts.go
index fb5bdb21..e9a814f8 100644
--- a/server/accounts.go
+++ b/server/accounts.go
@@ -166,26 +166,8 @@ const (
 )
 
 var commaSeparatorRegEx = regexp.MustCompile(`,\s*`)
-var partitionMappingFunctionRegEx = regexp.MustCompile(`{{\s*[pP]artition\s*\((.*)\)\s*}}`)
-var wildcardMappingFunctionRegEx = regexp.MustCompile(`{{\s*[wW]ildcard\s*\((.*)\)\s*}}`)
-var splitFromLeftMappingFunctionRegEx = regexp.MustCompile(`{{\s*[sS]plit[fF]rom[lL]eft\s*\((.*)\)\s*}}`)
-var splitFromRightMappingFunctionRegEx = regexp.MustCompile(`{{\s*[sS]plit[fF]rom[rR]ight\s*\((.*)\)\s*}}`)
-var sliceFromLeftMappingFunctionRegEx = regexp.MustCompile(`{{\s*[sS]lice[fF]rom[lL]eft\s*\((.*)\)\s*}}`)
-var sliceFromRightMappingFunctionRegEx = regexp.MustCompile(`{{\s*[sS]lice[fF]rom[rR]ight\s*\((.*)\)\s*}}`)
-var splitMappingFunctionRegEx = regexp.MustCompile(`{{\s*[sS]plit\s*\((.*)\)\s*}}`)
-
-// Enum for the subject mapping transform function types
-const (
-	NoTransform int16 = iota
-	BadTransform
-	Partition
-	Wildcard
-	SplitFromLeft
-	SplitFromRight
-	SliceFromLeft
-	SliceFromRight
-	Split
-)
+var partitionMappingFunctionRegEx = regexp.MustCompile(`{{\s*partition\s*\((.*)\)\s*}}`)
+var wildcardMappingFunctionRegEx = regexp.MustCompile(`{{\s*wildcard\s*\((.*)\)\s*}}`)
 
 // String helper.
 func (rt ServiceRespType) String() string {
@@ -863,7 +845,7 @@ func (a *Account) selectMappedSubject(dest string) (string, bool) {
 	}
 
 	if d != nil {
-		if len(d.tr.dtokmftokindexesargs) == 0 {
+		if len(d.tr.dtpi) == 0 {
 			ndest = d.tr.dest
 		} else if nsubj, err := d.tr.transform(tts); err == nil {
 			ndest = nsubj
@@ -4181,13 +4163,11 @@ func (dr *CacheDirAccResolver) Reload() error {
 // These can also be used for proper mapping on wildcard exports/imports.
 // These will be grouped and caching and locking are assumed to be in the upper layers.
 type transform struct {
-	src, dest            string
-	dtoks                []string // destination tokens
-	stoks                []string // source tokens
-	dtokmftypes          []int16  // destination token mapping function types
-	dtokmftokindexesargs [][]int  // destination token mapping function array of source token index arguments
-	dtokmfintargs        []int32  // destination token mapping function int32 arguments
-	dtokmfstringargs     []string // destination token mapping function string arguments
+	src, dest string
+	dtoks     []string
+	stoks     []string
+	dtpi      [][]int // destination token position indexes
+	dtpinp    []int32 // destination token position index number of partitions
 }
 
 func getMappingFunctionArgs(functionRegEx *regexp.Regexp, token string) []string {
@@ -4198,19 +4178,17 @@ func getMappingFunctionArgs(functionRegEx *regexp.Regexp, token string) []string
 	return nil
 }
 
-// Helper to ingest and index the transform destination token (e.g. $x or {{}}) in the token
-// returns a transformation type, and three function arguments: an array of source subject token indexes, and a single number (e.g. number of partitions, or a slice size), and a string (e.g.a split delimiter)
-
-func indexPlaceHolders(token string) (int16, []int, int32, string, error) {
+// Helper to pull raw place holder indexes and number of partitions. Returns -1 if not a place holder.
+func placeHolderIndex(token string) ([]int, int32, error) {
 	length := len(token)
 	if length > 1 {
 		// old $1, $2, etc... mapping format still supported to maintain backwards compatibility
 		if token[0] == '$' { // simple non-partition mapping
 			tp, err := strconv.Atoi(token[1:])
 			if err != nil {
-				return NoTransform, []int{-1}, -1, "", nil // other things rely on tokens starting with $ so not an error just leave it as is
+				return []int{-1}, -1, nil
 			}
-			return Wildcard, []int{tp}, -1, "", nil
+			return []int{tp}, -1, nil
 		}
 
 		// New 'mustache' style mapping
@@ -4219,152 +4197,45 @@ func indexPlaceHolders(token string) (int16, []int, int32, string, error) {
 			args := getMappingFunctionArgs(wildcardMappingFunctionRegEx, token)
 			if args != nil {
 				if len(args) == 1 && args[0] == _EMPTY_ {
-					return BadTransform, []int{}, -1, "", &mappingDestinationErr{token, ErrorMappingDestinationFunctionNotEnoughArguments}
+					return []int{-1}, -1, &mappingDestinationErr{token, ErrorMappingDestinationFunctionNotEnoughArguments}
 				}
 				if len(args) == 1 {
-					tokenIndex, err := strconv.Atoi(strings.Trim(args[0], " "))
+					tp, err := strconv.Atoi(strings.Trim(args[0], " "))
 					if err != nil {
-						return BadTransform, []int{}, -1, "", &mappingDestinationErr{token, ErrorMappingDestinationFunctionInvalidArgument}
+						return []int{}, -1, &mappingDestinationErr{token, ErrorMappingDestinationFunctionInvalidArgument}
 					}
-					return Wildcard, []int{tokenIndex}, -1, "", nil
+					return []int{tp}, -1, nil
 				} else {
-					return BadTransform, []int{}, -1, "", &mappingDestinationErr{token, ErrorMappingDestinationFunctionTooManyArguments}
+					return []int{}, -1, &mappingDestinationErr{token, ErrorMappingDestinationFunctionTooManyArguments}
 				}
 			}
-
 			// partition(number of partitions, token1, token2, ...)
 			args = getMappingFunctionArgs(partitionMappingFunctionRegEx, token)
 			if args != nil {
 				if len(args) < 2 {
-					return BadTransform, []int{}, -1, "", &mappingDestinationErr{token, ErrorMappingDestinationFunctionNotEnoughArguments}
+					return []int{-1}, -1, &mappingDestinationErr{token, ErrorMappingDestinationFunctionNotEnoughArguments}
 				}
 				if len(args) >= 2 {
-					mappingFunctionIntArg, err := strconv.Atoi(strings.Trim(args[0], " "))
+					tphnp, err := strconv.Atoi(strings.Trim(args[0], " "))
 					if err != nil {
-						return BadTransform, []int{}, -1, "", &mappingDestinationErr{token, ErrorMappingDestinationFunctionInvalidArgument}
+						return []int{}, -1, &mappingDestinationErr{token, ErrorMappingDestinationFunctionInvalidArgument}
 					}
 					var numPositions = len(args[1:])
-					tokenIndexes := make([]int, numPositions)
+					tps := make([]int, numPositions)
 					for ti, t := range args[1:] {
 						i, err := strconv.Atoi(strings.Trim(t, " "))
 						if err != nil {
-							return BadTransform, []int{}, -1, "", &mappingDestinationErr{token, ErrorMappingDestinationFunctionInvalidArgument}
+							return []int{}, -1, &mappingDestinationErr{token, ErrorMappingDestinationFunctionInvalidArgument}
 						}
-						tokenIndexes[ti] = i
+						tps[ti] = i
 					}
-
-					return Partition, tokenIndexes, int32(mappingFunctionIntArg), "", nil
-				}
-			}
-
-			// SplitFromLeft(token, position)
-			args = getMappingFunctionArgs(splitFromLeftMappingFunctionRegEx, token)
-			if args != nil {
-				if len(args) < 2 {
-					return BadTransform, []int{}, -1, "", &mappingDestinationErr{token, ErrorMappingDestinationFunctionNotEnoughArguments}
-				}
-				if len(args) > 2 {
-					return BadTransform, []int{}, -1, "", &mappingDestinationErr{token, ErrorMappingDestinationFunctionInvalidArgument}
-				}
-				i, err := strconv.Atoi(strings.Trim(args[0], " "))
-				if err != nil {
-					return BadTransform, []int{}, -1, "", &mappingDestinationErr{token, ErrorMappingDestinationFunctionInvalidArgument}
+					return tps, int32(tphnp), nil
 				}
-				mappingFunctionIntArg, err := strconv.Atoi(strings.Trim(args[1], " "))
-				if err != nil {
-					return BadTransform, []int{}, -1, "", &mappingDestinationErr{token, ErrorMappingDestinationFunctionInvalidArgument}
-				}
-
-				return SplitFromLeft, []int{i}, int32(mappingFunctionIntArg), "", nil
 			}
-
-			// SplitFromRight(token, position)
-			args = getMappingFunctionArgs(splitFromRightMappingFunctionRegEx, token)
-			if args != nil {
-				if len(args) < 2 {
-					return BadTransform, []int{}, -1, "", &mappingDestinationErr{token, ErrorMappingDestinationFunctionNotEnoughArguments}
-				}
-				if len(args) > 2 {
-					return BadTransform, []int{}, -1, "", &mappingDestinationErr{token, ErrorMappingDestinationFunctionInvalidArgument}
-				}
-				i, err := strconv.Atoi(strings.Trim(args[0], " "))
-				if err != nil {
-					return BadTransform, []int{}, -1, "", &mappingDestinationErr{token, ErrorMappingDestinationFunctionInvalidArgument}
-				}
-				mappingFunctionIntArg, err := strconv.Atoi(strings.Trim(args[1], " "))
-				if err != nil {
-					return BadTransform, []int{}, -1, "", &mappingDestinationErr{token, ErrorMappingDestinationFunctionInvalidArgument}
-				}
-
-				return SplitFromRight, []int{i}, int32(mappingFunctionIntArg), "", nil
-			}
-
-			// SliceFromLeft(token, position)
-			args = getMappingFunctionArgs(sliceFromLeftMappingFunctionRegEx, token)
-			if args != nil {
-				if len(args) < 2 {
-					return BadTransform, []int{}, -1, "", &mappingDestinationErr{token, ErrorMappingDestinationFunctionNotEnoughArguments}
-				}
-				if len(args) > 2 {
-					return BadTransform, []int{}, -1, "", &mappingDestinationErr{token, ErrorMappingDestinationFunctionInvalidArgument}
-				}
-				i, err := strconv.Atoi(strings.Trim(args[0], " "))
-				if err != nil {
-					return BadTransform, []int{}, -1, "", &mappingDestinationErr{token, ErrorMappingDestinationFunctionInvalidArgument}
-				}
-				mappingFunctionIntArg, err := strconv.Atoi(strings.Trim(args[1], " "))
-				if err != nil {
-					return BadTransform, []int{}, -1, "", &mappingDestinationErr{token, ErrorMappingDestinationFunctionInvalidArgument}
-				}
-
-				return SliceFromLeft, []int{i}, int32(mappingFunctionIntArg), "", nil
-			}
-
-			// SliceFromRight(token, position)
-			args = getMappingFunctionArgs(sliceFromRightMappingFunctionRegEx, token)
-			if args != nil {
-				if len(args) < 2 {
-					return BadTransform, []int{}, -1, "", &mappingDestinationErr{token, ErrorMappingDestinationFunctionNotEnoughArguments}
-				}
-				if len(args) > 2 {
-					return BadTransform, []int{}, -1, "", &mappingDestinationErr{token, ErrorMappingDestinationFunctionInvalidArgument}
-				}
-				i, err := strconv.Atoi(strings.Trim(args[0], " "))
-				if err != nil {
-					return BadTransform, []int{}, -1, "", &mappingDestinationErr{token, ErrorMappingDestinationFunctionInvalidArgument}
-				}
-				mappingFunctionIntArg, err := strconv.Atoi(strings.Trim(args[1], " "))
-				if err != nil {
-					return BadTransform, []int{}, -1, "", &mappingDestinationErr{token, ErrorMappingDestinationFunctionInvalidArgument}
-				}
-
-				return SliceFromRight, []int{i}, int32(mappingFunctionIntArg), "", nil
-			}
-
-			// split(token, deliminator)
-			args = getMappingFunctionArgs(splitMappingFunctionRegEx, token)
-			if args != nil {
-				if len(args) < 2 {
-					return BadTransform, []int{}, -1, "", &mappingDestinationErr{token, ErrorMappingDestinationFunctionNotEnoughArguments}
-				}
-				if len(args) > 2 {
-					return BadTransform, []int{}, -1, "", &mappingDestinationErr{token, ErrorMappingDestinationFunctionInvalidArgument}
-				}
-				i, err := strconv.Atoi(strings.Trim(args[0], " "))
-				if err != nil {
-					return BadTransform, []int{}, -1, "", &mappingDestinationErr{token, ErrorMappingDestinationFunctionInvalidArgument}
-				}
-				if strings.Contains(args[1], " ") || strings.Contains(args[1], ".") {
-					return BadTransform, []int{}, -1, "", &mappingDestinationErr{token: token, err: ErrorMappingDestinationFunctionInvalidArgument}
-				}
-
-				return Split, []int{i}, -1, args[1], nil
-			}
-
-			return BadTransform, []int{}, -1, "", &mappingDestinationErr{token, ErrUnknownMappingDestinationFunction}
+			return []int{}, -1, &mappingDestinationErr{token, ErrUnknownMappingDestinationFunction}
 		}
 	}
-	return NoTransform, []int{-1}, -1, "", nil
+	return []int{-1}, -1, nil
 }
 
 // SubjectTransformer transforms subjects using mappings
@@ -4392,10 +4263,8 @@ func newTransform(src, dest string) (*transform, error) {
 		return nil, ErrBadSubject
 	}
 
-	var dtokMappingFunctionTypes []int16
-	var dtokMappingFunctionTokenIndexes [][]int
-	var dtokMappingFunctionIntArgs []int32
-	var dtokMappingFunctionStringArgs []string
+	var dtpi [][]int
+	var dtpinb []int32
 
 	// If the src has partial wildcards then the dest needs to have the token place markers.
 	if npwcs > 0 || hasFwc {
@@ -4409,33 +4278,25 @@ func newTransform(src, dest string) (*transform, error) {
 
 		nphs := 0
 		for _, token := range dtokens {
-			tranformType, transformArgWildcardIndexes, transfomArgInt, transformArgString, err := indexPlaceHolders(token)
+			tp, nb, err := placeHolderIndex(token)
 			if err != nil {
 				return nil, err
 			}
-
-			if tranformType == NoTransform {
-				{
-					dtokMappingFunctionTypes = append(dtokMappingFunctionTypes, NoTransform)
-					dtokMappingFunctionTokenIndexes = append(dtokMappingFunctionTokenIndexes, []int{-1})
-					dtokMappingFunctionIntArgs = append(dtokMappingFunctionIntArgs, -1)
-					dtokMappingFunctionStringArgs = append(dtokMappingFunctionStringArgs, "")
-				}
-			} else {
+			if tp[0] >= 0 {
 				nphs++
 				// Now build up our runtime mapping from dest to source tokens.
 				var stis []int
-				for _, wildcardIndex := range transformArgWildcardIndexes {
-					if wildcardIndex > npwcs {
-						return nil, &mappingDestinationErr{fmt.Sprintf("%s: [%d]", token, wildcardIndex), ErrorMappingDestinationFunctionWildcardIndexOutOfRange}
+				for _, position := range tp {
+					if position > npwcs {
+						return nil, &mappingDestinationErr{fmt.Sprintf("%s: [%d]", token, position), ErrorMappingDestinationFunctionWildcardIndexOutOfRange}
 					}
-					stis = append(stis, sti[wildcardIndex])
+					stis = append(stis, sti[position])
 				}
-				dtokMappingFunctionTypes = append(dtokMappingFunctionTypes, tranformType)
-				dtokMappingFunctionTokenIndexes = append(dtokMappingFunctionTokenIndexes, stis)
-				dtokMappingFunctionIntArgs = append(dtokMappingFunctionIntArgs, transfomArgInt)
-				dtokMappingFunctionStringArgs = append(dtokMappingFunctionStringArgs, transformArgString)
-
+				dtpi = append(dtpi, stis)
+				dtpinb = append(dtpinb, nb)
+			} else {
+				dtpi = append(dtpi, []int{-1})
+				dtpinb = append(dtpinb, -1)
 			}
 		}
 		if nphs < npwcs {
@@ -4444,7 +4305,7 @@ func newTransform(src, dest string) (*transform, error) {
 		}
 	}
 
-	return &transform{src: src, dest: dest, dtoks: dtokens, stoks: stokens, dtokmftypes: dtokMappingFunctionTypes, dtokmftokindexesargs: dtokMappingFunctionTokenIndexes, dtokmfintargs: dtokMappingFunctionIntArgs, dtokmfstringargs: dtokMappingFunctionStringArgs}, nil
+	return &transform{src: src, dest: dest, dtoks: dtokens, stoks: stokens, dtpi: dtpi, dtpinp: dtpinb}, nil
 }
 
 // Match will take a literal published subject that is associated with a client and will match and transform
@@ -4506,108 +4367,41 @@ func (tr *transform) getHashPartition(key []byte, numBuckets int) string {
 
 // Do a transform on the subject to the dest subject.
 func (tr *transform) transform(tokens []string) (string, error) {
-	if len(tr.dtokmftypes) == 0 {
+	if len(tr.dtpi) == 0 {
 		return tr.dest, nil
 	}
 
 	var b strings.Builder
-	var transformedToken string
+	var token string
 
-	// We need to walk destination tokens and create the mapped subject pulling tokens or mapping functions
+	// We need to walk destination tokens and create the mapped subject pulling tokens from src.
 	// This is slow and that is ok, transforms should have caching layer in front for mapping transforms
 	// and export/import semantics with streams and services.
-	li := len(tr.dtokmftypes) - 1
-	for i, mfType := range tr.dtokmftypes {
-		if mfType == NoTransform {
-			transformedToken = tr.dtoks[i]
+	li := len(tr.dtpi) - 1
+	for i, index := range tr.dtpi {
+		// <0 means use destination token.
+		if index[0] < 0 {
+			token = tr.dtoks[i]
 			// Break if fwc
-			if len(transformedToken) == 1 && transformedToken[0] == fwc {
+			if len(token) == 1 && token[0] == fwc {
 				break
 			}
 		} else {
-			switch mfType {
-			case Partition:
+			// >= 0 means use source map index to figure out which source token to pull.
+			if tr.dtpinp[i] > 0 { // there is a valid (i.e. not -1) value for number of partitions, this is a partition transform token
 				var (
 					_buffer       [64]byte
 					keyForHashing = _buffer[:0]
 				)
-				for _, sourceToken := range tr.dtokmftokindexesargs[i] {
+				for _, sourceToken := range tr.dtpi[i] {
 					keyForHashing = append(keyForHashing, []byte(tokens[sourceToken])...)
 				}
-				transformedToken = tr.getHashPartition(keyForHashing, int(tr.dtokmfintargs[i]))
-			case Wildcard: // simple substitution
-				transformedToken = tokens[tr.dtokmftokindexesargs[i][0]]
-			case SplitFromLeft:
-				sourceToken := tokens[tr.dtokmftokindexesargs[i][0]]
-				sourceTokenLen := len(sourceToken)
-				position := int(tr.dtokmfintargs[i])
-				if position > 0 && position < sourceTokenLen {
-					transformedToken = sourceToken[:position] + "." + sourceToken[position:]
-				} else { // too small to split at the requested position: don't split
-					transformedToken = sourceToken
-				}
-			case SplitFromRight:
-				sourceToken := tokens[tr.dtokmftokindexesargs[i][0]]
-				sourceTokenLen := len(sourceToken)
-				position := int(tr.dtokmfintargs[i])
-				if position > 0 && position < sourceTokenLen {
-					transformedToken = sourceToken[:sourceTokenLen-position] + "." + sourceToken[sourceTokenLen-position:]
-				} else { // too small to split at the requested position: don't split
-					transformedToken = sourceToken
-				}
-			case SliceFromLeft:
-				sourceToken := tokens[tr.dtokmftokindexesargs[i][0]]
-				sourceTokenLen := len(sourceToken)
-				sliceSize := int(tr.dtokmfintargs[i])
-				if sliceSize > 0 && sliceSize < sourceTokenLen {
-					transformedToken = ""
-					for i := 0; i+sliceSize <= sourceTokenLen; i += sliceSize {
-						if i != 0 {
-							transformedToken = transformedToken + "."
-						}
-						transformedToken = transformedToken + sourceToken[i:i+sliceSize]
-						if i+sliceSize != sourceTokenLen && i+sliceSize+sliceSize > sourceTokenLen {
-							transformedToken = transformedToken + "." + sourceToken[i+sliceSize:]
-							break
-						}
-					}
-				} else { // too small to slice at the requested size: don't slice
-					transformedToken = sourceToken
-				}
-			case SliceFromRight:
-				sourceToken := tokens[tr.dtokmftokindexesargs[i][0]]
-				sourceTokenLen := len(sourceToken)
-				sliceSize := int(tr.dtokmfintargs[i])
-				if sliceSize > 0 && sliceSize < sourceTokenLen {
-					transformedToken = ""
-					remainder := sourceTokenLen % sliceSize
-					if remainder > 0 {
-						transformedToken = transformedToken + sourceToken[:remainder] + "."
-					}
-					for i := remainder; i+sliceSize <= sourceTokenLen; i += sliceSize {
-						transformedToken = transformedToken + sourceToken[i:i+sliceSize]
-						if i+sliceSize < sourceTokenLen {
-							transformedToken = transformedToken + "."
-						}
-					}
-				} else { // too small to slice at the requested size: don't slice
-					transformedToken = sourceToken
-				}
-			case Split:
-				sourceToken := tokens[tr.dtokmftokindexesargs[i][0]]
-				splits := strings.Split(sourceToken, tr.dtokmfstringargs[i])
-				transformedToken = ""
-				for j, split := range splits {
-					if split != "" {
-						transformedToken = transformedToken + split
-					}
-					if j < len(splits)-1 && splits[j+1] != "" && j != 0 {
-						transformedToken = transformedToken + "."
-					}
-				}
+				token = tr.getHashPartition(keyForHashing, int(tr.dtpinp[i]))
+			} else { // back to normal substitution
+				token = tokens[tr.dtpi[i][0]]
 			}
 		}
-		b.WriteString(transformedToken)
+		b.WriteString(token)
 		if i < li {
 			b.WriteByte(btsep)
 		}
@@ -4627,7 +4421,7 @@ func (tr *transform) transform(tokens []string) (string, error) {
 
 // Reverse a transform.
 func (tr *transform) reverse() *transform {
-	if len(tr.dtokmftokindexesargs) == 0 {
+	if len(tr.dtpi) == 0 {
 		rtr, _ := newTransform(tr.dest, tr.src)
 		return rtr
 	}
diff --git a/server/sublist.go b/server/sublist.go
index bae47306..99230dde 100644
--- a/server/sublist.go
+++ b/server/sublist.go
@@ -1140,13 +1140,7 @@ func ValidateMappingDestination(subject string) error {
 		}
 
 		if length > 4 && t[0] == '{' && t[1] == '{' && t[length-2] == '}' && t[length-1] == '}' {
-			if !partitionMappingFunctionRegEx.MatchString(t) &&
-				!wildcardMappingFunctionRegEx.MatchString(t) &&
-				!splitFromLeftMappingFunctionRegEx.MatchString(t) &&
-				!splitFromRightMappingFunctionRegEx.MatchString(t) &&
-				!sliceFromLeftMappingFunctionRegEx.MatchString(t) &&
-				!sliceFromRightMappingFunctionRegEx.MatchString(t) &&
-				!splitMappingFunctionRegEx.MatchString(t) {
+			if !partitionMappingFunctionRegEx.MatchString(t) && !wildcardMappingFunctionRegEx.MatchString(t) {
 				return &mappingDestinationErr{t, ErrUnknownMappingDestinationFunction}
 			} else {
 				continue


Test patch:
diff --git a/server/accounts_test.go b/server/accounts_test.go
index f9bc8623..435b418b 100644
--- a/server/accounts_test.go
+++ b/server/accounts_test.go
@@ -50,54 +50,47 @@ func simpleAccountServer(t *testing.T) (*Server, *Account, *Account) {
 
 func TestPlaceHolderIndex(t *testing.T) {
 	testString := "$1"
-	transformType, indexes, nbPartitions, _, err := indexPlaceHolders(testString)
-	var position int32
+	indexes, nbPartitions, err := placeHolderIndex(testString)
 
-	if err != nil || transformType != Wildcard || len(indexes) != 1 || indexes[0] != 1 || nbPartitions != -1 {
+	if err != nil || len(indexes) != 1 || indexes[0] != 1 || nbPartitions != -1 {
 		t.Fatalf("Error parsing %s", testString)
 	}
 
 	testString = "{{partition(10,1,2,3)}}"
 
-	transformType, indexes, nbPartitions, _, err = indexPlaceHolders(testString)
+	indexes, nbPartitions, err = placeHolderIndex(testString)
 
-	if err != nil || transformType != Partition || !reflect.DeepEqual(indexes, []int{1, 2, 3}) || nbPartitions != 10 {
+	if err != nil || !reflect.DeepEqual(indexes, []int{1, 2, 3}) || nbPartitions != 10 {
 		t.Fatalf("Error parsing %s", testString)
 	}
 
-	testString = "{{ Partition (10,1,2,3) }}"
+	testString = "{{ partition(10,1,2,3) }}"
 
-	transformType, indexes, nbPartitions, _, err = indexPlaceHolders(testString)
+	indexes, nbPartitions, err = placeHolderIndex(testString)
 
-	if err != nil || transformType != Partition || !reflect.DeepEqual(indexes, []int{1, 2, 3}) || nbPartitions != 10 {
+	if err != nil || !reflect.DeepEqual(indexes, []int{1, 2, 3}) || nbPartitions != 10 {
 		t.Fatalf("Error parsing %s", testString)
 	}
 
-	testString = "{{wildcard(2)}}"
-	transformType, indexes, nbPartitions, _, err = indexPlaceHolders(testString)
+	testString = "{{partition (10,1,2,3)}}"
 
-	if err != nil || transformType != Wildcard || len(indexes) != 1 || indexes[0] != 2 || nbPartitions != -1 {
-		t.Fatalf("Error parsing %s", testString)
-	}
+	indexes, nbPartitions, err = placeHolderIndex(testString)
 
-	testString = "{{SplitFromLeft(2,1)}}"
-	transformType, indexes, position, _, err = indexPlaceHolders(testString)
-
-	if err != nil || transformType != SplitFromLeft || len(indexes) != 1 || indexes[0] != 2 || position != 1 {
+	if err != nil || !reflect.DeepEqual(indexes, []int{1, 2, 3}) || nbPartitions != 10 {
 		t.Fatalf("Error parsing %s", testString)
 	}
 
-	testString = "{{SplitFromRight(3,2)}}"
-	transformType, indexes, position, _, err = indexPlaceHolders(testString)
+	testString = "{{wildcard(2)}}"
+	indexes, nbPartitions, err = placeHolderIndex(testString)
 
-	if err != nil || transformType != SplitFromRight || len(indexes) != 1 || indexes[0] != 3 || position != 2 {
+	if err != nil || len(indexes) != 1 || indexes[0] != 2 || nbPartitions != -1 {
 		t.Fatalf("Error parsing %s", testString)
 	}
 
-	testString = "{{SliceFromLeft(2,2)}}"
-	transformType, indexes, sliceSize, _, err := indexPlaceHolders(testString)
+	testString = "{{ wildcard (2) }}"
+	indexes, nbPartitions, err = placeHolderIndex(testString)
 
-	if err != nil || transformType != SliceFromLeft || len(indexes) != 1 || indexes[0] != 2 || sliceSize != 2 {
+	if err != nil || len(indexes) != 1 || indexes[0] != 2 || nbPartitions != -1 {
 		t.Fatalf("Error parsing %s", testString)
 	}
 }
@@ -3297,7 +3290,6 @@ func TestSubjectTransforms(t *testing.T) {
 	shouldErr("foo.*", "foo.{{wildcard()}}")       // Not enough arguments passed to the mapping function
 	shouldErr("foo.*", "foo.{{wildcard(1,2)}}")    // Too many arguments passed to the mapping function
 	shouldErr("foo.*", "foo.{{ wildcard5) }}")     // Bad mapping function
-	shouldErr("foo.*", "foo.{{splitLeft(2,2}}")    // arg out of range
 
 	shouldBeOK := func(src, dest string) *transform {
 		t.Helper()
@@ -3311,7 +3303,6 @@ func TestSubjectTransforms(t *testing.T) {
 	shouldBeOK("foo", "bar")
 	shouldBeOK("foo.*.bar.*.baz", "req.$2.$1")
 	shouldBeOK("baz.>", "mybaz.>")
-	shouldBeOK("*", "{{splitfromleft(1,1)}}")
 
 	shouldMatch := func(src, dest, sample, expected string) {
 		t.Helper()
@@ -3330,12 +3321,6 @@ func TestSubjectTransforms(t *testing.T) {
 	shouldMatch("baz.>", "my.pre.>", "baz.1.2.3", "my.pre.1.2.3")
 	shouldMatch("baz.>", "foo.bar.>", "baz.1.2.3", "foo.bar.1.2.3")
 	shouldMatch("*", "foo.bar.$1", "foo", "foo.bar.foo")
-	shouldMatch("*", "{{splitfromleft(1,3)}}", "12345", "123.45")
-	shouldMatch("*", "{{SplitFromRight(1,3)}}", "12345", "12.345")
-	shouldMatch("*", "{{SliceFromLeft(1,3)}}", "1234567890", "123.456.789.0")
-	shouldMatch("*", "{{SliceFromRight(1,3)}}", "1234567890", "1.234.567.890")
-	shouldMatch("*", "{{split(1,-)}}", "-abc-def--ghi-", "abc.def.ghi")
-	shouldMatch("*.*", "{{split(2,-)}}.{{splitfromleft(1,2)}}", "foo.-abc-def--ghij-", "abc.def.ghij.fo.o") // combo + checks split for multiple instance of deliminator and deliminator being at the start or end
 }
 
 func TestAccountSystemPermsWithGlobalAccess(t *testing.T) {
diff --git a/server/sublist_test.go b/server/sublist_test.go
index f1fb1fde..05a14dd2 100644
--- a/server/sublist_test.go
+++ b/server/sublist_test.go
@@ -669,8 +669,6 @@ func TestValidateDestinationSubject(t *testing.T) {
 	checkError(ValidateMappingDestination("foo.{{ wildcard(1) }}"), nil, t)
 	checkError(ValidateMappingDestination("foo.{{wildcard( 1 )}}"), nil, t)
 	checkError(ValidateMappingDestination("foo.{{partition(2,1)}}"), nil, t)
-	checkError(ValidateMappingDestination("foo.{{SplitFromLeft(2,1)}}"), nil, t)
-	checkError(ValidateMappingDestination("foo.{{SplitFromRight(2,1)}}"), nil, t)
 	checkError(ValidateMappingDestination("foo.{{unknown(1)}}"), ErrInvalidMappingDestination, t)
 	checkError(ValidateMappingDestination("foo..}"), ErrInvalidMappingDestination, t)
 	checkError(ValidateMappingDestination("foo. bar}"), ErrInvalidMappingDestinationSubject, t)