class Script {

    public static AssertionResult matchNamed(MatchType matchType, String expression, String path, String expected, ScenarioContext context) {
        String name = StringUtils.trimToEmpty(expression);
        if (isDollarPrefixedJsonPath(name) || isXmlPath(name)) { // short-cut for operating on response
            path = name;
            name = ScriptValueMap.VAR_RESPONSE;
        }
        if (name.startsWith("$")) { // in case someone used the dollar prefix by mistake on the LHS
            name = name.substring(1);
        }
        path = StringUtils.trimToNull(path);
        if (path == null) {
            StringUtils.Pair pair = parseVariableAndPath(name);
            name = pair.left;
            path = pair.right;
        }
        if (VAR_HEADER.equals(name)) { // convenience shortcut for asserting against response header
            return matchNamed(matchType, ScriptValueMap.VAR_RESPONSE_HEADERS, "$['" + path + "'][0]", expected, context);
        }
        ScriptValue actual;
        // karate started out by "defaulting" to JsonPath on the LHS of a match so we have this kludge
        // but we now handle JS expressions of almost any shape on the LHS, if in doubt, wrap in parentheses
        // actually it is not too bad - the XPath function check is the only odd one out
        // rules:
        // if not XPath function, wrapped in parentheses, involves function call
        //      [then] JS eval
        // else if XPath, JsonPath, JsonPath wildcard ".." or "*" or "[?"
        //      [then] eval name, and do a JsonPath or XPath using the parsed path
        if (isXmlPathFunction(path) 
                || (!name.startsWith("(") && !path.endsWith(")") && !path.contains(")."))
                && (isDollarPrefixed(path) || isJsonPath(path) || isXmlPath(path))) {
            actual = evalKarateExpression(name, context);
            // edge case: java property getter, e.g. "driver.cookies"
            if (!actual.isJsonLike() && !isXmlPath(path) && !isXmlPathFunction(path)) {
                // super rare edge case "match $.foo == '#notnull'" for response (which is not json, and will fail match)
                if (expression.startsWith("$")) {
                    expression = name + expression.substring(1);
                }
                actual = evalKarateExpression(expression, context); // fall back to JS eval
                path = VAR_ROOT;
            }
        } else {
            actual = evalKarateExpression(expression, context);
            path = VAR_ROOT; // we have eval-ed the entire LHS, so match RHS to "$"
        }
        return matchScriptValue(matchType, actual, path, expected, context);
    }

    private  Script();

}