@@ -67,7 +67,6 @@ import {
67
67
SdkServiceMethod ,
68
68
SdkType ,
69
69
SdkUnionType ,
70
- UsageFlags ,
71
70
createSdkContext ,
72
71
getAllModels ,
73
72
getClientType ,
@@ -107,10 +106,7 @@ import {
107
106
getHeaderFieldName ,
108
107
getPathParamName ,
109
108
getQueryParamName ,
110
- isBody ,
111
- isBodyRoot ,
112
109
isHeader ,
113
- isMultipartBodyProperty ,
114
110
isPathParam ,
115
111
isQueryParam ,
116
112
} from "@typespec/http" ;
@@ -455,6 +451,7 @@ export class CodeModelBuilder {
455
451
schema instanceof ConstantSchema
456
452
) {
457
453
const schemaUsage : SchemaContext [ ] | undefined = schema . usage ;
454
+
458
455
// Public override Internal
459
456
if ( schemaUsage ?. includes ( SchemaContext . Public ) ) {
460
457
const index = schemaUsage . indexOf ( SchemaContext . Internal ) ;
@@ -463,11 +460,17 @@ export class CodeModelBuilder {
463
460
}
464
461
}
465
462
466
- // Internal on Anonymous
467
- if ( schemaUsage ?. includes ( SchemaContext . Anonymous ) ) {
468
- const index = schemaUsage . indexOf ( SchemaContext . Internal ) ;
469
- if ( index < 0 ) {
470
- schemaUsage . push ( SchemaContext . Internal ) ;
463
+ // Internal on PublicSpread, but Public takes precedence
464
+ if ( schemaUsage ?. includes ( SchemaContext . PublicSpread ) ) {
465
+ // remove PublicSpread as it now served its purpose
466
+ schemaUsage . splice ( schemaUsage . indexOf ( SchemaContext . PublicSpread ) , 1 ) ;
467
+
468
+ // Public would override PublicSpread, hence do nothing if this schema is Public
469
+ if ( ! schemaUsage ?. includes ( SchemaContext . Public ) ) {
470
+ // set the model as Internal, so that it is not exposed to user
471
+ if ( ! schemaUsage . includes ( SchemaContext . Internal ) ) {
472
+ schemaUsage . push ( SchemaContext . Internal ) ;
473
+ }
471
474
}
472
475
}
473
476
}
@@ -1302,119 +1305,138 @@ export class CodeModelBuilder {
1302
1305
} ) ;
1303
1306
op . addParameter ( parameter ) ;
1304
1307
1308
+ const jsonMergePatch = operationIsJsonMergePatch ( sdkHttpOperation ) ;
1309
+
1310
+ const schemaIsPublicBeforeProcess =
1311
+ schema instanceof ObjectSchema && ( schema as SchemaUsage ) . usage ?. includes ( SchemaContext . Public ) ;
1312
+
1305
1313
this . trackSchemaUsage ( schema , { usage : [ SchemaContext . Input ] } ) ;
1306
1314
1307
1315
if ( op . convenienceApi ) {
1308
1316
// model/schema does not need to be Public or Internal, if it is not to be used in convenience API
1309
1317
this . trackSchemaUsage ( schema , { usage : [ op . internalApi ? SchemaContext . Internal : SchemaContext . Public ] } ) ;
1310
1318
}
1311
1319
1312
- if ( operationIsJsonMergePatch ( sdkHttpOperation ) ) {
1320
+ if ( jsonMergePatch ) {
1313
1321
this . trackSchemaUsage ( schema , { usage : [ SchemaContext . JsonMergePatch ] } ) ;
1314
1322
}
1315
1323
if ( op . convenienceApi && operationIsMultipart ( sdkHttpOperation ) ) {
1316
1324
this . trackSchemaUsage ( schema , { serializationFormats : [ KnownMediaType . Multipart ] } ) ;
1317
1325
}
1318
1326
1319
- // Implicit body parameter would have usage flag: UsageFlags.Spread, for this case we need to do body parameter flatten
1320
- const bodyParameterFlatten = sdkType . kind === "model" && sdkType . usage & UsageFlags . Spread && ! this . isArm ( ) ;
1321
-
1322
- if ( schema instanceof ObjectSchema && bodyParameterFlatten ) {
1323
- // flatten body parameter
1324
- const parameters = sdkHttpOperation . parameters ;
1325
- const bodyParameter = sdkHttpOperation . bodyParam ;
1326
- // name the schema for documentation
1327
- schema . language . default . name = pascalCase ( op . language . default . name ) + "Request" ;
1328
-
1329
- if ( ! parameter . language . default . name ) {
1330
- // name the parameter for documentation
1331
- parameter . language . default . name = "request" ;
1332
- }
1327
+ if ( op . convenienceApi ) {
1328
+ // Explicit body parameter @body or @bodyRoot would result to the existance of rawHttpOperation.parameters.body.property
1329
+ // Implicit body parameter would result to rawHttpOperation.parameters.body.property be undefined
1330
+ // see https://typespec.io/docs/libraries/http/cheat-sheet#data-types
1331
+ const bodyParameterFlatten =
1332
+ schema instanceof ObjectSchema &&
1333
+ sdkType . kind === "model" &&
1334
+ ! rawHttpOperation . parameters . body ?. property &&
1335
+ ! this . isArm ( ) ;
1336
+
1337
+ if ( schema instanceof ObjectSchema && bodyParameterFlatten ) {
1338
+ // flatten body parameter
1339
+ const parameters = sdkHttpOperation . parameters ;
1340
+ const bodyParameter = sdkHttpOperation . bodyParam ;
1341
+
1342
+ if ( ! parameter . language . default . name ) {
1343
+ // name the parameter for documentation
1344
+ parameter . language . default . name = "request" ;
1345
+ }
1333
1346
1334
- if ( operationIsJsonMergePatch ( sdkHttpOperation ) ) {
1335
- // skip model flatten, if "application/merge-patch+json"
1336
- schema . language . default . name = pascalCase ( op . language . default . name ) + "PatchRequest" ;
1337
- return ;
1338
- }
1347
+ if ( jsonMergePatch ) {
1348
+ // skip model flatten, if "application/merge-patch+json"
1349
+ if ( sdkType . isGeneratedName ) {
1350
+ schema . language . default . name = pascalCase ( op . language . default . name ) + "PatchRequest" ;
1351
+ }
1352
+ return ;
1353
+ }
1339
1354
1340
- this . trackSchemaUsage ( schema , { usage : [ SchemaContext . Anonymous ] } ) ;
1355
+ const schemaUsage = ( schema as SchemaUsage ) . usage ;
1356
+ if ( ! schemaIsPublicBeforeProcess && schemaUsage ?. includes ( SchemaContext . Public ) ) {
1357
+ // Public added in this op, change it to PublicSpread
1358
+ // This means that if this op would originally add Public to this schema, it adds PublicSpread instead
1359
+ schemaUsage ?. splice ( schemaUsage ?. indexOf ( SchemaContext . Public ) , 1 ) ;
1360
+ this . trackSchemaUsage ( schema , { usage : [ SchemaContext . PublicSpread ] } ) ;
1361
+ }
1341
1362
1342
- if ( op . convenienceApi && op . parameters ) {
1343
- op . convenienceApi . requests = [ ] ;
1344
- const request = new Request ( {
1345
- protocol : op . requests ! [ 0 ] . protocol ,
1346
- } ) ;
1347
- request . parameters = [ ] ;
1348
- op . convenienceApi . requests . push ( request ) ;
1363
+ if ( op . convenienceApi && op . parameters ) {
1364
+ op . convenienceApi . requests = [ ] ;
1365
+ const request = new Request ( {
1366
+ protocol : op . requests ! [ 0 ] . protocol ,
1367
+ } ) ;
1368
+ request . parameters = [ ] ;
1369
+ op . convenienceApi . requests . push ( request ) ;
1349
1370
1350
- // header/query/path params
1351
- for ( const opParameter of parameters ) {
1352
- this . addParameterOrBodyPropertyToCodeModelRequest ( opParameter , op , request , schema , parameter ) ;
1353
- }
1354
- // body param
1355
- if ( bodyParameter ) {
1356
- if ( bodyParameter . type . kind === "model" ) {
1357
- for ( const bodyProperty of bodyParameter . type . properties ) {
1358
- if ( bodyProperty . kind === "property" ) {
1359
- this . addParameterOrBodyPropertyToCodeModelRequest ( bodyProperty , op , request , schema , parameter ) ;
1371
+ // header/query/path params
1372
+ for ( const opParameter of parameters ) {
1373
+ this . addParameterOrBodyPropertyToCodeModelRequest ( opParameter , op , request , schema , parameter ) ;
1374
+ }
1375
+ // body param
1376
+ if ( bodyParameter ) {
1377
+ if ( bodyParameter . type . kind === "model" ) {
1378
+ for ( const bodyProperty of bodyParameter . type . properties ) {
1379
+ if ( bodyProperty . kind === "property" ) {
1380
+ this . addParameterOrBodyPropertyToCodeModelRequest ( bodyProperty , op , request , schema , parameter ) ;
1381
+ }
1360
1382
}
1361
1383
}
1362
1384
}
1363
- }
1364
- request . signatureParameters = request . parameters ;
1365
-
1366
- if ( request . signatureParameters . length > 6 ) {
1367
- // create an option bag
1368
- const name = op . language . default . name + "Options" ;
1369
- const namespace = getNamespace ( rawHttpOperation . operation ) ;
1370
- // option bag schema
1371
- const optionBagSchema = this . codeModel . schemas . add (
1372
- new GroupSchema ( name , `Options for ${ op . language . default . name } API` , {
1373
- language : {
1374
- default : {
1375
- namespace : namespace ,
1376
- } ,
1377
- java : {
1378
- namespace : this . getJavaNamespace ( namespace ) ,
1385
+ request . signatureParameters = request . parameters ;
1386
+
1387
+ if ( request . signatureParameters . length > 6 ) {
1388
+ // create an option bag
1389
+ const name = op . language . default . name + "Options" ;
1390
+ const namespace = getNamespace ( rawHttpOperation . operation ) ;
1391
+ // option bag schema
1392
+ const optionBagSchema = this . codeModel . schemas . add (
1393
+ new GroupSchema ( name , `Options for ${ op . language . default . name } API` , {
1394
+ language : {
1395
+ default : {
1396
+ namespace : namespace ,
1397
+ } ,
1398
+ java : {
1399
+ namespace : this . getJavaNamespace ( namespace ) ,
1400
+ } ,
1379
1401
} ,
1380
- } ,
1381
- } ) ,
1382
- ) ;
1383
- request . parameters . forEach ( ( it ) => {
1384
- optionBagSchema . add (
1385
- new GroupProperty ( it . language . default . name , it . language . default . description , it . schema , {
1386
- originalParameter : [ it ] ,
1387
- summary : it . summary ,
1388
- required : it . required ,
1389
- nullable : it . nullable ,
1390
- readOnly : false ,
1391
- serializedName : it . language . default . serializedName ,
1392
1402
} ) ,
1393
1403
) ;
1394
- } ) ;
1395
-
1396
- this . trackSchemaUsage ( optionBagSchema , { usage : [ SchemaContext . Input ] } ) ;
1397
- if ( op . convenienceApi ) {
1398
- this . trackSchemaUsage ( optionBagSchema , {
1399
- usage : [ op . internalApi ? SchemaContext . Internal : SchemaContext . Public ] ,
1404
+ request . parameters . forEach ( ( it ) => {
1405
+ optionBagSchema . add (
1406
+ new GroupProperty ( it . language . default . name , it . language . default . description , it . schema , {
1407
+ originalParameter : [ it ] ,
1408
+ summary : it . summary ,
1409
+ required : it . required ,
1410
+ nullable : it . nullable ,
1411
+ readOnly : false ,
1412
+ serializedName : it . language . default . serializedName ,
1413
+ } ) ,
1414
+ ) ;
1400
1415
} ) ;
1401
- }
1402
1416
1403
- // option bag parameter
1404
- const optionBagParameter = new Parameter (
1405
- "options" ,
1406
- optionBagSchema . language . default . description ,
1407
- optionBagSchema ,
1408
- {
1409
- implementation : ImplementationLocation . Method ,
1410
- required : true ,
1411
- nullable : false ,
1412
- } ,
1413
- ) ;
1417
+ this . trackSchemaUsage ( optionBagSchema , { usage : [ SchemaContext . Input ] } ) ;
1418
+ if ( op . convenienceApi ) {
1419
+ this . trackSchemaUsage ( optionBagSchema , {
1420
+ usage : [ op . internalApi ? SchemaContext . Internal : SchemaContext . Public ] ,
1421
+ } ) ;
1422
+ }
1423
+
1424
+ // option bag parameter
1425
+ const optionBagParameter = new Parameter (
1426
+ "options" ,
1427
+ optionBagSchema . language . default . description ,
1428
+ optionBagSchema ,
1429
+ {
1430
+ implementation : ImplementationLocation . Method ,
1431
+ required : true ,
1432
+ nullable : false ,
1433
+ } ,
1434
+ ) ;
1414
1435
1415
- request . signatureParameters = [ optionBagParameter ] ;
1416
- request . parameters . forEach ( ( it ) => ( it . groupedBy = optionBagParameter ) ) ;
1417
- request . parameters . push ( optionBagParameter ) ;
1436
+ request . signatureParameters = [ optionBagParameter ] ;
1437
+ request . parameters . forEach ( ( it ) => ( it . groupedBy = optionBagParameter ) ) ;
1438
+ request . parameters . push ( optionBagParameter ) ;
1439
+ }
1418
1440
}
1419
1441
}
1420
1442
}
@@ -2229,24 +2251,6 @@ export class CodeModelBuilder {
2229
2251
}
2230
2252
}
2231
2253
2232
- private getParameterLocation ( target : ModelProperty ) : ParameterLocation | "BodyProperty" {
2233
- if ( isHeader ( this . program , target ) ) {
2234
- return ParameterLocation . Header ;
2235
- } else if ( isQueryParam ( this . program , target ) ) {
2236
- return ParameterLocation . Query ;
2237
- } else if ( isPathParam ( this . program , target ) ) {
2238
- return ParameterLocation . Path ;
2239
- } else if (
2240
- isBody ( this . program , target ) ||
2241
- isBodyRoot ( this . program , target ) ||
2242
- isMultipartBodyProperty ( this . program , target )
2243
- ) {
2244
- return ParameterLocation . Body ;
2245
- } else {
2246
- return "BodyProperty" ;
2247
- }
2248
- }
2249
-
2250
2254
private isReadOnly ( target : SdkModelPropertyType ) : boolean {
2251
2255
const segment = target . __raw ? getSegment ( this . program , target . __raw ) !== undefined : false ;
2252
2256
if ( segment ) {
@@ -2516,10 +2520,21 @@ export class CodeModelBuilder {
2516
2520
} ;
2517
2521
2518
2522
// Exclude context that not to be propagated
2523
+ const updatedSchemaUsage = ( schema as SchemaUsage ) . usage ?. filter (
2524
+ ( it ) => it !== SchemaContext . Paged && it !== SchemaContext . PublicSpread ,
2525
+ ) ;
2526
+ const indexSpread = ( schema as SchemaUsage ) . usage ?. indexOf ( SchemaContext . PublicSpread ) ;
2527
+ if (
2528
+ updatedSchemaUsage &&
2529
+ indexSpread &&
2530
+ indexSpread >= 0 &&
2531
+ ! ( schema as SchemaUsage ) . usage ?. includes ( SchemaContext . Public )
2532
+ ) {
2533
+ // Propagate Public, if schema is PublicSpread
2534
+ updatedSchemaUsage . push ( SchemaContext . Public ) ;
2535
+ }
2519
2536
const schemaUsage = {
2520
- usage : ( schema as SchemaUsage ) . usage ?. filter (
2521
- ( it ) => it !== SchemaContext . Paged && it !== SchemaContext . Anonymous ,
2522
- ) ,
2537
+ usage : updatedSchemaUsage ,
2523
2538
serializationFormats : ( schema as SchemaUsage ) . serializationFormats ?. filter (
2524
2539
( it ) => it !== KnownMediaType . Multipart ,
2525
2540
) ,
0 commit comments