15
15
16
16
package software .amazon .smithy .typescript .codegen ;
17
17
18
- import java .util .HashMap ;
18
+ import java .util .Collection ;
19
19
import java .util .List ;
20
- import java .util .Map ;
21
20
import java .util .Objects ;
22
21
import software .amazon .smithy .build .FileManifest ;
23
22
import software .amazon .smithy .build .PluginContext ;
24
23
import software .amazon .smithy .codegen .core .Symbol ;
24
+ import software .amazon .smithy .codegen .core .SymbolDependency ;
25
25
import software .amazon .smithy .codegen .core .SymbolProvider ;
26
26
import software .amazon .smithy .model .Model ;
27
+ import software .amazon .smithy .model .knowledge .NeighborProviderIndex ;
27
28
import software .amazon .smithy .model .knowledge .OperationIndex ;
28
29
import software .amazon .smithy .model .knowledge .TopDownIndex ;
30
+ import software .amazon .smithy .model .neighbor .Walker ;
29
31
import software .amazon .smithy .model .shapes .MemberShape ;
30
32
import software .amazon .smithy .model .shapes .OperationShape ;
31
33
import software .amazon .smithy .model .shapes .ServiceShape ;
@@ -46,26 +48,53 @@ class CodegenVisitor extends ShapeVisitor.Default<Void> {
46
48
private final FileManifest fileManifest ;
47
49
private final SymbolProvider symbolProvider ;
48
50
private final ShapeIndex nonTraits ;
49
- private final Map < String , TypeScriptWriter > writers = new HashMap <>() ;
51
+ private final CodeWriterDelegator < TypeScriptWriter > writers ;
50
52
51
53
CodegenVisitor (PluginContext context ) {
52
54
settings = TypeScriptSettings .from (context .getSettings ());
53
55
nonTraits = context .getNonTraitShapes ();
54
56
model = context .getModel ();
55
57
service = settings .getService (model );
56
58
fileManifest = context .getFileManifest ();
57
- symbolProvider = TypeScriptCodegenPlugin .createSymbolProvider (model );
59
+ symbolProvider = SymbolProvider .cache (TypeScriptCodegenPlugin .createSymbolProvider (model ));
60
+
61
+ Walker walker = new Walker (model .getKnowledge (NeighborProviderIndex .class ).getProvider ());
62
+ writers = CodeWriterDelegator .<TypeScriptWriter >builder ()
63
+ .model (model )
64
+ .symbolProvider (symbolProvider )
65
+ .fileManifest (fileManifest )
66
+ .factory ((shape , symbol ) -> new TypeScriptWriter (symbol .getNamespace ()))
67
+ .beforeWrite ((filename , writer , shapes ) -> {
68
+ // Add dependencies of the shape and any references it has by
69
+ // walking the shape's neighbors.
70
+ for (Shape shape : shapes ) {
71
+ writer .addImport (symbolProvider .toSymbol (shape ));
72
+ walker .walkShapes (shape ).forEach (neighbor -> {
73
+ writer .addImport (symbolProvider .toSymbol (neighbor ));
74
+ });
75
+ }
76
+ })
77
+ .build ();
58
78
}
59
79
60
80
void execute () {
61
81
// Write shared / static content.
62
82
fileManifest .writeFile ("shared/shapeTypes.ts" , getClass (), "shapeTypes.ts" );
83
+ fileManifest .writeFile ("tsconfig.json" , getClass (), "tsconfig.json" );
63
84
64
85
// Generate models.
65
86
nonTraits .shapes ().sorted ().forEach (shape -> shape .accept (this ));
66
87
67
88
// Write each pending writer.
68
- writers .forEach ((filename , writer ) -> fileManifest .writeFile (filename , writer .toString ()));
89
+ // writers.forEach((filename, writer) -> fileManifest.writeFile(filename, writer.toString()));
90
+ writers .writeFiles ();
91
+
92
+ // Write the package.json file, including all symbol dependencies.
93
+ PackageJsonGenerator .writePackageJson (settings , fileManifest , SymbolDependency .gatherDependencies (
94
+ nonTraits .shapes ()
95
+ .map (symbolProvider ::toSymbol )
96
+ .map (Symbol ::getDependencies )
97
+ .flatMap (Collection ::stream )));
69
98
}
70
99
71
100
@ Override
@@ -150,8 +179,7 @@ public Void structureShape(StructureShape shape) {
150
179
*/
151
180
private void renderNonErrorStructure (StructureShape shape ) {
152
181
Symbol symbol = symbolProvider .toSymbol (shape );
153
- TypeScriptWriter writer = getWriter (symbol .getDefinitionFile (), symbol .getNamespace ());
154
- writer .addImport ("SmithyStructure" , "$SmithyStructure" , "./shared/shapeTypes" );
182
+ TypeScriptWriter writer = writers .createWriter (shape );
155
183
writer .openBlock ("export class $L implements $$SmithyStructure {" , symbol .getName ());
156
184
writer .write ("readonly $$id = $S;" , shape .getId ());
157
185
@@ -222,8 +250,7 @@ private void renderNonErrorStructure(StructureShape shape) {
222
250
private void renderErrorStructure (StructureShape shape ) {
223
251
ErrorTrait errorTrait = shape .getTrait (ErrorTrait .class ).orElseThrow (IllegalStateException ::new );
224
252
Symbol symbol = symbolProvider .toSymbol (shape );
225
- TypeScriptWriter writer = getWriter (symbol .getDefinitionFile (), symbol .getNamespace ());
226
- writer .addImport ("SmithyException" , "$SmithyException" , "./shared/shapeTypes" );
253
+ TypeScriptWriter writer = writers .createWriter (shape );
227
254
writer .openBlock ("export class $L extends $$SmithyException {" , symbol .getName ());
228
255
229
256
// Write properties.
@@ -321,8 +348,7 @@ private void renderErrorStructure(StructureShape shape) {
321
348
public Void unionShape (UnionShape shape ) {
322
349
Symbol symbol = symbolProvider .toSymbol (shape );
323
350
324
- TypeScriptWriter writer = getWriter (symbol .getDefinitionFile (), symbol .getNamespace ());
325
- writer .addImport ("TaggedUnion" , "./shared/shapeTypes" );
351
+ TypeScriptWriter writer = writers .createWriter (shape );
326
352
writer .openBlock ("export type $L = TaggedUnion<{" , symbol .getName ());
327
353
StructuredMemberWriter config = new StructuredMemberWriter (
328
354
model , symbolProvider , shape .getAllMembers ().values ());
@@ -394,17 +420,25 @@ public Void unionShape(UnionShape shape) {
394
420
*/
395
421
@ Override
396
422
public Void stringShape (StringShape shape ) {
397
- shape .getTrait (EnumTrait .class ).filter ( EnumTrait :: hasNames ). ifPresent (trait -> {
423
+ shape .getTrait (EnumTrait .class ).ifPresent (trait -> {
398
424
Symbol symbol = symbolProvider .toSymbol (shape );
399
- TypeScriptWriter writer = getWriter (symbol .getDefinitionFile (), symbol .getNamespace ());
400
- writer .openBlock ("export enum $L {" , symbol .getName ());
401
- trait .getValues ().forEach ((value , body ) -> body .getName ().ifPresent (name -> {
402
- body .getDocumentation ().ifPresent (writer ::writeDocs );
403
- writer .write ("$L = $S," , TypeScriptUtils .sanitizePropertyName (name ), value );
404
- }));
405
- writer .closeBlock ("};" );
425
+ TypeScriptWriter writer = writers .createWriter (shape );
426
+ // Unnamed enums generate a union of string literals.
427
+ if (!trait .hasNames ()) {
428
+ writer .write ("export type $L = $L" ,
429
+ symbol .getName (), TypeScriptUtils .getEnumVariants (trait .getValues ().keySet ()));
430
+ } else {
431
+ // Named enums generate an actual enum type.
432
+ writer .openBlock ("export enum $L {" , symbol .getName ());
433
+ trait .getValues ().forEach ((value , body ) -> body .getName ().ifPresent (name -> {
434
+ body .getDocumentation ().ifPresent (writer ::writeDocs );
435
+ writer .write ("$L = $S," , TypeScriptUtils .sanitizePropertyName (name ), value );
436
+ }));
437
+ writer .closeBlock ("};" );
438
+ }
406
439
});
407
440
441
+ // Normal string shapes don't generate any code on their own.
408
442
return null ;
409
443
}
410
444
@@ -426,8 +460,7 @@ public Void serviceShape(ServiceShape shape) {
426
460
427
461
// TODO: This does not need to be an exported type. Move this to the command.
428
462
private void renderErrorUnion (OperationIndex operationIndex , OperationShape operation ) {
429
- Symbol symbol = symbolProvider .toSymbol (operation );
430
- TypeScriptWriter writer = getWriter (symbol .getDefinitionFile (), symbol .getNamespace ());
463
+ TypeScriptWriter writer = writers .createWriter (operation );
431
464
List <StructureShape > errors = operationIndex .getErrors (operation );
432
465
433
466
if (errors .size () == 0 ) {
@@ -442,16 +475,4 @@ private void renderErrorUnion(OperationIndex operationIndex, OperationShape oper
442
475
writer .write (" | $T$L" , target , endOfLine );
443
476
}
444
477
}
445
-
446
- private TypeScriptWriter getWriter (String filename , String moduleName ) {
447
- boolean needsNewline = writers .containsKey (filename );
448
- TypeScriptWriter writer = writers .computeIfAbsent (filename , f -> new TypeScriptWriter (moduleName ));
449
-
450
- // Add newlines between types in the same file.
451
- if (needsNewline ) {
452
- writer .write ("" );
453
- }
454
-
455
- return writer ;
456
- }
457
478
}
0 commit comments