Skip to content

Commit

Permalink
subordinate ProtocolPriorityConfig to TypeScriptSettings
Browse files Browse the repository at this point in the history
  • Loading branch information
kuhe committed Aug 19, 2024
1 parent 552e4d6 commit e560080
Show file tree
Hide file tree
Showing 4 changed files with 273 additions and 133 deletions.
28 changes: 15 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,19 +185,21 @@ By default, the Smithy TypeScript code generators provide the code generation fr
[`TypeScriptSettings`](smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/TypeScriptSettings.java) contains all of the settings enabled from `smithy-build.json` and helper methods and types. The up-to-date list of top-level properties enabled for `typescript-client-codegen` can be found in `TypeScriptSettings.ArtifactType.CLIENT`.

|Setting|Required|Description|
|---|---|---|
|`package`|Yes|Name of the package in `package.json`.|
|`packageVersion`|Yes|Version of the package in `package.json`.|
|`packageDescription`|No|Description of the package in `package.json`. The default value is `${package} client`|
|`packageJson`|No|Custom `package.json` properties that will be merged with the base `package.json`. The default value is an empty object.|
|`packageManager`|No|Configured package manager for the package. The default value is `yarn`.|
|`service`|No|The Shape ID of the service to generate a client for. If not provided, the code generator will attempt to infer the service Shape ID. If there is exactly 1 service found in the model, then the service is used as the inferred Shape ID. If no services are found, then code generation fails. If more than 1 service is found, then code generation fails.|
|`protocol`|No|The Shape ID of the protocol used to generate serialization and deserialization. If not provided, the code generator will attempt to resolve the highest priority service protocol supported in code generation (registered through `TypeScriptIntegration`). If no protocols are found, code generation will use serialization and deserialization error stubs.|
|`private`|No|Whether the package is `private` in `package.json`. The default value is `false`.|
|`requiredMemberMode`|No|**NOT RECOMMENDED DUE TO BACKWARD COMPATIBILITY CONCERNS.** Sets whether members marked with the `@required` trait are allowed to be `undefined`. See more details on the risks in `TypeScriptSettings.RequiredMemberMode`. The default value is `nullable`.|
|`createDefaultReadme`|No|Whether to generate a default `README.md` for the package. The default value is `false`.|
|`useLegacyAuth`|No|**NOT RECOMMENDED, AVAILABLE ONLY FOR BACKWARD COMPATIBILITY CONCERNS.** Flag that enables using legacy auth. When in doubt, use the default identity and auth behavior (not configuring `useLegacyAuth`) as the golden path.|
| Setting |Required| Description |
|---------------------------|---|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `package` |Yes| Name of the package in `package.json`. |
| `packageVersion` |Yes| Version of the package in `package.json`. |
| `packageDescription` |No| Description of the package in `package.json`. The default value is `${package} client` |
| `packageJson` |No| Custom `package.json` properties that will be merged with the base `package.json`. The default value is an empty object. |
| `packageManager` |No| Configured package manager for the package. The default value is `yarn`. |
| `service` |No| The Shape ID of the service to generate a client for. If not provided, the code generator will attempt to infer the service Shape ID. If there is exactly 1 service found in the model, then the service is used as the inferred Shape ID. If no services are found, then code generation fails. If more than 1 service is found, then code generation fails. |
| `protocol` |No| The Shape ID of the protocol used to generate serialization and deserialization. If not provided, the code generator will attempt to resolve the highest priority service protocol supported in code generation (registered through `TypeScriptIntegration`). If no protocols are found, code generation will use serialization and deserialization error stubs. |
| `private` |No| Whether the package is `private` in `package.json`. The default value is `false`. |
| `requiredMemberMode` |No| **NOT RECOMMENDED DUE TO BACKWARD COMPATIBILITY CONCERNS.** Sets whether members marked with the `@required` trait are allowed to be `undefined`. See more details on the risks in `TypeScriptSettings.RequiredMemberMode`. The default value is `nullable`. |
| `createDefaultReadme` |No| Whether to generate a default `README.md` for the package. The default value is `false`. |
| `useLegacyAuth` |No| **NOT RECOMMENDED, AVAILABLE ONLY FOR BACKWARD COMPATIBILITY CONCERNS.** Flag that enables using legacy auth. When in doubt, use the default identity and auth behavior (not configuring `useLegacyAuth`) as the golden path. |
| `serviceProrotolPriority` |No| Map of service `ShapeId` strings to lists of protocol `ShapeId` strings. Used to override protocol selection behavior. |
| `defaultProtocolPriority` |No| List of protocol `ShapeId` strings. Lower precedence than `serviceProrotolPriority` but applies to all services. |

#### `typescript-client-codegen` plugin artifacts

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.logging.Logger;
Expand All @@ -28,6 +29,7 @@
import software.amazon.smithy.codegen.core.SymbolProvider;
import software.amazon.smithy.model.Model;
import software.amazon.smithy.model.knowledge.ServiceIndex;
import software.amazon.smithy.model.node.ArrayNode;
import software.amazon.smithy.model.node.BooleanNode;
import software.amazon.smithy.model.node.Node;
import software.amazon.smithy.model.node.ObjectNode;
Expand All @@ -37,7 +39,7 @@
import software.amazon.smithy.model.shapes.ShapeId;
import software.amazon.smithy.model.traits.DefaultTrait;
import software.amazon.smithy.model.traits.RequiredTrait;
import software.amazon.smithy.typescript.codegen.protocols.ProtocolPriority;
import software.amazon.smithy.typescript.codegen.protocols.ProtocolPriorityConfig;
import software.amazon.smithy.utils.SmithyUnstableApi;

/**
Expand All @@ -61,6 +63,8 @@ public final class TypeScriptSettings {
private static final String CREATE_DEFAULT_README = "createDefaultReadme";
private static final String USE_LEGACY_AUTH = "useLegacyAuth";
private static final String GENERATE_TYPEDOC = "generateTypeDoc";
private static final String SERVICE_PROTOCOL_PRIORITY = "serviceProtocolPriority";
private static final String DEFAULT_PROTOCOL_PRIORITY = "defaultProtocolPriority";

private String packageName;
private String packageDescription = "";
Expand All @@ -79,6 +83,7 @@ public final class TypeScriptSettings {
private boolean createDefaultReadme = false;
private boolean useLegacyAuth = false;
private boolean generateTypeDoc = false;
private final ProtocolPriorityConfig protocolPriorityConfig = new ProtocolPriorityConfig();

@Deprecated
public static TypeScriptSettings from(Model model, ObjectNode config) {
Expand Down Expand Up @@ -130,6 +135,9 @@ public static TypeScriptSettings from(Model model, ObjectNode config, ArtifactTy
.orElse(RequiredMemberMode.NULLABLE));

settings.setPluginSettings(config);

settings.readProtocolPriorityConfiguration(config);

return settings;
}

Expand Down Expand Up @@ -452,7 +460,7 @@ public ShapeId resolveServiceProtocol(Model model, ServiceShape service, Set<Sha
+ "generate in smithy-build.json to generate this service.");
}

List<ShapeId> protocolPriority = ProtocolPriority.getProtocolPriority(service.toShapeId());
List<ShapeId> protocolPriority = this.protocolPriorityConfig.getProtocolPriority(service.toShapeId());
List<ShapeId> protocolPriorityList = protocolPriority != null && !protocolPriority.isEmpty()
? protocolPriority
: new ArrayList<>(supportedProtocols);
Expand Down Expand Up @@ -489,6 +497,13 @@ public String getDefaultSigningName() {
return defaultSigningName;
}

/**
* @return config container for service and/or default protocol selection priority overrides.
*/
public ProtocolPriorityConfig getProtocolPriority() {
return protocolPriorityConfig;
}

/**
* An enum indicating the type of artifact the code generator will produce.
*/
Expand Down Expand Up @@ -593,4 +608,46 @@ public static PackageManager fromString(String s) {
throw new CodegenException(String.format("Unsupported package manager: %s", s));
}
}

/**
* Reads serviceProtocolPriority and defaultProtocolPriority configuration fields.
* {
* serviceProtocolPriority: {
* "namespace#Service": ["namespace#Protocol1", "namespace#Protocol2"]
* },
* defaultProtocolPriority: ["namespace#Protocol"]
* }
*/
private void readProtocolPriorityConfiguration(ObjectNode config) {
try {
Optional<ObjectNode> protocolPriorityNode = config.getObjectMember(SERVICE_PROTOCOL_PRIORITY);
if (protocolPriorityNode.isPresent()) {
ObjectNode objectNode = protocolPriorityNode.get();
objectNode.getMembers().forEach((StringNode k, Node v) -> {
ShapeId serviceShapeId = ShapeId.from(k.getValue());
List<ShapeId> protocolList = v.asArrayNode().get().getElementsAs(
e -> ShapeId.from(e.asStringNode().get().getValue())
);
protocolPriorityConfig.setProtocolPriority(
serviceShapeId,
protocolList
);
});
}
Optional<ArrayNode> defaultProtocolPriorityOpt = config.getArrayMember(DEFAULT_PROTOCOL_PRIORITY);
if (defaultProtocolPriorityOpt.isPresent()) {
ArrayNode defaultProtocolPriorityStringArr = defaultProtocolPriorityOpt.get();
protocolPriorityConfig.setCustomDefaultProtocolPriority(
defaultProtocolPriorityStringArr.getElementsAs(
e -> ShapeId.from(e.asStringNode().get().getValue())
)
);
}
} catch (Exception e) {
throw new IllegalArgumentException(
"Error while parsing serviceProtocolPriority or defaultProtocolPriority configuration fields",
e
);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,33 +15,31 @@
/**
* Allows customization of protocol selection for specific services or a global default ordering.
*/
public final class ProtocolPriority {
private static final Map<ShapeId, List<ShapeId>> SERVICE_PROTOCOL_PRIORITY_CUSTOMIZATIONS = new HashMap<>();
private static List<ShapeId> customDefaultPriority = null;

private ProtocolPriority() {}
public final class ProtocolPriorityConfig {
private final Map<ShapeId, List<ShapeId>> serviceProtocolPriorityCustomizations = new HashMap<>();
private List<ShapeId> customDefaultPriority = null;

/**
* @param serviceShapeId - service scope.
* @param protocolPriorityOrder - priority order of protocols.
*/
public static void setProtocolPriority(ShapeId serviceShapeId, List<ShapeId> protocolPriorityOrder) {
SERVICE_PROTOCOL_PRIORITY_CUSTOMIZATIONS.put(serviceShapeId, protocolPriorityOrder);
public void setProtocolPriority(ShapeId serviceShapeId, List<ShapeId> protocolPriorityOrder) {
serviceProtocolPriorityCustomizations.put(serviceShapeId, protocolPriorityOrder);
}

/**
* @param defaultProtocolPriorityOrder - use for all services that don't have a more specific priority order.
*/
public static void setCustomDefaultProtocolPriority(List<ShapeId> defaultProtocolPriorityOrder) {
public void setCustomDefaultProtocolPriority(List<ShapeId> defaultProtocolPriorityOrder) {
customDefaultPriority = new ArrayList<>(defaultProtocolPriorityOrder);
}

/**
* @param serviceShapeId - service scope.
* @return priority order of protocols or null if no override exists.
*/
public static List<ShapeId> getProtocolPriority(ShapeId serviceShapeId) {
return SERVICE_PROTOCOL_PRIORITY_CUSTOMIZATIONS.getOrDefault(
public List<ShapeId> getProtocolPriority(ShapeId serviceShapeId) {
return serviceProtocolPriorityCustomizations.getOrDefault(
serviceShapeId,
customDefaultPriority != null ? new ArrayList<>(customDefaultPriority) : null
);
Expand All @@ -50,14 +48,14 @@ public static List<ShapeId> getProtocolPriority(ShapeId serviceShapeId) {
/**
* @param serviceShapeId - to unset.
*/
public static void deleteProtocolPriority(ShapeId serviceShapeId) {
SERVICE_PROTOCOL_PRIORITY_CUSTOMIZATIONS.remove(serviceShapeId);
public void deleteProtocolPriority(ShapeId serviceShapeId) {
serviceProtocolPriorityCustomizations.remove(serviceShapeId);
}

/**
* Unset the custom default priority order.
*/
public static void deleteCustomDefaultProtocolPriority() {
public void deleteCustomDefaultProtocolPriority() {
customDefaultPriority = null;
}
}
Loading

0 comments on commit e560080

Please sign in to comment.