From d2934969cbc1f86f0edd551ba68684ad833976ac Mon Sep 17 00:00:00 2001 From: Trivikram Kamat <16024985+trivikr@users.noreply.github.com> Date: Wed, 26 Feb 2025 19:30:06 +0000 Subject: [PATCH 1/5] Use Object for smithy structure names --- .../endpointsV2/endpoints-operation-context-params.smithy | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/smithy-typescript-codegen/src/test/resources/software/amazon/smithy/typescript/codegen/endpointsV2/endpoints-operation-context-params.smithy b/smithy-typescript-codegen/src/test/resources/software/amazon/smithy/typescript/codegen/endpointsV2/endpoints-operation-context-params.smithy index f947e482e34..ad0fa6f7c47 100644 --- a/smithy-typescript-codegen/src/test/resources/software/amazon/smithy/typescript/codegen/endpointsV2/endpoints-operation-context-params.smithy +++ b/smithy-typescript-codegen/src/test/resources/software/amazon/smithy/typescript/codegen/endpointsV2/endpoints-operation-context-params.smithy @@ -48,7 +48,7 @@ operation GetFoo { structure GetFooInput { fooKeys: FooObject, fooList: FooList, - fooListObj: FooListObj, + fooListObj: FooListObject, fooObj: FooObject, fooObjObj: FooObjectObject, fooString: String, @@ -66,11 +66,11 @@ list FooList { member: String } -list FooListObj { - member: FooListObjMember +list FooListObject { + member: FooListObjectMember } -structure FooListObjMember { +structure FooListObjectMember { key: String } From 2418fe3cd4b8c18b40ed5f642de2089b08658b2d Mon Sep 17 00:00:00 2001 From: Trivikram Kamat <16024985+trivikr@users.noreply.github.com> Date: Wed, 26 Feb 2025 22:07:41 +0000 Subject: [PATCH 2/5] Manually compute parts of string using dot index Support for MultiSelect list will require processing dots inside list --- .../codegen/endpointsV2/RuleSetParameterFinder.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/endpointsV2/RuleSetParameterFinder.java b/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/endpointsV2/RuleSetParameterFinder.java index ffb84fd27d5..acd23608c93 100644 --- a/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/endpointsV2/RuleSetParameterFinder.java +++ b/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/endpointsV2/RuleSetParameterFinder.java @@ -279,7 +279,11 @@ public Map getOperationContextParamValues(OperationShape operati String path = definition.getPath(); // Split JMESPath expression string on separator and add JavaScript equivalent. - for (String part : path.split("[" + separator + "]")) { + while (path.length() > 0) { + int dotIndex = path.indexOf("."); + String part = dotIndex == -1 ? path : path.substring(0, dotIndex); + path = dotIndex == -1 ? "" : path.substring(dotIndex + 1); + if (value.endsWith(")")) { // The value is an object, which needs to run on map. value += ".map((obj: any) => obj"; From 276705927a6f131236b83c66316c8ea20aefa0d5 Mon Sep 17 00:00:00 2001 From: Trivikram Kamat <16024985+trivikr@users.noreply.github.com> Date: Wed, 26 Feb 2025 22:09:40 +0000 Subject: [PATCH 3/5] Add test for MultiSelect List in OperationContextParams --- .../typescript/codegen/CommandGeneratorTest.java | 1 + .../endpoints-operation-context-params.smithy | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/smithy-typescript-codegen/src/test/java/software/amazon/smithy/typescript/codegen/CommandGeneratorTest.java b/smithy-typescript-codegen/src/test/java/software/amazon/smithy/typescript/codegen/CommandGeneratorTest.java index e9f8c24ab6b..f09607c1110 100644 --- a/smithy-typescript-codegen/src/test/java/software/amazon/smithy/typescript/codegen/CommandGeneratorTest.java +++ b/smithy-typescript-codegen/src/test/java/software/amazon/smithy/typescript/codegen/CommandGeneratorTest.java @@ -44,6 +44,7 @@ public void writesOperationContextParamValues() { "opContextParamWildcardExpressionList: { type: \"operationContextParams\", get: (input?: any) => input?.fooList }", "opContextParamWildcardExpressionListObj: { type: \"operationContextParams\", get: (input?: any) => input?.fooListObj?.map((obj: any) => obj?.key) }", "opContextParamWildcardExpressionHash: { type: \"operationContextParams\", get: (input?: any) => Object.values(input?.fooObjObj ?? {}).map((obj: any) => obj?.bar) }", + "opContextParamMultiSelectList: { type: \"operationContextParams\", get: (input?: any) => input?.fooListObjObj?.map((obj: any) => [obj?.baz?.bar,obj?.qux].filter((i) => i)) }", "opContextParamKeys: { type: \"operationContextParams\", get: (input?: any) => Object.keys(input?.fooKeys ?? {}) }", } ); diff --git a/smithy-typescript-codegen/src/test/resources/software/amazon/smithy/typescript/codegen/endpointsV2/endpoints-operation-context-params.smithy b/smithy-typescript-codegen/src/test/resources/software/amazon/smithy/typescript/codegen/endpointsV2/endpoints-operation-context-params.smithy index ad0fa6f7c47..29a5eb93a34 100644 --- a/smithy-typescript-codegen/src/test/resources/software/amazon/smithy/typescript/codegen/endpointsV2/endpoints-operation-context-params.smithy +++ b/smithy-typescript-codegen/src/test/resources/software/amazon/smithy/typescript/codegen/endpointsV2/endpoints-operation-context-params.smithy @@ -20,6 +20,9 @@ namespace smithy.example opContextParamWildcardExpressionHash: { type: "stringArray", }, + opContextParamMultiSelectList: { + type: "stringArray", + }, opContextParamKeys: { type: "stringArray", }, @@ -37,6 +40,7 @@ service Example { "opContextParamWildcardExpressionList": { path: "fooList[*]" } "opContextParamWildcardExpressionListObj": { path: "fooListObj[*].key" } "opContextParamWildcardExpressionHash": { path: "fooObjObj.*.bar" } + "opContextParamMultiSelectList": { path: "fooListObjObj[*].[baz.bar, qux]" } "opContextParamKeys": { path: "keys(fooKeys)" } ) operation GetFoo { @@ -49,6 +53,7 @@ structure GetFooInput { fooKeys: FooObject, fooList: FooList, fooListObj: FooListObject, + fooListObjObj: FooListObjectObject, fooObj: FooObject, fooObjObj: FooObjectObject, fooString: String, @@ -58,6 +63,15 @@ structure FooObject { bar: String } +list FooListObjectObject { + member: FooMultiSelectObjectObject +} + +structure FooMultiSelectObjectObject { + baz: FooObject + qux: String +} + structure FooObjectObject { baz: FooObject } From 79aec6e1a538f8e3e763c16d8047a1f691ac649f Mon Sep 17 00:00:00 2001 From: Trivikram Kamat <16024985+trivikr@users.noreply.github.com> Date: Wed, 26 Feb 2025 22:57:36 +0000 Subject: [PATCH 4/5] Support MultiSelect List in OperationContextParams --- .../endpointsV2/RuleSetParameterFinder.java | 106 ++++++++++++------ 1 file changed, 69 insertions(+), 37 deletions(-) diff --git a/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/endpointsV2/RuleSetParameterFinder.java b/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/endpointsV2/RuleSetParameterFinder.java index acd23608c93..ebed0c1873f 100644 --- a/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/endpointsV2/RuleSetParameterFinder.java +++ b/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/endpointsV2/RuleSetParameterFinder.java @@ -277,43 +277,7 @@ public Map getOperationContextParamValues(OperationShape operati String separator = "?."; String value = "input"; String path = definition.getPath(); - - // Split JMESPath expression string on separator and add JavaScript equivalent. - while (path.length() > 0) { - int dotIndex = path.indexOf("."); - String part = dotIndex == -1 ? path : path.substring(0, dotIndex); - path = dotIndex == -1 ? "" : path.substring(dotIndex + 1); - - if (value.endsWith(")")) { - // The value is an object, which needs to run on map. - value += ".map((obj: any) => obj"; - } - - // Process keys https://jmespath.org/specification.html#keys - if (part.startsWith("keys(")) { - // Get provided object for which keys are to be extracted. - String object = part.substring(5, part.length() - 1); - value = "Object.keys(" + value + separator + object + " ?? {})"; - continue; - } - - // Process list wildcard expression https://jmespath.org/specification.html#wildcard-expressions - if (part.equals("*") || part.equals("[*]")) { - value = "Object.values(" + value + " ?? {})"; - continue; - } - - // Process hash wildcard expression https://jmespath.org/specification.html#wildcard-expressions - if (part.endsWith("[*]")) { - // Get key to run hash wildcard on. - String key = part.substring(0, part.length() - 3); - value = value + separator + key + separator + "map((obj: any) => obj"; - continue; - } - - // Treat remaining part as identifier without spaces https://jmespath.org/specification.html#identifiers - value += separator + part; - } + value = getJmesPathExpression(separator, value, path); // Remove no-op map, if it exists. final String noOpMap = "map((obj: any) => obj"; @@ -332,6 +296,74 @@ public Map getOperationContextParamValues(OperationShape operati return map; } + private String getJmesPathExpression(String separator, String value, String path) { + // Split JMESPath expression string on separator and add JavaScript equivalent. + while (path.length() > 0) { + if (path.startsWith("[") && !path.startsWith("[*]")) { + // Process MultiSelect List https://jmespath.org/specification.html#multiselect-list + if (value.endsWith("obj")) { + value = value.substring(0, value.length() - 3); + } + + value += "["; + path = path.substring(1); + + while (true) { + int commaIndex = path.indexOf(","); + int sepIndex = (commaIndex == -1) ? path.indexOf("]") : commaIndex; + String part = path.substring(0, sepIndex); + path = path.substring(sepIndex + 1).trim(); + value += getJmesPathExpression(separator, "obj", part) + ","; + if (commaIndex == -1) { + // Remove trailing comma and close bracket. + value = value.substring(0, value.length() - 1) + "].filter((i) => i))"; + break; + } + } + continue; + } + + int dotIndex = path.indexOf("."); + String part = dotIndex == -1 ? path : path.substring(0, dotIndex); + path = dotIndex == -1 ? "" : path.substring(dotIndex + 1); + value = getJmesPathExpressionSection(separator, value, part); + } + return value; + } + + private String getJmesPathExpressionSection(String separator, String value, String part) { + if (value.endsWith(")")) { + // The value is an object, which needs to run on map. + value += ".map((obj: any) => obj"; + } + + // Process keys https://jmespath.org/specification.html#keys + if (part.startsWith("keys(")) { + // Get provided object for which keys are to be extracted. + String object = part.substring(5, part.length() - 1); + value = "Object.keys(" + value + separator + object + " ?? {})"; + return value; + } + + // Process list wildcard expression https://jmespath.org/specification.html#wildcard-expressions + if (part.equals("*") || part.equals("[*]")) { + value = "Object.values(" + value + " ?? {})"; + return value; + } + + // Process hash wildcard expression https://jmespath.org/specification.html#wildcard-expressions + if (part.endsWith("[*]")) { + // Get key to run hash wildcard on. + String key = part.substring(0, part.length() - 3); + value = value + separator + key + separator + "map((obj: any) => obj"; + return value; + } + + // Treat remaining part as identifier without spaces https://jmespath.org/specification.html#identifiers + value += separator + part; + return value; + } + private static class RuleSetParameterFinderVisitor extends NodeVisitor.Default { private final Map map; From affaa2a13a216ba982b184aae1e3364aceb59c72 Mon Sep 17 00:00:00 2001 From: Trivikram Kamat <16024985+trivikr@users.noreply.github.com> Date: Wed, 26 Feb 2025 23:18:24 +0000 Subject: [PATCH 5/5] Add test for MultiSelect List of Lists --- .../smithy/typescript/codegen/CommandGeneratorTest.java | 2 +- .../endpointsV2/endpoints-operation-context-params.smithy | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/smithy-typescript-codegen/src/test/java/software/amazon/smithy/typescript/codegen/CommandGeneratorTest.java b/smithy-typescript-codegen/src/test/java/software/amazon/smithy/typescript/codegen/CommandGeneratorTest.java index f09607c1110..35db3414328 100644 --- a/smithy-typescript-codegen/src/test/java/software/amazon/smithy/typescript/codegen/CommandGeneratorTest.java +++ b/smithy-typescript-codegen/src/test/java/software/amazon/smithy/typescript/codegen/CommandGeneratorTest.java @@ -44,7 +44,7 @@ public void writesOperationContextParamValues() { "opContextParamWildcardExpressionList: { type: \"operationContextParams\", get: (input?: any) => input?.fooList }", "opContextParamWildcardExpressionListObj: { type: \"operationContextParams\", get: (input?: any) => input?.fooListObj?.map((obj: any) => obj?.key) }", "opContextParamWildcardExpressionHash: { type: \"operationContextParams\", get: (input?: any) => Object.values(input?.fooObjObj ?? {}).map((obj: any) => obj?.bar) }", - "opContextParamMultiSelectList: { type: \"operationContextParams\", get: (input?: any) => input?.fooListObjObj?.map((obj: any) => [obj?.baz?.bar,obj?.qux].filter((i) => i)) }", + "opContextParamMultiSelectList: { type: \"operationContextParams\", get: (input?: any) => input?.fooListObjObj?.map((obj: any) => [obj?.fooList[0],obj?.fooObject?.bar,obj?.fooString].filter((i) => i)) }", "opContextParamKeys: { type: \"operationContextParams\", get: (input?: any) => Object.keys(input?.fooKeys ?? {}) }", } ); diff --git a/smithy-typescript-codegen/src/test/resources/software/amazon/smithy/typescript/codegen/endpointsV2/endpoints-operation-context-params.smithy b/smithy-typescript-codegen/src/test/resources/software/amazon/smithy/typescript/codegen/endpointsV2/endpoints-operation-context-params.smithy index 29a5eb93a34..29817f28ee3 100644 --- a/smithy-typescript-codegen/src/test/resources/software/amazon/smithy/typescript/codegen/endpointsV2/endpoints-operation-context-params.smithy +++ b/smithy-typescript-codegen/src/test/resources/software/amazon/smithy/typescript/codegen/endpointsV2/endpoints-operation-context-params.smithy @@ -40,7 +40,7 @@ service Example { "opContextParamWildcardExpressionList": { path: "fooList[*]" } "opContextParamWildcardExpressionListObj": { path: "fooListObj[*].key" } "opContextParamWildcardExpressionHash": { path: "fooObjObj.*.bar" } - "opContextParamMultiSelectList": { path: "fooListObjObj[*].[baz.bar, qux]" } + "opContextParamMultiSelectList": { path: "fooListObjObj[*].[fooList[0], fooObject.bar, fooString]" } "opContextParamKeys": { path: "keys(fooKeys)" } ) operation GetFoo { @@ -68,8 +68,9 @@ list FooListObjectObject { } structure FooMultiSelectObjectObject { - baz: FooObject - qux: String + fooList: FooList + fooObject: FooObject + fooString: String } structure FooObjectObject {