66
77import java .util .HashSet ;
88import java .util .Set ;
9+ import java .util .logging .Logger ;
910import software .amazon .smithy .model .Model ;
1011import software .amazon .smithy .model .loader .Prelude ;
1112import software .amazon .smithy .model .selector .Selector ;
2526import software .amazon .smithy .model .transform .ModelTransformer ;
2627
2728final class CreateSyntheticService {
29+ private static final Logger LOGGER = Logger .getLogger (CreateSyntheticService .class .getName ());
2830 private static final String SYNTHETIC_NAMESPACE = "smithy.synthetic" ;
2931 private static final String SYNTHETIC_OPERATION_NAME = "TypesGenOperation" ;
3032 static final ShapeId SYNTHETIC_SERVICE_ID = ShapeId .fromParts (SYNTHETIC_NAMESPACE , "TypesGenService" );
@@ -33,6 +35,8 @@ final class CreateSyntheticService {
3335 ShapeType .UNION ,
3436 ShapeType .ENUM ,
3537 ShapeType .INT_ENUM );
38+ private static final Set <ShapeId > TRAIT_BLOCKLIST =
39+ Set .of (MixinTrait .ID , ProtocolDefinitionTrait .ID , TraitDefinition .ID , PrivateTrait .ID );
3640
3741 private final Selector selector ;
3842 private final boolean includeInputsAndOutputs ;
@@ -54,24 +58,34 @@ Model transform(ModelTransformer transformer, Model model) {
5458 }
5559
5660 var operationId = ShapeId .fromParts (SYNTHETIC_NAMESPACE , SYNTHETIC_OPERATION_NAME + index );
57- var inputId = ShapeId .fromParts (SYNTHETIC_NAMESPACE , operationId .getName () + "Input" );
58- var inputBuilder = StructureShape .builder ()
59- .id (inputId )
60- .addTrait (new InputTrait ());
61- var operationBuilder = OperationShape .builder ().id (operationId ).input (inputId );
62- serviceBuilder .addOperation (operationId );
61+ var operationBuilder = OperationShape .builder ().id (operationId );
6362
6463 if (shape .hasTrait (ErrorTrait .class )) {
6564 operationBuilder .addError (shape .getId ());
65+ } else if (shape .hasTrait (InputTrait .class )) {
66+ operationBuilder .input (shape );
67+ } else if (shape .hasTrait (OutputTrait .class )) {
68+ operationBuilder .output (shape );
6669 } else {
67- inputBuilder .addMember ("member" , shape .getId ());
70+ var input = StructureShape .builder ()
71+ .id (ShapeId .fromParts (SYNTHETIC_NAMESPACE , operationId .getName () + "Input" ))
72+ .addTrait (new InputTrait ())
73+ .addMember ("member" , shape .getId ())
74+ .build ();
6875 index ++;
76+ operationBuilder .input (input );
77+ addedShapes .add (input );
6978 }
70- addedShapes .add (inputBuilder .build ());
79+
80+ serviceBuilder .addOperation (operationId );
7181 addedShapes .add (operationBuilder .build ());
7282 }
7383
7484 addedShapes .add (serviceBuilder .build ());
85+
86+ // First, remove all existing operations and services. We don't need them, and they'll just get in the way
87+ // of adding input and output shapes if we're doing that.
88+ model = transformer .removeShapesIf (model , shape -> shape .isOperationShape () || shape .isServiceShape ());
7589 model = transformer .replaceShapes (model , addedShapes );
7690
7791 // Ensure validation gets run so we aren't generating anything too crazy
@@ -80,16 +94,26 @@ Model transform(ModelTransformer transformer, Model model) {
8094 }
8195
8296 private boolean shouldGenerate (Shape shape ) {
83- if (!GENERATED_TYPES .contains (shape .getType ())
84- || shape .hasTrait (MixinTrait .class )
85- || shape .hasTrait (ProtocolDefinitionTrait .class )
86- || shape .hasTrait (TraitDefinition .class )
87- || shape .hasTrait (PrivateTrait .class )
88- || Prelude .isPreludeShape (shape )) {
97+ if (!GENERATED_TYPES .contains (shape .getType ()) || Prelude .isPreludeShape (shape )) {
98+ return false ;
99+ }
100+
101+ if (!includeInputsAndOutputs && (shape .hasTrait (InputTrait .class ) || shape .hasTrait (OutputTrait .class ))) {
102+ LOGGER .finest ("""
103+ Skipping generating Python type for shape `%s` because it is either an input or output shape. \
104+ To generate this shape anyway, set "generateInputsAndOutputs" to true.""" .formatted (shape .getId ()));
89105 return false ;
90106 }
91107
92- return includeInputsAndOutputs
93- || (!shape .hasTrait (InputTrait .class ) && !shape .hasTrait (OutputTrait .class ));
108+ for (var blockedTrait : TRAIT_BLOCKLIST ) {
109+ if (shape .hasTrait (blockedTrait )) {
110+ LOGGER .finest ("Skipping generating Python type for shape `%s` because it has trait `%s`" .formatted (
111+ shape .getId (),
112+ blockedTrait ));
113+ return false ;
114+ }
115+ }
116+
117+ return true ;
94118 }
95119}
0 commit comments