Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Transform waiter path field names using new JmesPath ExpressionSerializer #77

Merged
merged 3 commits into from
Feb 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions codegen/projections/weather/lib/weather/waiters.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def initialize(client, options = {})
state: 'retry',
matcher: {
inputOutput: {
path: "length(input.city_id) == length(output.name)",
path: "length(\"input\".\"city_id\") == length(\"output\".\"member_name\")",
comparator: "booleanEquals",
expected: 'true'
}
Expand All @@ -65,7 +65,7 @@ def initialize(client, options = {})
state: 'success',
matcher: {
output: {
path: "name",
path: "\"member_name\"",
comparator: "stringEquals",
expected: 'seattle'
}
Expand Down Expand Up @@ -120,7 +120,7 @@ def initialize(client, options = {})
state: 'failure',
matcher: {
output: {
path: "items[].name",
path: "\"items\"[].\"member_name\"",
comparator: "allStringEquals",
expected: 'seattle'
}
Expand All @@ -130,7 +130,7 @@ def initialize(client, options = {})
state: 'success',
matcher: {
output: {
path: "items[].name",
path: "\"items\"[].\"member_name\"",
comparator: "anyStringEquals",
expected: 'NewYork'
}
Expand Down
4 changes: 2 additions & 2 deletions codegen/projections/white_label/lib/white_label/waiters.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def initialize(client, options = {})
state: 'failure',
matcher: {
output: {
path: "status",
path: "\"status\"",
comparator: "stringEquals",
expected: 'failed'
}
Expand All @@ -64,7 +64,7 @@ def initialize(client, options = {})
state: 'failure',
matcher: {
inputOutput: {
path: "input.status == 'failed' || output.status == 'failed'",
path: "(\"input\".\"status\" == `\"failed\"` || \"output\".\"status\" == `\"failed\"`)",
comparator: "booleanEquals",
expected: 'true'
}
Expand Down
4 changes: 2 additions & 2 deletions codegen/projections/white_label/spec/waiters_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,15 @@ module Waiters
state: 'failure',
matcher: {
output: {
path: 'status', comparator: "stringEquals", expected: "failed"
path: '"status"', comparator: "stringEquals", expected: "failed"
}
}
},
{
state: 'failure',
matcher: {
inputOutput: {
path: 'input.status == \'failed\' || output.status == \'failed\'',
path: '("input"."status" == `"failed"` || "output"."status" == `"failed"`)',
comparator: "booleanEquals",
expected: "true"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,15 @@ module Waiters
state: 'failure',
matcher: {
output: {
path: 'status', comparator: "stringEquals", expected: "failed"
path: '"status"', comparator: "stringEquals", expected: "failed"
}
}
},
{
state: 'failure',
matcher: {
inputOutput: {
path: 'input.status == \'failed\' || output.status == \'failed\'',
path: '("input"."status" == `"failed"` || "output"."status" == `"failed"`)',
comparator: "booleanEquals",
expected: "true"
}
Expand Down
2 changes: 1 addition & 1 deletion codegen/smithy-ruby-codegen/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ extra["displayName"] = "Smithy :: Ruby :: Codegen"
extra["moduleName"] = "software.amazon.smithy.ruby.codegen"

dependencies {
api("software.amazon.smithy:smithy-codegen-core:[1.16.0,2.0.0[")
api("software.amazon.smithy:smithy-codegen-core:[1.17.0,2.0.0[")
implementation("software.amazon.smithy:smithy-waiters:[1.4.0,2.0.0[")
implementation("software.amazon.smithy:smithy-protocol-test-traits:[1.9.0,2.0.0[")
}
Original file line number Diff line number Diff line change
Expand Up @@ -133,12 +133,22 @@ public String toMemberName(MemberShape shape) {
return memberName;
}
} else {
// Note: we do not neeed to escape words that are only reserved for error members
// Note: we do not need to escape words that are only reserved for error members
// error classes have parsed data accessible through a `data` member only so there are no conflicts.
return getDefaultMemberName(shape);
}
}

/**
* Convert a String shape name into a snake_cased member. Also checks reserved wording.
* @param shapeName The shape's name as a string
* @return A snake cased string for the member.
*/
public String toMemberName(String shapeName) {
return prefixLeadingInvalidIdentCharacters(
escaper.escapeMemberName(RubyFormatter.toSnakeCase(shapeName)), "member_");
}

// Member names (Except for union members) are snake_case.
// The member names MAY start with underscores but MUST NOT start with a number.
// If they are a reserved word or start with a number they will be prefixed with “member_”.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,34 @@

package software.amazon.smithy.ruby.codegen.generators;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import software.amazon.smithy.build.FileManifest;
import software.amazon.smithy.jmespath.ExpressionSerializer;
import software.amazon.smithy.jmespath.ExpressionVisitor;
import software.amazon.smithy.jmespath.JmespathExpression;
import software.amazon.smithy.jmespath.ast.AndExpression;
import software.amazon.smithy.jmespath.ast.ComparatorExpression;
import software.amazon.smithy.jmespath.ast.CurrentExpression;
import software.amazon.smithy.jmespath.ast.ExpressionTypeExpression;
import software.amazon.smithy.jmespath.ast.FieldExpression;
import software.amazon.smithy.jmespath.ast.FilterProjectionExpression;
import software.amazon.smithy.jmespath.ast.FlattenExpression;
import software.amazon.smithy.jmespath.ast.FunctionExpression;
import software.amazon.smithy.jmespath.ast.IndexExpression;
import software.amazon.smithy.jmespath.ast.LiteralExpression;
import software.amazon.smithy.jmespath.ast.MultiSelectHashExpression;
import software.amazon.smithy.jmespath.ast.MultiSelectListExpression;
import software.amazon.smithy.jmespath.ast.NotExpression;
import software.amazon.smithy.jmespath.ast.ObjectProjectionExpression;
import software.amazon.smithy.jmespath.ast.OrExpression;
import software.amazon.smithy.jmespath.ast.ProjectionExpression;
import software.amazon.smithy.jmespath.ast.SliceExpression;
import software.amazon.smithy.jmespath.ast.Subexpression;
import software.amazon.smithy.model.Model;
import software.amazon.smithy.model.knowledge.TopDownIndex;
import software.amazon.smithy.model.shapes.OperationShape;
Expand Down Expand Up @@ -212,10 +233,9 @@ private void renderAcceptors(Waiter waiter) {
}

private String translatePath(String path) {
//TODO: This needs to use a JMESPathExpression to parse the path and actually correctly translate names
// This will not work correctly in all cases
return Arrays.stream(path.split("[.]"))
.map((m) -> RubyFormatter.toSnakeCase(m)).collect(Collectors.joining("."));
JmespathExpression transformedExpression = JmespathExpression.parse(path).accept(new JmespathTranslator());
String transformedPath = (new ExpressionSerializer()).serialize(transformedExpression);
return transformedPath;
}

private void renderWaiterWaitDocumentation(OperationShape operation, String operationName) {
Expand Down Expand Up @@ -257,7 +277,7 @@ private class AcceptorVisitor implements Matcher.Visitor<Void> {
private void renderPathMatcher(String memberName, String path, String comparator, String expected) {
writer
.openBlock("$L: {", memberName)
.write("path: \"$L\",", translatePath(path))
.write("path: $S,", translatePath(path))
.write("comparator: \"$L\",", comparator)
.write("expected: '$L'", expected)
.closeBlock("}");
Expand Down Expand Up @@ -300,4 +320,183 @@ public Void visitUnknown(Matcher.UnknownMember unknown) {
return null;
}
}

private class JmespathTranslator implements ExpressionVisitor<JmespathExpression> {

@Override
public JmespathExpression visitComparator(ComparatorExpression expression) {
return new ComparatorExpression(
expression.getComparator(),
expression.getLeft().accept(this),
expression.getRight().accept(this),
expression.getLine(),
expression.getColumn()
);
}

@Override
public JmespathExpression visitCurrentNode(CurrentExpression expression) {
return new CurrentExpression(expression.getLine(), expression.getColumn());
}

@Override
public JmespathExpression visitExpressionType(ExpressionTypeExpression expression) {
return new ExpressionTypeExpression(
expression.getExpression().accept(this),
expression.getLine(),
expression.getColumn());
}

@Override
public JmespathExpression visitFlatten(FlattenExpression expression) {
return new FlattenExpression(
expression.getExpression().accept(this),
expression.getLine(),
expression.getColumn()
);
}

@Override
public JmespathExpression visitFunction(FunctionExpression expression) {

return new FunctionExpression(
expression.getName(),
expression.getArguments().stream()
.map((e) -> e.accept(this)).collect(Collectors.toList()),
expression.getLine(),
expression.getColumn()
);
}

@Override
public JmespathExpression visitField(FieldExpression expression) {
return new FieldExpression(
symbolProvider.toMemberName(expression.getName()),
expression.getLine(), expression.getColumn());
}

@Override
public JmespathExpression visitIndex(IndexExpression expression) {
return new IndexExpression(
expression.getIndex(),
expression.getLine(),
expression.getColumn()
);
}

@Override
public JmespathExpression visitLiteral(LiteralExpression expression) {
return new LiteralExpression(
expression.getValue(),
expression.getLine(),
expression.getColumn()
);
}

@Override
public JmespathExpression visitMultiSelectList(MultiSelectListExpression expression) {
return new MultiSelectListExpression(
expression.getExpressions().stream()
.map((e) -> e.accept(this)).collect(Collectors.toList()),
expression.getLine(),
expression.getColumn()
);
}

@Override
public JmespathExpression visitMultiSelectHash(MultiSelectHashExpression expression) {
Map<String, JmespathExpression> newExpression = new HashMap<>();
for (Map.Entry<String, JmespathExpression> entry : expression.getExpressions().entrySet()) {
newExpression.put(entry.getKey(), entry.getValue().accept(this));
}

return new MultiSelectHashExpression(
newExpression,
expression.getLine(),
expression.getColumn()
);
}

@Override
public JmespathExpression visitAnd(AndExpression expression) {
return new AndExpression(
expression.getLeft().accept(this),
expression.getRight().accept(this),
expression.getLine(),
expression.getColumn()
);
}

@Override
public JmespathExpression visitOr(OrExpression expression) {
return new OrExpression(
expression.getLeft().accept(this),
expression.getRight().accept(this),
expression.getLine(),
expression.getColumn()
);
}

@Override
public JmespathExpression visitNot(NotExpression expression) {
return new NotExpression(
expression.getExpression().accept(this),
expression.getLine(),
expression.getColumn()
);
}

@Override
public JmespathExpression visitProjection(ProjectionExpression expression) {
return new ProjectionExpression(
expression.getLeft().accept(this),
expression.getRight().accept(this),
expression.getLine(),
expression.getColumn()
);
}

@Override
public JmespathExpression visitFilterProjection(FilterProjectionExpression expression) {
return new FilterProjectionExpression(
expression.getLeft().accept(this),
expression.getComparison().accept(this),
expression.getRight().accept(this),
expression.getLine(),
expression.getColumn()
);
}

@Override
public JmespathExpression visitObjectProjection(ObjectProjectionExpression expression) {
return new ObjectProjectionExpression(
expression.getLeft().accept(this),
expression.getRight().accept(this),
expression.getLine(),
expression.getColumn()
);
}

@Override
public JmespathExpression visitSlice(SliceExpression expression) {
return new SliceExpression(
expression.getStart().isPresent() ? expression.getStart().getAsInt() : null,
expression.getStop().isPresent() ? expression.getStop().getAsInt() : null,
expression.getStep(),
expression.getLine(),
expression.getColumn()
);
}

@Override
public JmespathExpression visitSubexpression(Subexpression expression) {
return new Subexpression(
expression.getLeft().accept(this),
expression.getRight().accept(this),
expression.getLine(),
expression.getColumn(),
expression.isPipe()
);
}
}
}