17
17
18
18
import static java .lang .String .format ;
19
19
20
+ import java .util .Comparator ;
21
+ import java .util .HashMap ;
20
22
import java .util .HashSet ;
23
+ import java .util .Map ;
21
24
import java .util .Optional ;
22
25
import java .util .Set ;
23
26
import java .util .logging .Logger ;
27
+
28
+ import software .amazon .smithy .build .FileManifest ;
24
29
import software .amazon .smithy .codegen .core .CodegenException ;
25
30
import software .amazon .smithy .codegen .core .ReservedWordSymbolProvider ;
26
31
import software .amazon .smithy .codegen .core .ReservedWords ;
@@ -75,8 +80,13 @@ final class SymbolVisitor implements SymbolProvider, ShapeVisitor<Symbol> {
75
80
private final Model model ;
76
81
private final ReservedWordSymbolProvider .Escaper escaper ;
77
82
private final Set <StructureShape > errorShapes = new HashSet <>();
83
+ private final ModuleNameDelegator moduleNameDelegator ;
78
84
79
85
SymbolVisitor (Model model ) {
86
+ this (model , ModuleNameDelegator .DEFAULT_CHUNK_SIZE );
87
+ }
88
+
89
+ SymbolVisitor (Model model , int shapeChunkSize ) {
80
90
this .model = model ;
81
91
82
92
// Load reserved words from a new-line delimited file.
@@ -96,6 +106,12 @@ final class SymbolVisitor implements SymbolProvider, ShapeVisitor<Symbol> {
96
106
model .shapes (OperationShape .class ).forEach (operationShape -> {
97
107
errorShapes .addAll (operationIndex .getErrors (operationShape ));
98
108
});
109
+
110
+ moduleNameDelegator = new ModuleNameDelegator (shapeChunkSize );
111
+ }
112
+
113
+ static void writeModelIndex (Model model , SymbolProvider symbolProvider , FileManifest fileManifest ) {
114
+ ModuleNameDelegator .writeModelIndex (model , symbolProvider , fileManifest );
99
115
}
100
116
101
117
@ Override
@@ -225,7 +241,7 @@ public Symbol documentShape(DocumentShape shape) {
225
241
@ Override
226
242
public Symbol operationShape (OperationShape shape ) {
227
243
String commandName = flattenShapeName (shape ) + "Command" ;
228
- String moduleName = formatModuleName (shape . getType () , commandName );
244
+ String moduleName = moduleNameDelegator . formatModuleName (shape , commandName );
229
245
Symbol intermediate = createGeneratedSymbolBuilder (shape , commandName , moduleName ).build ();
230
246
Symbol .Builder builder = intermediate .toBuilder ();
231
247
// Add input and output type symbols (XCommandInput / XCommandOutput).
@@ -271,7 +287,7 @@ public Symbol resourceShape(ResourceShape shape) {
271
287
@ Override
272
288
public Symbol serviceShape (ServiceShape shape ) {
273
289
String name = StringUtils .capitalize (shape .getId ().getName ()) + "Client" ;
274
- String moduleName = formatModuleName (shape . getType () , name );
290
+ String moduleName = moduleNameDelegator . formatModuleName (shape , name );
275
291
return createGeneratedSymbolBuilder (shape , name , moduleName ).build ();
276
292
}
277
293
@@ -358,7 +374,7 @@ private String flattenShapeName(ToShapeId id) {
358
374
359
375
private Symbol .Builder createObjectSymbolBuilder (Shape shape ) {
360
376
String name = flattenShapeName (shape );
361
- String moduleName = formatModuleName (shape . getType () , name );
377
+ String moduleName = moduleNameDelegator . formatModuleName (shape , name );
362
378
return createGeneratedSymbolBuilder (shape , name , moduleName );
363
379
}
364
380
@@ -378,18 +394,57 @@ private Symbol.Builder createGeneratedSymbolBuilder(Shape shape, String typeName
378
394
.definitionFile (toFilename (namespace ));
379
395
}
380
396
381
- private String formatModuleName (ShapeType shapeType , String name ) {
382
- // All shapes except for the service and operations are stored in models.
383
- if (shapeType == ShapeType .SERVICE ) {
384
- return "./" + name ;
385
- } else if (shapeType == ShapeType .OPERATION ) {
386
- return "./commands/" + name ;
387
- } else {
388
- return "./models/index" ;
389
- }
390
- }
391
-
392
397
private String toFilename (String namespace ) {
393
398
return namespace + ".ts" ;
394
399
}
400
+
401
+ /**
402
+ * Utility class to locate which path should the symbol be generated into.
403
+ * It will break the models into multiple files to prevent it getting too big.
404
+ */
405
+ static final class ModuleNameDelegator {
406
+ static final int DEFAULT_CHUNK_SIZE = 300 ;
407
+ static final String SHAPE_NAMESPACE_PREFIX = "./models/" ;
408
+
409
+ private final Map <Shape , String > visitedModels = new HashMap <>();
410
+ private int bucketCount = 0 ;
411
+ private int currentBucketSize = 0 ;
412
+ private final int chunkSize ;
413
+
414
+ ModuleNameDelegator (int shapeChunkSize ) {
415
+ chunkSize = shapeChunkSize ;
416
+ }
417
+
418
+ public String formatModuleName (Shape shape , String name ) {
419
+ // All shapes except for the service and operations are stored in models.
420
+ if (shape .getType () == ShapeType .SERVICE ) {
421
+ return "./" + name ;
422
+ } else if (shape .getType () == ShapeType .OPERATION ) {
423
+ return "./commands/" + name ;
424
+ } else if (visitedModels .containsKey (shape )) {
425
+ return visitedModels .get (shape );
426
+ }
427
+ // Add models into buckets no bigger than chunk size.
428
+ String path = SHAPE_NAMESPACE_PREFIX + "models_" + bucketCount ;
429
+ visitedModels .put (shape , path );
430
+ currentBucketSize ++;
431
+ if (currentBucketSize == chunkSize ) {
432
+ bucketCount ++;
433
+ currentBucketSize = 0 ;
434
+ }
435
+ return path ;
436
+ }
437
+
438
+ static void writeModelIndex (Model model , SymbolProvider symbolProvider , FileManifest fileManifest ) {
439
+ TypeScriptWriter writer = new TypeScriptWriter ("" );
440
+ model .shapes ()
441
+ .map (shape -> symbolProvider .toSymbol (shape ).getNamespace ())
442
+ .filter (namespace -> namespace .startsWith (SHAPE_NAMESPACE_PREFIX ))
443
+ .distinct ()
444
+ .sorted (Comparator .naturalOrder ())
445
+ .forEach (namespace -> writer .write (
446
+ "export * from $S;" , namespace .replaceFirst (SHAPE_NAMESPACE_PREFIX , "./" )));
447
+ fileManifest .writeFile ("models/index.ts" , writer .toString ());
448
+ }
449
+ }
395
450
}
0 commit comments