diff --git a/CHANGELOG.md b/CHANGELOG.md index d8963d6f5..0d152f692 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +### Added +[Java] Make CucumberExpressionParser.parse public ([#340](https://github.com/cucumber/cucumber-expressions/pull/340)) ## [18.0.1] - 2024-10-28 ### Fixed diff --git a/java/src/main/java/io/cucumber/cucumberexpressions/Ast.java b/java/src/main/java/io/cucumber/cucumberexpressions/Ast.java index 50c0fef67..ab2568244 100644 --- a/java/src/main/java/io/cucumber/cucumberexpressions/Ast.java +++ b/java/src/main/java/io/cucumber/cucumberexpressions/Ast.java @@ -4,18 +4,17 @@ import java.util.Objects; import java.util.StringJoiner; -import static java.util.Arrays.asList; import static java.util.Objects.requireNonNull; import static java.util.stream.Collectors.joining; -final class Ast { +public final class Ast { - private static final char escapeCharacter = '\\'; - private static final char alternationCharacter = '/'; - private static final char beginParameterCharacter = '{'; - private static final char endParameterCharacter = '}'; - private static final char beginOptionalCharacter = '('; - private static final char endOptionalCharacter = ')'; + public static final char escapeCharacter = '\\'; + public static final char alternationCharacter = '/'; + public static final char beginParameterCharacter = '{'; + public static final char endParameterCharacter = '}'; + public static final char beginOptionalCharacter = '('; + public static final char endOptionalCharacter = ')'; interface Located { int start(); @@ -24,7 +23,7 @@ interface Located { } - static final class Node implements Located { + public static final class Node implements Located { private final Type type; private final List nodes; @@ -33,11 +32,11 @@ static final class Node implements Located { private final int end; Node(Type type, int start, int end, String token) { - this(type, start, end, null, token); + this(type, start, end, null, requireNonNull(token)); } Node(Type type, int start, int end, List nodes) { - this(type, start, end, nodes, null); + this(type, start, end, requireNonNull(nodes), null); } private Node(Type type, int start, int end, List nodes, String token) { @@ -48,7 +47,7 @@ private Node(Type type, int start, int end, List nodes, String token) { this.end = end; } - enum Type { + public enum Type { TEXT_NODE, OPTIONAL_NODE, ALTERNATION_NODE, @@ -65,14 +64,24 @@ public int end() { return end; } - List nodes() { + /** + * @return child nodes, {@code null} if a leaf-node + */ + public List nodes() { return nodes; } - Type type() { + public Type type() { return type; } + /** + * @return the text contained with in this node, {@code null} if not a leaf-node + */ + public String token() { + return token; + } + String text() { if (nodes == null) return token; @@ -106,13 +115,13 @@ private StringBuilder toString(int depth) { if (nodes != null) { sb.append(", \"nodes\": "); if (!nodes.isEmpty()) { - StringBuilder padding = new StringBuilder(); - for (int i = 0; i < depth; i++) { - padding.append(" "); - } - sb.append(nodes.stream() - .map(node -> node.toString(depth + 1)) - .collect(joining(",\n", "[\n", "\n" +padding + "]"))); + StringBuilder padding = new StringBuilder(); + for (int i = 0; i < depth; i++) { + padding.append(" "); + } + sb.append(nodes.stream() + .map(node -> node.toString(depth + 1)) + .collect(joining(",\n", "[\n", "\n" + padding + "]"))); } else { sb.append("[]"); @@ -224,10 +233,10 @@ public int hashCode() { @Override public String toString() { - return new StringJoiner(", ", "" + "{", "}") + return new StringJoiner(", ", "{", "}") .add("\"type\": \"" + type + "\"") - .add("\"start\": " + start + "") - .add("\"end\": " + end + "") + .add("\"start\": " + start) + .add("\"end\": " + end) .add("\"text\": \"" + text + "\"") .toString(); } diff --git a/java/src/main/java/io/cucumber/cucumberexpressions/CucumberExpressionParser.java b/java/src/main/java/io/cucumber/cucumberexpressions/CucumberExpressionParser.java index b77be40e9..1df7ab037 100644 --- a/java/src/main/java/io/cucumber/cucumberexpressions/CucumberExpressionParser.java +++ b/java/src/main/java/io/cucumber/cucumberexpressions/CucumberExpressionParser.java @@ -28,7 +28,10 @@ import static java.util.Arrays.asList; import static java.util.Collections.singletonList; -final class CucumberExpressionParser { +/** + * A parser for Cucumber expressions + */ +public final class CucumberExpressionParser { /* * text := whitespace | ')' | '}' | . @@ -160,7 +163,13 @@ final class CucumberExpressionParser { ) ); - Node parse(String expression) { + /** + * Parses as Cucumber expression into an AST of {@link Node nodes}. + * @param expression the expression to parse + * @return an AST of nodes + * @throws CucumberExpressionException if the expression could not be parsed + */ + public Node parse(String expression) { CucumberExpressionTokenizer tokenizer = new CucumberExpressionTokenizer(); List tokens = tokenizer.tokenize(expression); Result result = cucumberExpressionParser.parse(expression, tokens, 0); diff --git a/java/src/main/java/io/cucumber/cucumberexpressions/GroupBuilder.java b/java/src/main/java/io/cucumber/cucumberexpressions/GroupBuilder.java index f5222f6f6..e0f6336b5 100644 --- a/java/src/main/java/io/cucumber/cucumberexpressions/GroupBuilder.java +++ b/java/src/main/java/io/cucumber/cucumberexpressions/GroupBuilder.java @@ -9,7 +9,7 @@ final class GroupBuilder { private final List groupBuilders = new ArrayList<>(); private boolean capturing = true; private String source; - private int startIndex; + private final int startIndex; private int endIndex; GroupBuilder(int startIndex) { diff --git a/java/src/main/java/io/cucumber/cucumberexpressions/RegularExpression.java b/java/src/main/java/io/cucumber/cucumberexpressions/RegularExpression.java index 53c53f3a4..10d5e3440 100644 --- a/java/src/main/java/io/cucumber/cucumberexpressions/RegularExpression.java +++ b/java/src/main/java/io/cucumber/cucumberexpressions/RegularExpression.java @@ -48,7 +48,7 @@ public List> match(String text, Type... typeHints) { // When there is a conflict between the type hint from the regular expression and the method // prefer the parameter type associated with the regular expression. This ensures we will - // use the internal/user registered parameter transformer rather then the default. + // use the internal/user registered parameter transformer rather than the default. // // Unless the parameter type indicates it is the stronger type hint. if (parameterType != null && hasTypeHint && !parameterType.useRegexpMatchAsStrongTypeHint()) { diff --git a/java/src/main/java/io/cucumber/cucumberexpressions/TreeRegexp.java b/java/src/main/java/io/cucumber/cucumberexpressions/TreeRegexp.java index 37e2f9830..4b647b5b1 100644 --- a/java/src/main/java/io/cucumber/cucumberexpressions/TreeRegexp.java +++ b/java/src/main/java/io/cucumber/cucumberexpressions/TreeRegexp.java @@ -91,7 +91,7 @@ Group match(CharSequence s) { return groupBuilder.build(matcher, IntStream.rangeClosed(0, matcher.groupCount()).iterator()); } - public GroupBuilder getGroupBuilder() { + GroupBuilder getGroupBuilder() { return groupBuilder; } diff --git a/java/src/test/java/io/cucumber/cucumberexpressions/CucumberExpressionTest.java b/java/src/test/java/io/cucumber/cucumberexpressions/CucumberExpressionTest.java index d9554df54..d9b8e218b 100644 --- a/java/src/test/java/io/cucumber/cucumberexpressions/CucumberExpressionTest.java +++ b/java/src/test/java/io/cucumber/cucumberexpressions/CucumberExpressionTest.java @@ -15,6 +15,7 @@ import java.lang.reflect.Type; import java.math.BigDecimal; import java.math.BigInteger; +import java.nio.file.DirectoryStream; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; @@ -38,7 +39,10 @@ class CucumberExpressionTest { private static List acceptance_tests_pass() throws IOException { List paths = new ArrayList<>(); - newDirectoryStream(Paths.get("..", "testdata", "cucumber-expression", "matching")).forEach(paths::add); + Path path = Paths.get("..", "testdata", "cucumber-expression", "matching"); + try (DirectoryStream directories = newDirectoryStream(path)){ + directories.forEach(paths::add); + } paths.sort(Comparator.naturalOrder()); return paths; }