16
16
package software .amazon .smithy .typescript .codegen ;
17
17
18
18
import java .nio .file .Paths ;
19
+ import java .util .Collections ;
19
20
import java .util .Iterator ;
20
21
import java .util .List ;
21
22
import java .util .Map ;
22
- import java .util .Map .Entry ;
23
23
import java .util .TreeMap ;
24
24
import java .util .function .Consumer ;
25
- import java .util .stream .Collectors ;
26
25
import software .amazon .smithy .build .SmithyBuildException ;
26
+ import software .amazon .smithy .codegen .core .CodegenException ;
27
27
import software .amazon .smithy .codegen .core .SymbolProvider ;
28
28
import software .amazon .smithy .model .Model ;
29
29
import software .amazon .smithy .model .knowledge .ServiceIndex ;
30
30
import software .amazon .smithy .model .shapes .ServiceShape ;
31
31
import software .amazon .smithy .model .shapes .ShapeId ;
32
- import software .amazon .smithy .model .traits .Trait ;
33
32
import software .amazon .smithy .typescript .codegen .auth .AuthUtils ;
34
33
import software .amazon .smithy .typescript .codegen .auth .http .HttpAuthScheme ;
35
34
import software .amazon .smithy .typescript .codegen .auth .http .HttpAuthSchemeProviderGenerator ;
@@ -208,59 +207,60 @@ private void generateHttpAuthSchemeConfig(
208
207
TypeScriptWriter writer ,
209
208
LanguageTarget target
210
209
) {
210
+ // feat(experimentalIdentityAndAuth): write the default imported HttpAuthSchemeProvider
211
+ if (target .equals (LanguageTarget .SHARED )) {
212
+ configs .put ("httpAuthSchemeProvider" , w -> {
213
+ String providerName = "default" + service .toShapeId ().getName () + "HttpAuthSchemeProvider" ;
214
+ w .addRelativeImport (providerName , null , Paths .get ("." , CodegenUtils .SOURCE_FOLDER ,
215
+ HttpAuthSchemeProviderGenerator .HTTP_AUTH_FOLDER ,
216
+ HttpAuthSchemeProviderGenerator .HTTP_AUTH_SCHEME_RESOLVER_MODULE ));
217
+ w .write (providerName );
218
+ });
219
+ }
220
+
211
221
// feat(experimentalIdentityAndAuth): gather HttpAuthSchemes to generate
212
- SupportedHttpAuthSchemesIndex index = new SupportedHttpAuthSchemesIndex (integrations );
222
+ SupportedHttpAuthSchemesIndex authIndex = new SupportedHttpAuthSchemesIndex (integrations );
213
223
ServiceIndex serviceIndex = ServiceIndex .of (model );
214
- Map <ShapeId , Trait > authSchemeTraits = serviceIndex .getAuthSchemes (service );
215
- Map <ShapeId , HttpAuthScheme > authSchemes = authSchemeTraits .entrySet ().stream ()
216
- .filter (entry -> index .getHttpAuthScheme (entry .getKey ()) != null )
217
- .collect (Collectors .toMap (
218
- entry -> entry .getKey (),
219
- entry -> index .getHttpAuthScheme (entry .getKey ())));
220
- // feat(experimentalIdentityAndAuth): can be removed after changing to NO_AUTH_AWARE schemes
221
- // The default set of HttpAuthSchemes is @smithy.api#noAuth on the shared runtime config
222
- authSchemes .put (AuthUtils .NO_AUTH_ID , index .getHttpAuthScheme (AuthUtils .NO_AUTH_ID ));
223
- boolean shouldGenerateHttpAuthSchemes = index .getSupportedHttpAuthSchemes ().values ().stream ().anyMatch (value ->
224
- // If either an default identity or signer is configured for the target, generate auth schemes
225
- value .getDefaultIdentityProviders ().containsKey (target ) || value .getDefaultSigners ().containsKey (target ));
226
- if (!shouldGenerateHttpAuthSchemes ) {
224
+ Map <ShapeId , HttpAuthScheme > allEffectiveHttpAuthSchemes =
225
+ AuthUtils .getAllEffectiveNoAuthAwareAuthSchemes (service , serviceIndex , authIndex );
226
+ List <HttpAuthSchemeTarget > targetAuthSchemes = getHttpAuthSchemeTargets (target , allEffectiveHttpAuthSchemes );
227
+
228
+ // Generate only if the "inherited" target is different than the current target
229
+ List <HttpAuthSchemeTarget > inheritedAuthSchemes = Collections .emptyList ();
230
+ // Always generated the SHARED target
231
+ if (target .equals (LanguageTarget .SHARED )) {
232
+ // no-op
233
+ // NODE and BROWSER inherit from SHARED
234
+ } else if (target .equals (LanguageTarget .NODE ) || target .equals (LanguageTarget .BROWSER )) {
235
+ inheritedAuthSchemes = getHttpAuthSchemeTargets (LanguageTarget .SHARED , allEffectiveHttpAuthSchemes );
236
+ // REACT_NATIVE inherits from BROWSER
237
+ } else if (target .equals (LanguageTarget .REACT_NATIVE )) {
238
+ inheritedAuthSchemes = getHttpAuthSchemeTargets (LanguageTarget .BROWSER , allEffectiveHttpAuthSchemes );
239
+ } else {
240
+ throw new CodegenException ("Unhandled Language Target: " + target );
241
+ }
242
+
243
+ // If target and inherited auth schemes are equal, then don't generate target auth schemes.
244
+ if (targetAuthSchemes .equals (inheritedAuthSchemes )) {
227
245
return ;
228
246
}
229
- // feat(experimentalIdentityAndAuth): write the default imported HttpAuthSchemeProvider
230
- configs .put ("httpAuthSchemeProvider" , w -> {
231
- String providerName = "default" + service .toShapeId ().getName () + "HttpAuthSchemeProvider" ;
232
- w .addRelativeImport (providerName , null , Paths .get ("." , CodegenUtils .SOURCE_FOLDER ,
233
- HttpAuthSchemeProviderGenerator .HTTP_AUTH_FOLDER ,
234
- HttpAuthSchemeProviderGenerator .HTTP_AUTH_SCHEME_RESOLVER_MODULE ));
235
- w .write (providerName );
236
- });
247
+
237
248
// feat(experimentalIdentityAndAuth): write the default IdentityProviderConfiguration with configured
238
249
// HttpAuthSchemes
239
250
configs .put ("httpAuthSchemes" , w -> {
240
- w .addDependency (TypeScriptDependency .EXPERIMENTAL_IDENTITY_AND_AUTH );
241
- w .addImport ("DefaultIdentityProviderConfiguration" , null ,
242
- TypeScriptDependency .EXPERIMENTAL_IDENTITY_AND_AUTH );
243
- w .openBlock ("new DefaultIdentityProviderConfiguration([" , "])" , () -> {
244
- Iterator <Entry <ShapeId , HttpAuthScheme >> iter = authSchemes .entrySet ().iterator ();
251
+ w .openBlock ("[" , "]" , () -> {
252
+ Iterator <HttpAuthSchemeTarget > iter = targetAuthSchemes .iterator ();
245
253
while (iter .hasNext ()) {
246
- Entry <ShapeId , HttpAuthScheme > entry = iter .next ();
247
- // Default IdentityProvider or HttpSigner, otherwise write {@code never} to force a TypeScript
248
- // compilation failure.
249
- Consumer <TypeScriptWriter > defaultIdentityProvider = entry .getValue ()
250
- .getDefaultIdentityProviders ()
251
- .getOrDefault (target , AuthUtils .DEFAULT_NEVER_WRITER );
252
- Consumer <TypeScriptWriter > defaultSigner = entry .getValue ()
253
- .getDefaultSigners ()
254
- .getOrDefault (target , AuthUtils .DEFAULT_NEVER_WRITER );
254
+ HttpAuthSchemeTarget entry = iter .next ();
255
255
w .write ("""
256
256
{
257
257
schemeId: $S,
258
258
identityProvider: $C,
259
259
signer: $C,
260
260
}""" ,
261
- entry .getKey (),
262
- defaultIdentityProvider ,
263
- defaultSigner );
261
+ entry .httpAuthScheme . getSchemeId (),
262
+ entry . identityProvider ,
263
+ entry . signer );
264
264
if (iter .hasNext ()) {
265
265
w .writeInline (", " );
266
266
}
@@ -269,6 +269,118 @@ private void generateHttpAuthSchemeConfig(
269
269
});
270
270
}
271
271
272
+ private static class HttpAuthSchemeTarget {
273
+ public HttpAuthScheme httpAuthScheme ;
274
+ public Consumer <TypeScriptWriter > identityProvider ;
275
+ public Consumer <TypeScriptWriter > signer ;
276
+
277
+ HttpAuthSchemeTarget (
278
+ HttpAuthScheme httpAuthScheme ,
279
+ Consumer <TypeScriptWriter > identityProvider ,
280
+ Consumer <TypeScriptWriter > signer
281
+ ) {
282
+ this .httpAuthScheme = httpAuthScheme ;
283
+ this .identityProvider = identityProvider ;
284
+ this .signer = signer ;
285
+ }
286
+
287
+ @ Override
288
+ public boolean equals (Object other ) {
289
+ if (!(other instanceof HttpAuthSchemeTarget )) {
290
+ return false ;
291
+ }
292
+ HttpAuthSchemeTarget o = (HttpAuthSchemeTarget ) other ;
293
+ return httpAuthScheme .equals (o .httpAuthScheme )
294
+ && identityProvider .equals (o .identityProvider )
295
+ && signer .equals (o .signer );
296
+ }
297
+
298
+ @ Override
299
+ public int hashCode () {
300
+ return super .hashCode ();
301
+ }
302
+ }
303
+
304
+ private List <HttpAuthSchemeTarget > getHttpAuthSchemeTargets (
305
+ LanguageTarget target ,
306
+ Map <ShapeId , HttpAuthScheme > httpAuthSchemes
307
+ ) {
308
+ return getPartialHttpAuthSchemeTargets (target , httpAuthSchemes )
309
+ .values ()
310
+ .stream ()
311
+ .filter (httpAuthSchemeTarget ->
312
+ httpAuthSchemeTarget .identityProvider != null && httpAuthSchemeTarget .signer != null )
313
+ .toList ();
314
+ }
315
+
316
+ private Map <ShapeId , HttpAuthSchemeTarget > getPartialHttpAuthSchemeTargets (
317
+ LanguageTarget target ,
318
+ Map <ShapeId , HttpAuthScheme > httpAuthSchemes
319
+ ) {
320
+ if (target .equals (LanguageTarget .SHARED )) {
321
+ Map <ShapeId , HttpAuthSchemeTarget > httpAuthSchemeTargets = new TreeMap <>();
322
+ for (var httpAuthScheme : httpAuthSchemes .values ()) {
323
+ if (httpAuthScheme == null ) {
324
+ continue ;
325
+ }
326
+ var identityProvider = httpAuthScheme .getDefaultIdentityProviders ().get (target );
327
+ var signer = httpAuthScheme .getDefaultSigners ().get (target );
328
+ httpAuthSchemeTargets .put (httpAuthScheme .getSchemeId (),
329
+ new HttpAuthSchemeTarget (httpAuthScheme , identityProvider , signer ));
330
+ }
331
+ return httpAuthSchemeTargets ;
332
+ }
333
+ if (target .equals (LanguageTarget .NODE ) || target .equals (LanguageTarget .BROWSER )) {
334
+ var partialSharedHttpAuthSchemeTargets =
335
+ getPartialHttpAuthSchemeTargets (LanguageTarget .SHARED , httpAuthSchemes );
336
+ for (var httpAuthScheme : httpAuthSchemes .values ()) {
337
+ if (httpAuthScheme == null ) {
338
+ continue ;
339
+ }
340
+ var identityProvider = httpAuthScheme .getDefaultIdentityProviders ().get (target );
341
+ var signer = httpAuthScheme .getDefaultSigners ().get (target );
342
+ var sharedEntry = partialSharedHttpAuthSchemeTargets .get (httpAuthScheme .getSchemeId ());
343
+ if (sharedEntry == null ) {
344
+ partialSharedHttpAuthSchemeTargets .put (httpAuthScheme .getSchemeId (),
345
+ new HttpAuthSchemeTarget (httpAuthScheme , identityProvider , signer ));
346
+ continue ;
347
+ }
348
+ if (identityProvider != null ) {
349
+ sharedEntry .identityProvider = identityProvider ;
350
+ }
351
+ if (signer != null ) {
352
+ sharedEntry .signer = signer ;
353
+ }
354
+ }
355
+ return partialSharedHttpAuthSchemeTargets ;
356
+ }
357
+ if (target .equals (LanguageTarget .REACT_NATIVE )) {
358
+ var partialBrowserHttpAuthSchemeTargets =
359
+ getPartialHttpAuthSchemeTargets (LanguageTarget .BROWSER , httpAuthSchemes );
360
+ for (var httpAuthScheme : httpAuthSchemes .values ()) {
361
+ if (httpAuthScheme == null ) {
362
+ continue ;
363
+ }
364
+ var identityProvider = httpAuthScheme .getDefaultIdentityProviders ().get (target );
365
+ var signer = httpAuthScheme .getDefaultSigners ().get (target );
366
+ var sharedEntry = partialBrowserHttpAuthSchemeTargets .get (httpAuthScheme .getSchemeId ());
367
+ if (sharedEntry == null ) {
368
+ partialBrowserHttpAuthSchemeTargets .put (httpAuthScheme .getSchemeId (),
369
+ new HttpAuthSchemeTarget (httpAuthScheme , identityProvider , signer ));
370
+ continue ;
371
+ }
372
+ if (identityProvider != null ) {
373
+ sharedEntry .identityProvider = identityProvider ;
374
+ }
375
+ if (signer != null ) {
376
+ sharedEntry .signer = signer ;
377
+ }
378
+ }
379
+ return partialBrowserHttpAuthSchemeTargets ;
380
+ }
381
+ throw new CodegenException ("Unsupported Language Target: " + target );
382
+ }
383
+
272
384
private Map <String , Consumer <TypeScriptWriter >> getDefaultRuntimeConfigs (LanguageTarget target ) {
273
385
switch (target ) {
274
386
case NODE :
0 commit comments