SLING-10816 fixing left token of parsed expr
diff --git a/src/main/java/org/apache/sling/pipes/PipeBindings.java b/src/main/java/org/apache/sling/pipes/PipeBindings.java
index ebcaa78..3f120c2 100644
--- a/src/main/java/org/apache/sling/pipes/PipeBindings.java
+++ b/src/main/java/org/apache/sling/pipes/PipeBindings.java
@@ -69,7 +69,7 @@
      */
     public static final String NAME_BINDING = "name";
 
-    public static final String INJECTED_SCRIPT_REGEXP = "\\$\\{(([^\\{^\\}]+(\\{[0-9,]+\\})?)*)\\}";
+    public static final String INJECTED_SCRIPT_REGEXP = "\\$\\{(([^\\{^\\}]+(\\{[0-9,]+\\})?)+)\\}";
     private static final Pattern INJECTED_SCRIPT = Pattern.compile(INJECTED_SCRIPT_REGEXP);
     protected static final String IF_PREFIX = "$if";
     protected static final Pattern CONDITIONAL_STRING =  Pattern.compile("^\\" + IF_PREFIX + INJECTED_SCRIPT_REGEXP);
diff --git a/src/main/java/org/apache/sling/pipes/internal/CommandUtil.java b/src/main/java/org/apache/sling/pipes/internal/CommandUtil.java
index 8de164c..527e5d7 100644
--- a/src/main/java/org/apache/sling/pipes/internal/CommandUtil.java
+++ b/src/main/java/org/apache/sling/pipes/internal/CommandUtil.java
@@ -24,7 +24,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.function.Function;
+import java.util.function.UnaryOperator;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
@@ -37,19 +37,20 @@
 public class CommandUtil {
     static final String PAIR_SEP = ",";
     static final String KEY_VALUE_SEP = "=";
-    static final String FIRST_TOKEN = "first";
-    static final String SECOND_TOKEN = "second";
+    static final String FIRST_KEY = "first";
+    static final String SECOND_KEY = "second";
     static final String PN_JCR_MIXIN = "jcr:mixinTypes";
     static final Pattern MIXINS_ARRAY_PATTERN = Pattern.compile("^\\s*\\[(.*)\\]\\s*$");
     private static final Pattern UNEMBEDDEDSCRIPT_PATTERN = Pattern.compile("^(\\d+(\\.\\d+)?)|" + //21.42
-            "(\\[.*]$)|" + //['one','two']
-            "(\\w[\\w_\\-\\d]+\\..+)|" + //map.field...
-            "(\\w[\\w_\\-\\d]+\\['.+'])|" + //map['field']
-            "(true$|false$)|" + //boolean
-            "(new .*)|" + //instantiation
+            "\\[.*]$|" + //['one','two']
+            "[\\w_\\-]+\\..+|" + //map.field...
+            "[\\w_\\-]+\\['.+']|" + //map['field']
+            "true$|false$|" + //boolean
+            "new .*|" + //instantiation
             "(.*'$)"); // 'string'
-    static final String CONFIGURATION_TOKEN = "(?<" + FIRST_TOKEN + ">[\\w/\\:]+)\\s*" + KEY_VALUE_SEP
-            + "(?<" + SECOND_TOKEN + ">[(\\w*)|" + INJECTED_SCRIPT_REGEXP + "]+)";
+    static final String EXPR_TOKEN = "([^=]+|" + INJECTED_SCRIPT_REGEXP + ")+";
+    static final String CONFIGURATION_TOKEN = "\\s*(?<" + FIRST_KEY + ">" + EXPR_TOKEN + ")\\s*" + KEY_VALUE_SEP
+            + "\\s*(?<" + SECOND_KEY + ">(" + EXPR_TOKEN + ")+)\\s*";
     public static final Pattern CONFIGURATION_PATTERN = Pattern.compile(CONFIGURATION_TOKEN);
 
     private CommandUtil() {
@@ -110,12 +111,12 @@
      * @param valueTransformer before adding it to the map, that function will be applied to found value
      * @return map of key and (transformed) value
      */
-    public static Map stringToMap(@NotNull String input, Function<String, String> valueTransformer) {
+    public static Map<String, Object> stringToMap(@NotNull String input, UnaryOperator<String> valueTransformer) {
         Map<String, Object> map = new HashMap<>();
         for (String pair : input.split(PAIR_SEP) ){
             Matcher matcher = CONFIGURATION_PATTERN.matcher(pair);
             if (matcher.find()) {
-                map.put(matcher.group(FIRST_TOKEN), valueTransformer.apply(matcher.group(SECOND_TOKEN)));
+                map.put(matcher.group(FIRST_KEY), valueTransformer.apply(matcher.group(SECOND_KEY)));
             }
         }
         return map;
@@ -131,8 +132,8 @@
             for (String pair : o) {
                 Matcher matcher = CONFIGURATION_PATTERN.matcher(pair.trim());
                 if (matcher.matches()) {
-                    args.add(matcher.group(FIRST_TOKEN));
-                    args.add(matcher.group(SECOND_TOKEN));
+                    args.add(matcher.group(FIRST_KEY));
+                    args.add(matcher.group(SECOND_KEY));
                 }
             }
         }
diff --git a/src/main/java/org/apache/sling/pipes/package-info.java b/src/main/java/org/apache/sling/pipes/package-info.java
index e892a88..711bf13 100644
--- a/src/main/java/org/apache/sling/pipes/package-info.java
+++ b/src/main/java/org/apache/sling/pipes/package-info.java
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@Version("4.1.0")
+@Version("4.2.0")
 package org.apache.sling.pipes;
 
 import org.osgi.annotation.versioning.Version;
diff --git a/src/test/java/org/apache/sling/pipes/BasePipeTest.java b/src/test/java/org/apache/sling/pipes/BasePipeTest.java
index 833813a..a7adf13 100644
--- a/src/test/java/org/apache/sling/pipes/BasePipeTest.java
+++ b/src/test/java/org/apache/sling/pipes/BasePipeTest.java
@@ -30,7 +30,6 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
 public class BasePipeTest extends AbstractPipeTest {
diff --git a/src/test/java/org/apache/sling/pipes/internal/CommandExecutorImplTest.java b/src/test/java/org/apache/sling/pipes/internal/CommandExecutorImplTest.java
index 5b06d97..31021f1 100644
--- a/src/test/java/org/apache/sling/pipes/internal/CommandExecutorImplTest.java
+++ b/src/test/java/org/apache/sling/pipes/internal/CommandExecutorImplTest.java
@@ -104,11 +104,13 @@
 
     @Test
     public void testKeyValueToArray() {
-        assertArrayEquals(new String[]{"one","two","three","four"}, keyValuesToArray(Arrays.asList("one=two","three=four")));
-        assertArrayEquals(new String[]{"one","two","three","${four}"}, keyValuesToArray(Arrays.asList("one=two","three=${four}")));
-        assertArrayEquals(new String[]{"one","two","three","${four == 'blah' ? 'five' : 'six'}"},
+        assertArrayEquals("1", new String[]{"one","two","three","four"}, keyValuesToArray(Arrays.asList("one=two","three=four")));
+        assertArrayEquals("2", new String[]{"one","two","three","${four}"}, keyValuesToArray(Arrays.asList("one=two","three=${four}")));
+        assertArrayEquals("3", new String[]{"${one == 'check'? 'three':'four'}","two"}, keyValuesToArray((Arrays.asList("${one == 'check'? 'three':'four'}=two"))));
+        assertArrayEquals("4", new String[]{"a_b-c","two"}, keyValuesToArray((Arrays.asList("a_b-c=two"))));
+        assertArrayEquals("5", new String[]{"one","two","three","${four == 'blah' ? 'five' : 'six'}"},
             keyValuesToArray(Arrays.asList("one=two","three=${four == 'blah' ? 'five' : 'six'}")));
-        assertArrayEquals(new String[]{"jcr:content/singer","${'ringo' == one ? false : true}"}, keyValuesToArray(Arrays.asList("jcr:content/singer=${'ringo' == one ? false : true}")));
+        assertArrayEquals("6", new String[]{"jcr:content/singer","${'ringo' == one ? false : true}"}, keyValuesToArray(Arrays.asList("jcr:content/singer=${'ringo' == one ? false : true}")));
     }
 
     @Test
diff --git a/src/test/java/org/apache/sling/pipes/internal/CommandUtilTest.java b/src/test/java/org/apache/sling/pipes/internal/CommandUtilTest.java
index 08dba0b..eaaf336 100644
--- a/src/test/java/org/apache/sling/pipes/internal/CommandUtilTest.java
+++ b/src/test/java/org/apache/sling/pipes/internal/CommandUtilTest.java
@@ -16,16 +16,41 @@
  */
 package org.apache.sling.pipes.internal;
 
+import static org.apache.sling.pipes.internal.CommandUtil.CONFIGURATION_PATTERN;
+import static org.apache.sling.pipes.internal.CommandUtil.FIRST_KEY;
+import static org.apache.sling.pipes.internal.CommandUtil.SECOND_KEY;
+
 import junit.framework.TestCase;
 
 import java.util.HashMap;
 import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 import org.junit.Assert;
 import org.junit.Test;
 
 public class CommandUtilTest extends TestCase {
 
+
+    private void assertMatch(Pattern pattern, String token, String first, String second) {
+        Matcher matcher = pattern.matcher(token);
+        assertTrue(pattern.toString() + " should match with " + token, matcher.matches());
+        assertEquals("first token should be " + first, first, matcher.group(FIRST_KEY));
+        assertEquals("second token should be " + second, second, matcher.group(SECOND_KEY));
+    }
+    @Test
+    public void testTokenMatch() {
+        assertMatch(CONFIGURATION_PATTERN, "foo=bar", "foo", "bar");
+        assertMatch(CONFIGURATION_PATTERN, "${foo}=bar", "${foo}", "bar");
+        assertMatch(CONFIGURATION_PATTERN, "foo=${bar}", "foo", "${bar}");
+        assertMatch(CONFIGURATION_PATTERN, "foo='bar'", "foo", "'bar'");
+        assertMatch(CONFIGURATION_PATTERN, "foo=${'bar'}", "foo", "${'bar'}");
+        assertMatch(CONFIGURATION_PATTERN, "${foo == bar ? 1 : 2}=bar", "${foo == bar ? 1 : 2}", "bar");
+        assertMatch(CONFIGURATION_PATTERN, "foo=${foo == bar ? 1 : 2}", "foo", "${foo == bar ? 1 : 2}");
+        assertMatch(CONFIGURATION_PATTERN, "foo/bar=check/some", "foo/bar", "check/some");
+        assertMatch(CONFIGURATION_PATTERN, "foo:bar='.+'", "foo:bar", "'.+'");
+    }
     @Test
     public void testEmbedIfNeeded() {
         assertEquals(2, CommandUtil.embedIfNeeded(2));
diff --git a/src/test/java/org/apache/sling/pipes/internal/FilterPipeTest.java b/src/test/java/org/apache/sling/pipes/internal/FilterPipeTest.java
index e8a86da..2151241 100644
--- a/src/test/java/org/apache/sling/pipes/internal/FilterPipeTest.java
+++ b/src/test/java/org/apache/sling/pipes/internal/FilterPipeTest.java
@@ -113,7 +113,7 @@
 
     @Test
     public void testBadTestFails() throws InvocationTargetException, IllegalAccessException {
-        ExecutionResult result = execute("echo /content/fruits | grep slingPipesFilter_test=${'some string'}");
+        ExecutionResult result = execute("echo /content/fruits | grep slingPipesFilter_test=${'some string'}");
         assertEquals(0, result.size());
     }
 
diff --git a/src/test/java/org/apache/sling/pipes/internal/JCRWritePipeTest.java b/src/test/java/org/apache/sling/pipes/internal/JCRWritePipeTest.java
index 028e545..545efb5 100644
--- a/src/test/java/org/apache/sling/pipes/internal/JCRWritePipeTest.java
+++ b/src/test/java/org/apache/sling/pipes/internal/JCRWritePipeTest.java
@@ -35,7 +35,6 @@
 import org.apache.sling.testing.mock.sling.junit.SlingContext;
 import org.apache.sling.testing.mock.sling.junit.SlingContextBuilder;
 import org.codehaus.plexus.util.CollectionUtils;
-import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
diff --git a/src/test/java/org/apache/sling/pipes/internal/PlumberServletTest.java b/src/test/java/org/apache/sling/pipes/internal/PlumberServletTest.java
index 9fdb8a6..b5d5b9a 100644
--- a/src/test/java/org/apache/sling/pipes/internal/PlumberServletTest.java
+++ b/src/test/java/org/apache/sling/pipes/internal/PlumberServletTest.java
@@ -152,14 +152,10 @@
 
     @Test
     public void testAdditionalBindingsAndWriter() throws Exception {
-        String testBinding = "testBinding";
-        String testBindingLength = testBinding + "Length";
-        String bindingValue = "testBindingValue";
-        String pathLengthParam = "pathLength";
-        String bindings = "{\"" + testBinding + "\":\"" + bindingValue + "\"}";
-        String respObject =  pathLengthParam + "=path.get(\"dummyGrandChild\").length()," + testBindingLength + "=" + testBinding + ".length()";
+        String bindings = "{\"testBinding\":\"testBindingValue\"}";
+        String respObject =  "pathLength=path.get(\"dummyGrandChild\").length(),testBindingValue=testBinding.length()";
         SlingHttpServletRequest request =
-                mockPlumberServletRequest(context.resourceResolver(), "json", dummyTreePath, null, bindings.toString(), respObject.toString(), null, null);
+                mockPlumberServletRequest(context.resourceResolver(), "json", dummyTreePath, null, bindings, respObject, null, null);
         servlet.execute(request, response, false);
         assertDummyTree();
         JsonObject response = Json.createReader(new StringReader(stringResponse.toString())).readObject();
@@ -169,13 +165,13 @@
             assertNotNull("there should be an object returned at each time", object);
             String path = object.getString(OutputWriter.PATH_KEY);
             assertNotNull("the string path should be returned for each item, containing the path of the resource");
-            String pathLength = object.getString(pathLengthParam);
+            String pathLength = object.getString("pathLength");
             assertNotNull("there should be a pathLength param, as specified in the writer", pathLength);
             assertEquals("Pathlength should be the string representation of the path length", path.length() + "", pathLength);
-            String testBindingLengthValue = object.getString(testBindingLength);
+            String testBindingLengthValue = object.getString("testBindingValue", null);
             assertNotNull("testBindingLength should be there", testBindingLengthValue);
             assertEquals("testBindingLength should be the string representation of the additional binding length",
-                    bindingValue.length() + "", testBindingLengthValue);
+                    "testBindingValue".length() + "", testBindingLengthValue);
         }
     }
 
diff --git a/src/test/resources/simplelogger.properties b/src/test/resources/simplelogger.properties
index 0217e08..16018c4 100644
--- a/src/test/resources/simplelogger.properties
+++ b/src/test/resources/simplelogger.properties
@@ -15,7 +15,7 @@
 # limitations under the License.
 
 org.slf4j.simpleLogger.logFile=System.out
-org.slf4j.simpleLogger.defaultLogLevel=debug
+org.slf4j.simpleLogger.defaultLogLevel=off
 org.slf4j.simpleLogger.log.org.apache.jackrabbit.oak.plugins.index.IndexUpdate=warn
 org.slf4j.simpleLogger.log.org.apache.sling.scripting.core.impl.ScriptEngineManagerFactory=warn
 org.slf4j.simpleLogger.log.org.apache.sling.resourceresolver.impl.mapping.MapEntries=warn