Skip to content

Commit 99af20a

Browse files
authored
Merge branch 'main' into template
2 parents 4dc7e51 + 288e7b2 commit 99af20a

35 files changed

+861
-134
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
changeKind: fix
3+
packages:
4+
- "@azure-tools/typespec-azure-resource-manager"
5+
---
6+
7+
Fix common-types privatelink typo in `@key("privateLinkResourcenName") from privateLinkResourcenName to privateLinkResourceName`
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
changeKind: fix
3+
packages:
4+
- "@azure-tools/typespec-client-generator-core"
5+
---
6+
7+
Fix wrong example doc of `@override` decorator.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
3+
changeKind: fix
4+
packages:
5+
- "@azure-tools/typespec-client-generator-core"
6+
---
7+
8+
add cache for `SdkModelPropertyType` in TCGCContext
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
changeKind: internal
3+
packages:
4+
- "@azure-tools/typespec-client-generator-core"
5+
---
6+
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
3+
changeKind: feature
4+
packages:
5+
- "@azure-tools/typespec-autorest"
6+
- "@azure-tools/typespec-azure-resource-manager"
7+
---
8+
9+
Update versioning handling to use new mutator approach
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
changeKind: feature
3+
packages:
4+
- "@azure-tools/typespec-autorest"
5+
- "@azure-tools/typespec-azure-resource-manager"
6+
---
7+
8+
Use the `@identifiers` decorator to identify and utilize identifiers for `x-ms-identifiers`. Additionally, use the `@key` decorator to identify identifiers.

core

Submodule core updated 54 files

packages/typespec-autorest/src/emit.ts

Lines changed: 62 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,25 @@
11
import { createTCGCContext } from "@azure-tools/typespec-client-generator-core";
22
import {
3+
compilerAssert,
34
EmitContext,
4-
Namespace,
5-
NoTarget,
6-
Program,
7-
Service,
85
emitFile,
96
getDirectoryPath,
107
getNamespaceFullName,
118
getService,
129
interpolatePath,
1310
listServices,
14-
projectProgram,
11+
NoTarget,
12+
Program,
1513
reportDeprecated,
1614
resolvePath,
15+
Service,
1716
} from "@typespec/compiler";
17+
import {
18+
unsafe_mutateSubgraphWithNamespace,
19+
unsafe_MutatorWithNamespace,
20+
} from "@typespec/compiler/experimental";
1821
import { resolveInfo } from "@typespec/openapi";
19-
import { buildVersionProjections } from "@typespec/versioning";
22+
import { getVersioningMutators } from "@typespec/versioning";
2023
import { AutorestEmitterOptions, getTracer, reportDiagnostic } from "./lib.js";
2124
import {
2225
AutorestDocumentEmitterOptions,
@@ -123,31 +126,13 @@ export async function getAllServicesAtAllVersions(
123126

124127
const serviceRecords: AutorestServiceRecord[] = [];
125128
for (const service of services) {
126-
const originalProgram = program;
127-
const versions = buildVersionProjections(program, service.type).filter(
128-
(v) => !options.version || options.version === v.version,
129-
);
130-
131-
if (versions.length === 0) {
132-
reportDiagnostic(program, { code: "no-matching-version-found", target: service.type });
133-
}
129+
const versions = getVersioningMutators(program, service.type);
134130

135-
if (versions.length === 1 && versions[0].version === undefined) {
136-
let projectedProgram;
137-
if (versions[0].projections.length > 0) {
138-
projectedProgram = program = projectProgram(originalProgram, versions[0].projections);
139-
}
140-
const projectedServiceNs: Namespace = projectedProgram
141-
? (projectedProgram.projector.projectedTypes.get(service.type) as Namespace)
142-
: service.type;
143-
const projectedService =
144-
projectedServiceNs === program.getGlobalNamespaceType()
145-
? { type: program.getGlobalNamespaceType() }
146-
: getService(program, projectedServiceNs)!;
131+
if (versions === undefined) {
147132
const context: AutorestEmitterContext = {
148133
program,
149134
outputFile: resolveOutputFile(program, service, services.length > 1, options),
150-
service: projectedService,
135+
service: service,
151136
tcgcSdkContext,
152137
};
153138

@@ -157,42 +142,55 @@ export async function getAllServicesAtAllVersions(
157142
versioned: false,
158143
...result,
159144
});
145+
} else if (versions.kind === "transient") {
146+
const context: AutorestEmitterContext = {
147+
program,
148+
outputFile: resolveOutputFile(program, service, services.length > 1, options),
149+
service: service,
150+
tcgcSdkContext,
151+
};
152+
153+
const result = await getVersionSnapshotDocument(context, versions.mutator, options);
154+
serviceRecords.push({
155+
service,
156+
versioned: false,
157+
...result,
158+
});
160159
} else {
160+
const filteredVersions = versions.snapshots.filter(
161+
(v) => !options.version || options.version === v.version?.value,
162+
);
163+
164+
if (filteredVersions.length === 0 && options.version) {
165+
reportDiagnostic(program, { code: "no-matching-version-found", target: service.type });
166+
}
161167
const serviceRecord: AutorestVersionedServiceRecord = {
162168
service,
163169
versioned: true,
164170
versions: [],
165171
};
166172
serviceRecords.push(serviceRecord);
167173

168-
for (const record of versions) {
169-
const projectedProgram = (program = projectProgram(originalProgram, record.projections));
170-
171-
const projectedServiceNs: Namespace = projectedProgram
172-
? (projectedProgram.projector.projectedTypes.get(service.type) as Namespace)
173-
: service.type;
174-
const projectedService =
175-
projectedServiceNs === program.getGlobalNamespaceType()
176-
? { type: program.getGlobalNamespaceType() }
177-
: getService(program, projectedServiceNs)!;
174+
for (const record of filteredVersions) {
178175
const context: AutorestEmitterContext = {
179176
program,
180177
outputFile: resolveOutputFile(
181178
program,
182-
projectedService,
179+
service,
183180
services.length > 1,
184181
options,
185-
record.version,
182+
record.version?.value,
186183
),
187-
service: projectedService,
188-
version: record.version,
184+
service,
185+
version: record.version?.value,
189186
tcgcSdkContext,
190187
};
191-
const result = await getOpenAPIForService(context, options);
188+
189+
const result = await getVersionSnapshotDocument(context, record.mutator, options);
192190
serviceRecord.versions.push({
193191
...result,
194-
service: projectedService,
195-
version: record.version!,
192+
service,
193+
version: record.version!.value,
196194
});
197195
}
198196
}
@@ -201,6 +199,26 @@ export async function getAllServicesAtAllVersions(
201199
return serviceRecords;
202200
}
203201

202+
async function getVersionSnapshotDocument(
203+
context: AutorestEmitterContext,
204+
mutator: unsafe_MutatorWithNamespace,
205+
options: ResolvedAutorestEmitterOptions,
206+
) {
207+
const subgraph = unsafe_mutateSubgraphWithNamespace(
208+
context.program,
209+
[mutator],
210+
context.service.type,
211+
);
212+
213+
compilerAssert(subgraph.type.kind === "Namespace", "Should not have mutated to another type");
214+
const document = await getOpenAPIForService(
215+
{ ...context, service: getService(context.program, subgraph.type)! },
216+
options,
217+
);
218+
219+
return document;
220+
}
221+
204222
async function emitAllServiceAtAllVersions(
205223
program: Program,
206224
options: ResolvedAutorestEmitterOptions,

packages/typespec-autorest/src/openapi.ts

Lines changed: 45 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@ import {
1212
} from "@azure-tools/typespec-azure-core";
1313
import {
1414
getArmCommonTypeOpenAPIRef,
15+
getArmIdentifiers,
1516
getExternalTypeRef,
1617
isArmCommonType,
18+
isArmProviderNamespace,
1719
isAzureResource,
1820
isConditionallyFlattened,
1921
} from "@azure-tools/typespec-azure-resource-manager";
@@ -458,6 +460,7 @@ export async function getOpenAPIForService(
458460
prop.type.kind === "Scalar" &&
459461
ignoreDiagnostics(
460462
program.checker.isTypeAssignableTo(
463+
// eslint-disable-next-line @typescript-eslint/no-deprecated
461464
prop.type.projectionBase ?? prop.type,
462465
program.checker.getStdType("url"),
463466
prop.type,
@@ -750,6 +753,7 @@ export async function getOpenAPIForService(
750753
}
751754

752755
function isBytes(type: Type) {
756+
// eslint-disable-next-line @typescript-eslint/no-deprecated
753757
const baseType = type.projectionBase ?? type;
754758
return ignoreDiagnostics(
755759
program.checker.isTypeAssignableTo(baseType, program.checker.getStdType("bytes"), type),
@@ -963,7 +967,7 @@ export async function getOpenAPIForService(
963967
}
964968
return undefined;
965969
}
966-
function getSchemaOrRef(type: Type, schemaContext: SchemaContext): any {
970+
function getSchemaOrRef(type: Type, schemaContext: SchemaContext, namespace?: Namespace): any {
967971
let schemaNameOverride: ((name: string, visibility: Visibility) => string) | undefined =
968972
undefined;
969973
const ref = resolveExternalRef(type);
@@ -1013,7 +1017,7 @@ export async function getOpenAPIForService(
10131017
const name = getOpenAPITypeName(program, type, typeNameOptions);
10141018

10151019
if (shouldInline(program, type)) {
1016-
const schema = getSchemaForInlineType(type, name, schemaContext);
1020+
const schema = getSchemaForInlineType(type, name, schemaContext, namespace);
10171021

10181022
if (schema === undefined && isErrorType(type)) {
10191023
// Exit early so that syntax errors are exposed. This error will
@@ -1040,7 +1044,12 @@ export async function getOpenAPIForService(
10401044
return { $ref: pending.ref };
10411045
}
10421046
}
1043-
function getSchemaForInlineType(type: Type, name: string, context: SchemaContext) {
1047+
function getSchemaForInlineType(
1048+
type: Type,
1049+
name: string,
1050+
context: SchemaContext,
1051+
namespace?: Namespace,
1052+
) {
10441053
if (inProgressInlineTypes.has(type)) {
10451054
reportDiagnostic(program, {
10461055
code: "inline-cycle",
@@ -1050,7 +1059,7 @@ export async function getOpenAPIForService(
10501059
return {};
10511060
}
10521061
inProgressInlineTypes.add(type);
1053-
const schema = getSchemaForType(type, context);
1062+
const schema = getSchemaForType(type, context, namespace);
10541063
inProgressInlineTypes.delete(type);
10551064
return schema;
10561065
}
@@ -1627,17 +1636,20 @@ export async function getOpenAPIForService(
16271636
}
16281637
}
16291638

1630-
function getSchemaForType(type: Type, schemaContext: SchemaContext): OpenAPI2Schema | undefined {
1639+
function getSchemaForType(
1640+
type: Type,
1641+
schemaContext: SchemaContext,
1642+
namespace?: Namespace,
1643+
): OpenAPI2Schema | undefined {
16311644
const builtinType = getSchemaForLiterals(type);
16321645
if (builtinType !== undefined) {
16331646
return builtinType;
16341647
}
1635-
16361648
switch (type.kind) {
16371649
case "Intrinsic":
16381650
return getSchemaForIntrinsicType(type);
16391651
case "Model":
1640-
return getSchemaForModel(type, schemaContext);
1652+
return getSchemaForModel(type, schemaContext, namespace);
16411653
case "ModelProperty":
16421654
return getSchemaForType(type.type, schemaContext);
16431655
case "Scalar":
@@ -1843,6 +1855,10 @@ export async function getOpenAPIForService(
18431855
);
18441856
}
18451857

1858+
function ifArmIdentifiersDefault(armIdentifiers: string[]) {
1859+
return armIdentifiers.every((identifier) => identifier === "id" || identifier === "name");
1860+
}
1861+
18461862
function getSchemaForUnionVariant(
18471863
variant: UnionVariant,
18481864
schemaContext: SchemaContext,
@@ -1887,8 +1903,8 @@ export async function getOpenAPIForService(
18871903
return undefined;
18881904
}
18891905

1890-
function getSchemaForModel(model: Model, schemaContext: SchemaContext) {
1891-
const array = getArrayType(model, schemaContext);
1906+
function getSchemaForModel(model: Model, schemaContext: SchemaContext, namespace?: Namespace) {
1907+
const array = getArrayType(model, schemaContext, namespace);
18921908
if (array) {
18931909
return array;
18941910
}
@@ -2073,7 +2089,7 @@ export async function getOpenAPIForService(
20732089
propSchema = getSchemaOrRef(prop.type, context);
20742090
}
20752091
} else {
2076-
propSchema = getSchemaOrRef(prop.type, context);
2092+
propSchema = getSchemaOrRef(prop.type, context, prop.model?.namespace);
20772093
}
20782094

20792095
if (options.armResourceFlattening && isConditionallyFlattened(program, prop)) {
@@ -2375,7 +2391,11 @@ export async function getOpenAPIForService(
23752391
/**
23762392
* If the model is an array model return the OpenAPI2Schema for the array type.
23772393
*/
2378-
function getArrayType(typespecType: Model, context: SchemaContext): OpenAPI2Schema | undefined {
2394+
function getArrayType(
2395+
typespecType: Model,
2396+
context: SchemaContext,
2397+
namespace?: Namespace,
2398+
): OpenAPI2Schema | undefined {
23792399
if (isArrayModelType(program, typespecType)) {
23802400
const array: OpenAPI2Schema = {
23812401
type: "array",
@@ -2384,14 +2404,27 @@ export async function getOpenAPIForService(
23842404
visibility: context.visibility | Visibility.Item,
23852405
}),
23862406
};
2387-
if (!ifArrayItemContainsIdentifier(program, typespecType as any)) {
2407+
2408+
const armIdentifiers = getArmIdentifiers(program, typespecType);
2409+
if (isArmProviderNamespace(program, namespace) && hasValidArmIdentifiers(armIdentifiers)) {
2410+
array["x-ms-identifiers"] = armIdentifiers;
2411+
} else if (!ifArrayItemContainsIdentifier(program, typespecType as any)) {
23882412
array["x-ms-identifiers"] = [];
23892413
}
2414+
23902415
return applyIntrinsicDecorators(typespecType, array);
23912416
}
23922417
return undefined;
23932418
}
23942419

2420+
function hasValidArmIdentifiers(armIdentifiers: string[] | undefined) {
2421+
return (
2422+
armIdentifiers !== undefined &&
2423+
armIdentifiers.length > 0 &&
2424+
!ifArmIdentifiersDefault(armIdentifiers)
2425+
);
2426+
}
2427+
23952428
function getSchemaForScalar(scalar: Scalar): OpenAPI2Schema {
23962429
let result: OpenAPI2Schema = {};
23972430
const isStd = program.checker.isStdType(scalar);

0 commit comments

Comments
 (0)