51
51
import software .amazon .smithy .model .traits .ErrorTrait ;
52
52
import software .amazon .smithy .model .traits .ExamplesTrait ;
53
53
import software .amazon .smithy .model .traits .InternalTrait ;
54
+ import software .amazon .smithy .model .traits .StreamingTrait ;
54
55
import software .amazon .smithy .rulesengine .traits .EndpointRuleSetTrait ;
55
56
import software .amazon .smithy .typescript .codegen .documentation .DocumentationExampleGenerator ;
56
57
import software .amazon .smithy .typescript .codegen .documentation .StructureExampleGenerator ;
63
64
import software .amazon .smithy .typescript .codegen .sections .PreCommandClassCodeSection ;
64
65
import software .amazon .smithy .typescript .codegen .sections .SmithyContextCodeSection ;
65
66
import software .amazon .smithy .typescript .codegen .util .CommandWriterConsumer ;
67
+ import software .amazon .smithy .typescript .codegen .util .PropertyAccessor ;
66
68
import software .amazon .smithy .typescript .codegen .validation .SensitiveDataFinder ;
67
69
import software .amazon .smithy .utils .SmithyInternalApi ;
68
70
@@ -255,28 +257,30 @@ private String getCommandExample(
255
257
) {
256
258
String packageName = settings .getPackageName ();
257
259
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 );
280
284
281
285
return exampleDoc ;
282
286
}
@@ -301,13 +305,14 @@ private String getCuratedExamples(String commandName) {
301
305
.append ("""
302
306
const input = %s;
303
307
const command = new %s(input);
304
- const response = await client.send(command);
308
+ const response = await client.send(command);%s
305
309
/* response is
306
310
%s
307
311
*/
308
312
""" .formatted (
309
313
DocumentationExampleGenerator .inputToJavaScriptObject (input ),
310
314
commandName ,
315
+ getStreamingBlobOutputAddendum (),
311
316
DocumentationExampleGenerator .outputToJavaScriptObject (output .orElse (null ))
312
317
))
313
318
.append ("```" )
@@ -319,6 +324,49 @@ private String getCuratedExamples(String commandName) {
319
324
return exampleDoc ;
320
325
}
321
326
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
+
322
370
private String getThrownExceptions () {
323
371
List <ShapeId > errors = operation .getErrors ();
324
372
StringBuilder buffer = new StringBuilder ();
0 commit comments