20
20
import java .util .Collection ;
21
21
import java .util .HashMap ;
22
22
import java .util .List ;
23
+ import java .util .Locale ;
23
24
import java .util .Map ;
24
25
import java .util .Set ;
25
26
import java .util .logging .Logger ;
27
+ import java .util .stream .Collectors ;
26
28
import software .amazon .smithy .build .FileManifest ;
29
+ import software .amazon .smithy .codegen .core .CodegenException ;
27
30
import software .amazon .smithy .codegen .core .Symbol ;
31
+ import software .amazon .smithy .codegen .core .SymbolDependency ;
28
32
import software .amazon .smithy .codegen .core .SymbolProvider ;
29
33
import software .amazon .smithy .codegen .core .directed .CreateContextDirective ;
30
34
import software .amazon .smithy .codegen .core .directed .CreateSymbolProviderDirective ;
35
+ import software .amazon .smithy .codegen .core .directed .CustomizeDirective ;
31
36
import software .amazon .smithy .codegen .core .directed .DirectedCodegen ;
32
37
import software .amazon .smithy .codegen .core .directed .GenerateEnumDirective ;
33
38
import software .amazon .smithy .codegen .core .directed .GenerateErrorDirective ;
34
39
import software .amazon .smithy .codegen .core .directed .GenerateServiceDirective ;
35
40
import software .amazon .smithy .codegen .core .directed .GenerateStructureDirective ;
36
41
import software .amazon .smithy .codegen .core .directed .GenerateUnionDirective ;
37
42
import software .amazon .smithy .model .Model ;
43
+ import software .amazon .smithy .model .knowledge .OperationIndex ;
38
44
import software .amazon .smithy .model .knowledge .TopDownIndex ;
39
45
import software .amazon .smithy .model .shapes .OperationShape ;
40
46
import software .amazon .smithy .model .shapes .ServiceShape ;
43
49
import software .amazon .smithy .typescript .codegen .integration .ProtocolGenerator ;
44
50
import software .amazon .smithy .typescript .codegen .integration .RuntimeClientPlugin ;
45
51
import software .amazon .smithy .typescript .codegen .integration .TypeScriptIntegration ;
52
+ import software .amazon .smithy .utils .MapUtils ;
46
53
import software .amazon .smithy .utils .SmithyUnstableApi ;
47
54
import software .amazon .smithy .waiters .WaitableTrait ;
48
55
import software .amazon .smithy .waiters .Waiter ;
@@ -52,6 +59,19 @@ final class DirectedTypeScriptCodegen implements DirectedCodegen<TypeScriptCodeg
52
59
53
60
private static final Logger LOGGER = Logger .getLogger (DirectedTypeScriptCodegen .class .getName ());
54
61
62
+ /**
63
+ * A mapping of static resource files to copy over to a new filename.
64
+ */
65
+ private static final Map <String , String > STATIC_FILE_COPIES = MapUtils .of (
66
+ "typedoc.json" , "typedoc.json" ,
67
+ "tsconfig.json" , "tsconfig.json" ,
68
+ "tsconfig.cjs.json" , "tsconfig.cjs.json" ,
69
+ "tsconfig.es.json" , "tsconfig.es.json" ,
70
+ "tsconfig.types.json" , "tsconfig.types.json"
71
+ );
72
+ private static final ShapeId VALIDATION_EXCEPTION_SHAPE =
73
+ ShapeId .fromParts ("smithy.framework" , "ValidationException" );
74
+
55
75
@ Override
56
76
public SymbolProvider createSymbolProvider (CreateSymbolProviderDirective <TypeScriptSettings > directive ) {
57
77
return new SymbolVisitor (directive .model (), directive .settings ());
@@ -89,11 +109,15 @@ public TypeScriptCodegenContext createContext(CreateContextDirective<TypeScriptS
89
109
.protocolGenerator (protocolGenerator )
90
110
.applicationProtocol (applicationProtocol )
91
111
112
+ // //TODO: fix delegator constructor
113
+ // .writerDelegator(new TypeScriptDelegator(
114
+ // directive.settings(), directive.model(),
115
+ // directive.fileManifest(), directive.symbolProvider(),
116
+ // directive.integrations())) // TODO: integrations?
117
+
92
118
//TODO: fix delegator constructor
93
- .writerDelegator (new TypeScriptDelegator (
94
- directive .settings (), directive .model (),
95
- directive .fileManifest (), directive .symbolProvider (),
96
- directive .integrations ())) // TODO: integrations?
119
+ .writerDelegator (new TypeScriptDelegator (directive .fileManifest (), directive .symbolProvider ()))
120
+
97
121
.build ();
98
122
}
99
123
@@ -340,4 +364,121 @@ public void generateEnumShape(GenerateEnumDirective<TypeScriptCodegenContext, Ty
340
364
generator .run ();
341
365
});
342
366
}
367
+
368
+ @ Override
369
+ public void customizeBeforeIntegrations (CustomizeDirective <TypeScriptCodegenContext , TypeScriptSettings > directive ) {
370
+ // Write shared / static content.
371
+ STATIC_FILE_COPIES .forEach ((from , to ) -> {
372
+ LOGGER .fine (() -> "Writing contents of `" + from + "` to `" + to + "`" );
373
+ directive .fileManifest ().writeFile (from , getClass (), to );
374
+ });
375
+
376
+ // TODO: do all of these parts below are before/after?
377
+ SymbolVisitor .writeModelIndex (directive .model (), directive .symbolProvider (), directive .fileManifest ());
378
+
379
+ // Generate the client Node and Browser configuration files. These
380
+ // files are switched between in package.json based on the targeted
381
+ // environment.
382
+ if (directive .settings ().generateClient ()) {
383
+ // For now these are only generated for clients.
384
+ // TODO: generate ssdk config
385
+ RuntimeConfigGenerator configGenerator = new RuntimeConfigGenerator (
386
+ directive .settings (),
387
+ directive .model (),
388
+ directive .symbolProvider (),
389
+ directive .context ().writerDelegator (),
390
+ directive .context ().integrations ());
391
+ for (LanguageTarget target : LanguageTarget .values ()) {
392
+ LOGGER .fine ("Generating " + target + " runtime configuration" );
393
+ configGenerator .generate (target );
394
+ }
395
+ }
396
+
397
+ // Write each custom file.
398
+ for (TypeScriptIntegration integration : directive .context ().integrations ()) {
399
+ LOGGER .finer (() -> "Calling writeAdditionalFiles on " + integration .getClass ().getCanonicalName ());
400
+ integration .writeAdditionalFiles (
401
+ directive .settings (),
402
+ directive .model (),
403
+ directive .symbolProvider (),
404
+ directive .context ().writerDelegator ()::useFileWriter );
405
+ }
406
+
407
+ // Generate index for client.
408
+ IndexGenerator .writeIndex (
409
+ directive .settings (),
410
+ directive .model (),
411
+ directive .symbolProvider (),
412
+ directive .fileManifest (),
413
+ directive .context ().integrations (),
414
+ directive .context ().protocolGenerator ());
415
+
416
+ if (directive .settings ().generateServerSdk ()) {
417
+ checkValidationSettings (directive .settings (), directive .model (), directive .service ());
418
+ // Generate index for server
419
+ IndexGenerator .writeServerIndex (
420
+ directive .settings (),
421
+ directive .model (),
422
+ directive .symbolProvider (),
423
+ directive .fileManifest ());
424
+ }
425
+
426
+ // Generate protocol tests IFF found in the model.
427
+ ProtocolGenerator protocolGenerator = directive .context ().protocolGenerator ();
428
+ if (protocolGenerator != null ) {
429
+ ShapeId protocol = protocolGenerator .getProtocol ();
430
+ ProtocolGenerator .GenerationContext context = new ProtocolGenerator .GenerationContext ();
431
+ context .setProtocolName (protocolGenerator .getName ());
432
+ context .setIntegrations (directive .context ().integrations ());
433
+ context .setModel (directive .model ());
434
+ context .setService (directive .service ());
435
+ context .setSettings (directive .settings ());
436
+ context .setSymbolProvider (directive .symbolProvider ());
437
+ String baseName = protocol .getName ().toLowerCase (Locale .US )
438
+ .replace ("-" , "_" )
439
+ .replace ("." , "_" );
440
+ String protocolTestFileName = String .format ("test/functional/%s.spec.ts" , baseName );
441
+
442
+ // TODO: what to do here?
443
+ // context.setDeferredWriter(() -> directive.context().writerDelegator().checkoutFileWriter(protocolTestFileName));
444
+
445
+ // protocolGenerator.generateProtocolTests(context);
446
+ }
447
+
448
+ }
449
+
450
+ private void checkValidationSettings (TypeScriptSettings settings , Model model , ServiceShape service ) {
451
+ if (settings .isDisableDefaultValidation ()) {
452
+ return ;
453
+ }
454
+
455
+ final OperationIndex operationIndex = OperationIndex .of (model );
456
+
457
+ List <String > unvalidatedOperations = TopDownIndex .of (model )
458
+ .getContainedOperations (service )
459
+ .stream ()
460
+ .filter (o -> operationIndex .getErrors (o , service ).stream ()
461
+ .noneMatch (e -> e .getId ().equals (VALIDATION_EXCEPTION_SHAPE )))
462
+ .map (s -> s .getId ().toString ())
463
+ .sorted ()
464
+ .collect (Collectors .toList ());
465
+
466
+ if (!unvalidatedOperations .isEmpty ()) {
467
+ throw new CodegenException (String .format ("Every operation must have the %s error attached unless %s is set "
468
+ + "to 'true' in the plugin settings. Operations without %s errors attached: %s" ,
469
+ VALIDATION_EXCEPTION_SHAPE ,
470
+ TypeScriptSettings .DISABLE_DEFAULT_VALIDATION ,
471
+ VALIDATION_EXCEPTION_SHAPE ,
472
+ unvalidatedOperations ));
473
+ }
474
+ }
475
+
476
+ @ Override
477
+ public void customizeAfterIntegrations (CustomizeDirective <TypeScriptCodegenContext , TypeScriptSettings > directive ) {
478
+ LOGGER .fine ("Generating package.json files" );
479
+ PackageJsonGenerator .writePackageJson (
480
+ directive .settings (),
481
+ directive .fileManifest (),
482
+ SymbolDependency .gatherDependencies (directive .context ().writerDelegator ().getDependencies ().stream ()));
483
+ }
343
484
}
0 commit comments