5151import software .amazon .smithy .model .traits .ErrorTrait ;
5252import software .amazon .smithy .model .traits .ExamplesTrait ;
5353import software .amazon .smithy .model .traits .InternalTrait ;
54+ import software .amazon .smithy .model .traits .StreamingTrait ;
5455import software .amazon .smithy .rulesengine .traits .EndpointRuleSetTrait ;
5556import software .amazon .smithy .typescript .codegen .documentation .DocumentationExampleGenerator ;
5657import software .amazon .smithy .typescript .codegen .documentation .StructureExampleGenerator ;
6364import software .amazon .smithy .typescript .codegen .sections .PreCommandClassCodeSection ;
6465import software .amazon .smithy .typescript .codegen .sections .SmithyContextCodeSection ;
6566import software .amazon .smithy .typescript .codegen .util .CommandWriterConsumer ;
67+ import software .amazon .smithy .typescript .codegen .util .PropertyAccessor ;
6668import software .amazon .smithy .typescript .codegen .validation .SensitiveDataFinder ;
6769import software .amazon .smithy .utils .SmithyInternalApi ;
6870
@@ -255,28 +257,30 @@ private String getCommandExample(
255257 ) {
256258 String packageName = settings .getPackageName ();
257259 String exampleDoc = "@example\n "
258- + "Use a bare-bones client and the command you need to make an API call.\n "
259- + "```javascript\n "
260- + String .format ("import { %s, %s } from \" %s\" ; // ES Modules import%n" , serviceName , commandName ,
261- packageName )
262- + String .format ("// const { %s, %s } = require(\" %s\" ); // CommonJS import%n" , serviceName , commandName ,
263- packageName )
264- + String .format ("const client = new %s(config);%n" , serviceName )
265- + String .format ("const input = %s%n" ,
266- StructureExampleGenerator .generateStructuralHintDocumentation (
267- model .getShape (operation .getInputShape ()).get (), model , false , true ))
268- + String .format ("const command = new %s(input);%n" , commandName )
269- + "const response = await client.send(command);\n "
270- + String .format ("%s%n" ,
271- StructureExampleGenerator .generateStructuralHintDocumentation (
272- model .getShape (operation .getOutputShape ()).get (), model , true , false ))
273- + "\n ```\n "
274- + "\n "
275- + String .format ("@param %s - {@link %s}%n" , commandInput , commandInput )
276- + String .format ("@returns {@link %s}%n" , commandOutput )
277- + String .format ("@see {@link %s} for command's `input` shape.%n" , commandInput )
278- + String .format ("@see {@link %s} for command's `response` shape.%n" , commandOutput )
279- + String .format ("@see {@link %s | config} for %s's `config` shape.%n" , configName , serviceName );
260+ + "Use a bare-bones client and the command you need to make an API call.\n "
261+ + "```javascript\n "
262+ + String .format ("import { %s, %s } from \" %s\" ; // ES Modules import%n" , serviceName , commandName ,
263+ packageName )
264+ + String .format ("// const { %s, %s } = require(\" %s\" ); // CommonJS import%n" , serviceName , commandName ,
265+ packageName )
266+ + String .format ("const client = new %s(config);%n" , serviceName )
267+ + String .format ("const input = %s%n" ,
268+ StructureExampleGenerator .generateStructuralHintDocumentation (
269+ model .getShape (operation .getInputShape ()).get (), model , false , true ))
270+ + String .format ("const command = new %s(input);%n" , commandName )
271+ + "const response = await client.send(command);"
272+ + getStreamingBlobOutputAddendum ()
273+ + "\n "
274+ + String .format ("%s%n" ,
275+ StructureExampleGenerator .generateStructuralHintDocumentation (
276+ model .getShape (operation .getOutputShape ()).get (), model , true , false ))
277+ + "\n ```\n "
278+ + "\n "
279+ + String .format ("@param %s - {@link %s}%n" , commandInput , commandInput )
280+ + String .format ("@returns {@link %s}%n" , commandOutput )
281+ + String .format ("@see {@link %s} for command's `input` shape.%n" , commandInput )
282+ + String .format ("@see {@link %s} for command's `response` shape.%n" , commandOutput )
283+ + String .format ("@see {@link %s | config} for %s's `config` shape.%n" , configName , serviceName );
280284
281285 return exampleDoc ;
282286 }
@@ -301,13 +305,14 @@ private String getCuratedExamples(String commandName) {
301305 .append ("""
302306 const input = %s;
303307 const command = new %s(input);
304- const response = await client.send(command);
308+ const response = await client.send(command);%s
305309 /* response is
306310 %s
307311 */
308312 """ .formatted (
309313 DocumentationExampleGenerator .inputToJavaScriptObject (input ),
310314 commandName ,
315+ getStreamingBlobOutputAddendum (),
311316 DocumentationExampleGenerator .outputToJavaScriptObject (output .orElse (null ))
312317 ))
313318 .append ("```" )
@@ -319,6 +324,49 @@ private String getCuratedExamples(String commandName) {
319324 return exampleDoc ;
320325 }
321326
327+ /**
328+ * @param operation - to query.
329+ * @return member name of the streaming blob http payload, or empty string.
330+ */
331+ private String getStreamingBlobOutputMember (OperationShape operation ) {
332+ return (model .expectShape (operation .getOutputShape ()))
333+ .getAllMembers ()
334+ .values ()
335+ .stream ()
336+ .filter (memberShape -> {
337+ Shape target = model .expectShape (memberShape .getTarget ());
338+ return target .isBlobShape () && (
339+ target .hasTrait (StreamingTrait .class )
340+ || memberShape .hasTrait (StreamingTrait .class )
341+ );
342+ })
343+ .map (MemberShape ::getMemberName )
344+ .findFirst ()
345+ .orElse ("" );
346+ }
347+
348+ /**
349+ * @return e.g. appendable "const bytes = await response.Body.transformToByteArray();".
350+ */
351+ private String getStreamingBlobOutputAddendum () {
352+ String streamingBlobAddendum = "" ;
353+ String streamingBlobMemberName = getStreamingBlobOutputMember (operation );
354+ if (!streamingBlobMemberName .isEmpty ()) {
355+ String propAccess = PropertyAccessor .getFrom ("response" , streamingBlobMemberName );
356+ streamingBlobAddendum = """
357+ \n // consume or destroy the stream to free the socket.
358+ const bytes = await %s.transformToByteArray();
359+ // const str = await %s.transformToString();
360+ // %s.destroy(); // only applicable to Node.js Readable streams.
361+ """ .formatted (
362+ propAccess ,
363+ propAccess ,
364+ propAccess
365+ );
366+ }
367+ return streamingBlobAddendum ;
368+ }
369+
322370 private String getThrownExceptions () {
323371 List <ShapeId > errors = operation .getErrors ();
324372 StringBuilder buffer = new StringBuilder ();
0 commit comments