@azure-tools/typespec-autorest 0.42.0-dev.3 → 0.42.0-dev.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,44 +1,14 @@
1
1
  import { extractLroStates, getArmResourceIdentifierConfig, getAsEmbeddingVector, getLroMetadata, getPagedResult, getUnionAsEnum, isFixed, } from "@azure-tools/typespec-azure-core";
2
- import { createSdkContext, getClientNameOverride, shouldFlattenProperty, } from "@azure-tools/typespec-client-generator-core";
3
- import { NoTarget, SyntaxKind, TwoLevelMap, compilerAssert, emitFile, getAllTags, getDirectoryPath, getDiscriminator, getDoc, getEncode, getFormat, getKnownValues, getMaxItems, getMaxLength, getMaxValue, getMinItems, getMinLength, getMinValue, getNamespaceFullName, getPattern, getProjectedName, getProperty, getPropertyType, getRelativePathFromDirectory, getRootLength, getService, getSummary, getVisibility, ignoreDiagnostics, interpolatePath, isArrayModelType, isDeprecated, isErrorModel, isErrorType, isGlobalNamespace, isNeverType, isNullType, isNumericType, isRecordModelType, isSecret, isService, isStringType, isTemplateDeclaration, isTemplateDeclarationOrInstance, isVoidType, listServices, navigateTypesInNamespace, projectProgram, resolveEncodedName, resolvePath, stringTemplateToString, } from "@typespec/compiler";
2
+ import { shouldFlattenProperty } from "@azure-tools/typespec-client-generator-core";
3
+ import { NoTarget, SyntaxKind, compilerAssert, createDiagnosticCollector, getAllTags, getDirectoryPath, getDiscriminator, getDoc, getEncode, getFormat, getKnownValues, getMaxItems, getMaxLength, getMaxValue, getMinItems, getMinLength, getMinValue, getPattern, getProjectedName, getProperty, getPropertyType, getRelativePathFromDirectory, getRootLength, getSummary, getVisibility, ignoreDiagnostics, interpolatePath, isArrayModelType, isDeprecated, isErrorModel, isErrorType, isGlobalNamespace, isNeverType, isNullType, isNumericType, isRecordModelType, isSecret, isService, isStringType, isTemplateDeclaration, isTemplateDeclarationOrInstance, isVoidType, navigateTypesInNamespace, resolveEncodedName, resolvePath, stringTemplateToString, } from "@typespec/compiler";
4
+ import { TwoLevelMap } from "@typespec/compiler/utils";
4
5
  import { Visibility, createMetadataInfo, getAllHttpServices, getAuthentication, getHeaderFieldOptions, getQueryParamOptions, getServers, getStatusCodeDescription, getVisibilitySuffix, isContentTypeHeader, isSharedRoute, reportIfNoRoutes, resolveRequestVisibility, } from "@typespec/http";
5
6
  import { checkDuplicateTypeName, getExtensions, getExternalDocs, getOpenAPITypeName, getParameterKey, isReadonlyProperty, resolveInfo, shouldInline, } from "@typespec/openapi";
6
- import { buildVersionProjections } from "@typespec/versioning";
7
7
  import { AutorestOpenAPISchema } from "./autorest-openapi-schema.js";
8
8
  import { getExamples, getRef } from "./decorators.js";
9
9
  import { sortWithJsonSchema } from "./json-schema-sorter/sorter.js";
10
- import { getTracer, reportDiagnostic } from "./lib.js";
11
- import { resolveOperationId } from "./utils.js";
12
- const defaultOptions = {
13
- "output-file": "{azure-resource-provider-folder}/{service-name}/{version-status}/{version}/openapi.json",
14
- "new-line": "lf",
15
- "include-x-typespec-name": "never",
16
- };
17
- export async function $onEmit(context) {
18
- const resolvedOptions = { ...defaultOptions, ...context.options };
19
- const tcgcSdkContext = createSdkContext(context, "@azure-tools/typespec-autorest");
20
- const armTypesDir = interpolatePath(resolvedOptions["arm-types-dir"] ?? "{project-root}/../../common-types/resource-management", {
21
- "project-root": context.program.projectRoot,
22
- "emitter-output-dir": context.emitterOutputDir,
23
- });
24
- const options = {
25
- outputFile: resolvedOptions["output-file"],
26
- outputDir: context.emitterOutputDir,
27
- azureResourceProviderFolder: resolvedOptions["azure-resource-provider-folder"],
28
- examplesDirectory: resolvedOptions["examples-directory"],
29
- version: resolvedOptions["version"],
30
- newLine: resolvedOptions["new-line"],
31
- omitUnreachableTypes: resolvedOptions["omit-unreachable-types"],
32
- includeXTypeSpecName: resolvedOptions["include-x-typespec-name"],
33
- armTypesDir,
34
- useReadOnlyStatusSchema: resolvedOptions["use-read-only-status-schema"],
35
- };
36
- const emitter = createOAPIEmitter(context.program, tcgcSdkContext, options);
37
- await emitter.emitOpenAPI();
38
- }
39
- function getEmitterDetails(program) {
40
- return [{ emitter: "@azure-tools/typespec-autorest" }];
41
- }
10
+ import { createDiagnostic, reportDiagnostic } from "./lib.js";
11
+ import { getClientName, resolveOperationId } from "./utils.js";
42
12
  /**
43
13
  * Represents a node that will hold a JSON reference. The value is computed
44
14
  * at the end so that we can defer decisions about the name that is
@@ -51,113 +21,111 @@ class Ref {
51
21
  return this.value;
52
22
  }
53
23
  }
54
- function createOAPIEmitter(program, tcgcSdkContext, options) {
55
- const tracer = getTracer(program);
56
- tracer.trace("options", JSON.stringify(options, null, 2));
24
+ export async function getOpenAPIForService(context, options) {
25
+ const { program, service } = context;
57
26
  const typeNameOptions = {
58
27
  // shorten type names by removing TypeSpec and service namespace
59
28
  namespaceFilter(ns) {
60
29
  return !isService(program, ns);
61
30
  },
62
31
  };
63
- let root;
64
- let currentService;
32
+ const info = resolveInfo(program, service.type);
33
+ const auth = processAuth(service.type);
34
+ const root = {
35
+ swagger: "2.0",
36
+ info: {
37
+ title: "(title)",
38
+ ...info,
39
+ version: context.version ?? info?.version ?? "0000-00-00",
40
+ "x-typespec-generated": [{ emitter: "@azure-tools/typespec-autorest" }],
41
+ },
42
+ schemes: ["https"],
43
+ ...resolveHost(program, service.type),
44
+ externalDocs: getExternalDocs(program, service.type),
45
+ produces: [], // Pre-initialize produces and consumes so that
46
+ consumes: [], // they show up at the top of the document
47
+ security: auth?.security,
48
+ securityDefinitions: auth?.securitySchemes ?? {},
49
+ tags: [],
50
+ paths: {},
51
+ "x-ms-paths": {},
52
+ definitions: {},
53
+ parameters: {},
54
+ };
65
55
  let currentEndpoint;
66
56
  let currentConsumes;
67
57
  let currentProduces;
68
- let metadataInfo;
58
+ const metadataInfo = createMetadataInfo(program, {
59
+ canonicalVisibility: Visibility.Read,
60
+ canShareProperty: canSharePropertyUsingReadonlyOrXMSMutability,
61
+ });
69
62
  // Keep a map of all Types+Visibility combinations that were encountered
70
63
  // that need schema definitions.
71
- let pendingSchemas = new TwoLevelMap();
64
+ const pendingSchemas = new TwoLevelMap();
72
65
  // Reuse a single ref object per Type+Visibility combination.
73
- let refs = new TwoLevelMap();
66
+ const refs = new TwoLevelMap();
74
67
  // Keep track of inline types still in the process of having their schema computed
75
68
  // This is used to detect cycles in inline types, which is an
76
- let inProgressInlineTypes = new Set();
69
+ const inProgressInlineTypes = new Set();
77
70
  // Map model properties that represent shared parameters to their parameter
78
71
  // definition that will go in #/parameters. Inlined parameters do not go in
79
72
  // this map.
80
- let params;
73
+ const params = new Map();
81
74
  // Keep track of models that have had properties spread into parameters. We won't
82
75
  // consider these unreferenced when emitting unreferenced types.
83
- let paramModels;
76
+ const paramModels = new Set();
84
77
  // De-dupe the per-endpoint tags that will be added into the #/tags
85
- let tags;
78
+ const tags = new Set();
86
79
  // The set of produces/consumes values found in all operations
87
80
  const globalProduces = new Set(["application/json"]);
88
81
  const globalConsumes = new Set(["application/json"]);
89
- let operationExamplesMap;
90
- let operationIdsWithExample;
91
- let outputFile;
92
- let context;
93
- async function emitOpenAPI() {
94
- const services = listServices(program);
95
- if (services.length === 0) {
96
- services.push({ type: program.getGlobalNamespaceType() });
97
- }
98
- for (const service of services) {
99
- currentService = service;
100
- const originalProgram = program;
101
- const versions = buildVersionProjections(program, service.type).filter((v) => !options.version || options.version === v.version);
102
- for (const record of versions) {
103
- let projectedProgram;
104
- if (record.projections.length > 0) {
105
- projectedProgram = program = projectProgram(originalProgram, record.projections);
106
- }
107
- context = {
108
- program,
109
- service,
110
- version: record.version,
111
- getClientName,
112
- };
113
- const projectedServiceNs = projectedProgram
114
- ? projectedProgram.projector.projectedTypes.get(service.type)
115
- : service.type;
116
- await emitOpenAPIFromVersion(projectedServiceNs === program.getGlobalNamespaceType()
117
- ? { type: program.getGlobalNamespaceType() }
118
- : getService(program, projectedServiceNs), services.length > 1, record.version);
119
- }
120
- }
121
- }
122
- return { emitOpenAPI };
123
- function initializeEmitter(service, multipleService, version) {
124
- const auth = processAuth(service.type);
125
- const info = resolveInfo(program, service.type);
126
- root = {
127
- swagger: "2.0",
128
- info: {
129
- title: "(title)",
130
- ...info,
131
- version: version ?? info?.version ?? "0000-00-00",
132
- "x-typespec-generated": getEmitterDetails(program),
133
- },
134
- schemes: ["https"],
135
- ...resolveHost(program, service.type),
136
- externalDocs: getExternalDocs(program, service.type),
137
- produces: [], // Pre-initialize produces and consumes so that
138
- consumes: [], // they show up at the top of the document
139
- security: auth?.security,
140
- securityDefinitions: auth?.securitySchemes ?? {},
141
- tags: [],
142
- paths: {},
143
- "x-ms-paths": {},
144
- definitions: {},
145
- parameters: {},
146
- };
147
- pendingSchemas = new TwoLevelMap();
148
- refs = new TwoLevelMap();
149
- metadataInfo = createMetadataInfo(program, {
150
- canonicalVisibility: Visibility.Read,
151
- canShareProperty: canSharePropertyUsingReadonlyOrXMSMutability,
152
- });
153
- inProgressInlineTypes = new Set();
154
- params = new Map();
155
- paramModels = new Set();
156
- tags = new Set();
157
- operationExamplesMap = new Map();
158
- operationIdsWithExample = new Set();
159
- outputFile = resolveOutputFile(program, service, multipleService, options, version);
160
- }
82
+ const operationIdsWithExample = new Set();
83
+ const [exampleMap, diagnostics] = await loadExamples(program.host, options, context.version);
84
+ program.reportDiagnostics(diagnostics);
85
+ const services = ignoreDiagnostics(getAllHttpServices(program));
86
+ const routes = services[0].operations;
87
+ reportIfNoRoutes(program, routes);
88
+ routes.forEach(emitOperation);
89
+ emitParameters();
90
+ emitSchemas(service.type);
91
+ emitTags();
92
+ // Finalize global produces/consumes
93
+ if (globalProduces.size > 0) {
94
+ root.produces = [...globalProduces.values()];
95
+ }
96
+ else {
97
+ delete root.produces;
98
+ }
99
+ if (globalConsumes.size > 0) {
100
+ root.consumes = [...globalConsumes.values()];
101
+ }
102
+ else {
103
+ delete root.consumes;
104
+ }
105
+ // Clean up empty entries
106
+ if (root["x-ms-paths"] && Object.keys(root["x-ms-paths"]).length === 0) {
107
+ delete root["x-ms-paths"];
108
+ }
109
+ if (root.security && Object.keys(root.security).length === 0) {
110
+ delete root["security"];
111
+ }
112
+ if (root.securityDefinitions && Object.keys(root.securityDefinitions).length === 0) {
113
+ delete root["securityDefinitions"];
114
+ }
115
+ return {
116
+ document: root,
117
+ operationExamples: [...operationIdsWithExample]
118
+ .map((operationId) => {
119
+ const data = exampleMap.get(operationId);
120
+ if (data) {
121
+ return { operationId, examples: Object.values(data) };
122
+ }
123
+ else {
124
+ return undefined;
125
+ }
126
+ })
127
+ .filter((x) => x),
128
+ };
161
129
  function resolveHost(program, namespace) {
162
130
  const servers = getServers(program, namespace);
163
131
  if (servers === undefined) {
@@ -192,7 +160,10 @@ function createOAPIEmitter(program, tcgcSdkContext, options) {
192
160
  }
193
161
  const parameters = [];
194
162
  for (const prop of server.parameters.values()) {
195
- const param = getOpenAPI2Parameter(prop, "path", Visibility.Read);
163
+ const param = getOpenAPI2Parameter(prop, "path", {
164
+ visibility: Visibility.Read,
165
+ ignoreMetadataAnnotations: false,
166
+ });
196
167
  if (prop.type.kind === "Scalar" &&
197
168
  ignoreDiagnostics(program.checker.isTypeAssignableTo(prop.type.projectionBase ?? prop.type, program.checker.getStdType("url"), prop.type))) {
198
169
  param["x-ms-skip-url-encoding"] = true;
@@ -207,83 +178,6 @@ function createOAPIEmitter(program, tcgcSdkContext, options) {
207
178
  },
208
179
  };
209
180
  }
210
- async function emitOpenAPIFromVersion(service, multipleService, version) {
211
- initializeEmitter(service, multipleService, version);
212
- try {
213
- await loadExamples(version);
214
- const services = ignoreDiagnostics(getAllHttpServices(program));
215
- const routes = services[0].operations;
216
- reportIfNoRoutes(program, routes);
217
- routes.forEach(emitOperation);
218
- emitParameters();
219
- emitSchemas(service.type);
220
- emitTags();
221
- // Finalize global produces/consumes
222
- if (globalProduces.size > 0) {
223
- root.produces = [...globalProduces.values()];
224
- }
225
- else {
226
- delete root.produces;
227
- }
228
- if (globalConsumes.size > 0) {
229
- root.consumes = [...globalConsumes.values()];
230
- }
231
- else {
232
- delete root.consumes;
233
- }
234
- // Clean up empty entries
235
- if (root["x-ms-paths"] && Object.keys(root["x-ms-paths"]).length === 0) {
236
- delete root["x-ms-paths"];
237
- }
238
- if (root.security && Object.keys(root.security).length === 0) {
239
- delete root["security"];
240
- }
241
- if (root.securityDefinitions && Object.keys(root.securityDefinitions).length === 0) {
242
- delete root["securityDefinitions"];
243
- }
244
- if (!program.compilerOptions.noEmit && !program.hasError()) {
245
- // Sort the document
246
- const sortedRoot = sortOpenAPIDocument(root);
247
- // Write out the OpenAPI document to the output path
248
- await emitFile(program, {
249
- path: outputFile,
250
- content: prettierOutput(JSON.stringify(sortedRoot, null, 2)),
251
- newLine: options.newLine,
252
- });
253
- // Copy examples to the output directory
254
- if (options.examplesDirectory && operationIdsWithExample.size > 0) {
255
- const examplesPath = resolvePath(getDirectoryPath(outputFile), "examples");
256
- const exampleDir = version
257
- ? resolvePath(options.examplesDirectory, version)
258
- : resolvePath(options.examplesDirectory);
259
- await program.host.mkdirp(examplesPath);
260
- for (const operationId of operationIdsWithExample) {
261
- const examples = operationExamplesMap.get(operationId);
262
- if (examples) {
263
- for (const [_, fileName] of Object.entries(examples)) {
264
- const content = await program.host.readFile(resolvePath(exampleDir, fileName));
265
- await emitFile(program, {
266
- path: resolvePath(examplesPath, fileName),
267
- content: content.text,
268
- newLine: options.newLine,
269
- });
270
- }
271
- }
272
- }
273
- }
274
- }
275
- }
276
- catch (err) {
277
- if (err instanceof ErrorTypeFoundError) {
278
- // Return early, there must be a parse error if an ErrorType was
279
- // inserted into the TypeSpec output
280
- return;
281
- }
282
- else {
283
- throw err;
284
- }
285
- }
286
- }
287
181
  function parseNextLinkName(paged) {
288
182
  const pathComponents = paged.nextLinkSegments;
289
183
  if (pathComponents) {
@@ -415,7 +309,7 @@ function createOAPIEmitter(program, tcgcSdkContext, options) {
415
309
  currentEndpoint["x-ms-examples"] = examples.reduce((acc, example) => ({ ...acc, [example.title]: { $ref: example.pathOrUri } }), {});
416
310
  }
417
311
  if (options.examplesDirectory) {
418
- const examples = operationExamplesMap.get(currentEndpoint.operationId);
312
+ const examples = exampleMap.get(currentEndpoint.operationId);
419
313
  if (examples && currentEndpoint.operationId) {
420
314
  operationIdsWithExample.add(currentEndpoint.operationId);
421
315
  currentEndpoint["x-ms-examples"] = currentEndpoint["x-ms-examples"] || {};
@@ -536,19 +430,24 @@ function createOAPIEmitter(program, tcgcSdkContext, options) {
536
430
  }
537
431
  }
538
432
  if (data.body) {
539
- if (body && body !== data.body.type) {
433
+ if (body && body.type !== data.body.type) {
540
434
  reportDiagnostic(program, {
541
435
  code: "duplicate-body-types",
542
436
  target: response.type,
543
437
  });
544
438
  }
545
- body = data.body.type;
439
+ body = data.body;
546
440
  contentTypes.push(...data.body.contentTypes);
547
441
  }
548
442
  }
549
443
  if (body) {
550
- const isBinary = contentTypes.every((t) => isBinaryPayload(body, t));
551
- openapiResponse.schema = isBinary ? { type: "file" } : getSchemaOrRef(body, Visibility.Read);
444
+ const isBinary = contentTypes.every((t) => isBinaryPayload(body.type, t));
445
+ openapiResponse.schema = isBinary
446
+ ? { type: "file" }
447
+ : getSchemaOrRef(body.type, {
448
+ visibility: Visibility.Read,
449
+ ignoreMetadataAnnotations: body.isExplicit && body.containsMetadataAnnotations,
450
+ });
552
451
  }
553
452
  for (const contentType of contentTypes) {
554
453
  currentProduces.add(contentType);
@@ -557,7 +456,10 @@ function createOAPIEmitter(program, tcgcSdkContext, options) {
557
456
  }
558
457
  function getResponseHeader(prop) {
559
458
  const header = {};
560
- populateParameter(header, prop, "header", Visibility.Read);
459
+ populateParameter(header, prop, "header", {
460
+ visibility: Visibility.Read,
461
+ ignoreMetadataAnnotations: false,
462
+ });
561
463
  delete header.in;
562
464
  delete header.name;
563
465
  delete header.required;
@@ -570,9 +472,9 @@ function createOAPIEmitter(program, tcgcSdkContext, options) {
570
472
  if (getRootLength(absoluteRef) === 0) {
571
473
  return absoluteRef; // It is already relative.
572
474
  }
573
- return getRelativePathFromDirectory(getDirectoryPath(outputFile), absoluteRef, false);
475
+ return getRelativePathFromDirectory(getDirectoryPath(context.outputFile), absoluteRef, false);
574
476
  }
575
- function getSchemaOrRef(type, visibility) {
477
+ function getSchemaOrRef(type, schemaContext) {
576
478
  const refUrl = getRef(program, type, { version: context.version, service: context.service });
577
479
  if (refUrl) {
578
480
  return {
@@ -602,12 +504,12 @@ function createOAPIEmitter(program, tcgcSdkContext, options) {
602
504
  }
603
505
  }
604
506
  if (type.kind === "ModelProperty") {
605
- return resolveProperty(type, visibility);
507
+ return resolveProperty(type, schemaContext);
606
508
  }
607
- type = metadataInfo.getEffectivePayloadType(type, visibility);
509
+ type = metadataInfo.getEffectivePayloadType(type, schemaContext.visibility);
608
510
  const name = getOpenAPITypeName(program, type, typeNameOptions);
609
511
  if (shouldInline(program, type)) {
610
- const schema = getSchemaForInlineType(type, name, visibility);
512
+ const schema = getSchemaForInlineType(type, name, schemaContext);
611
513
  if (schema === undefined && isErrorType(type)) {
612
514
  // Exit early so that syntax errors are exposed. This error will
613
515
  // be caught and handled in emitOpenAPI.
@@ -621,18 +523,18 @@ function createOAPIEmitter(program, tcgcSdkContext, options) {
621
523
  }
622
524
  else {
623
525
  // Use shared schema when type is not transformed by visibility from the canonical read visibility.
624
- if (!metadataInfo.isTransformed(type, visibility)) {
625
- visibility = Visibility.Read;
526
+ if (!metadataInfo.isTransformed(type, schemaContext.visibility)) {
527
+ schemaContext = { ...schemaContext, visibility: Visibility.Read };
626
528
  }
627
- const pending = pendingSchemas.getOrAdd(type, visibility, () => ({
529
+ const pending = pendingSchemas.getOrAdd(type, schemaContext.visibility, () => ({
628
530
  type,
629
- visibility,
630
- ref: refs.getOrAdd(type, visibility, () => new Ref()),
531
+ visibility: schemaContext.visibility,
532
+ ref: refs.getOrAdd(type, schemaContext.visibility, () => new Ref()),
631
533
  }));
632
534
  return { $ref: pending.ref };
633
535
  }
634
536
  }
635
- function getSchemaForInlineType(type, name, visibility) {
537
+ function getSchemaForInlineType(type, name, context) {
636
538
  if (inProgressInlineTypes.has(type)) {
637
539
  reportDiagnostic(program, {
638
540
  code: "inline-cycle",
@@ -642,7 +544,7 @@ function createOAPIEmitter(program, tcgcSdkContext, options) {
642
544
  return {};
643
545
  }
644
546
  inProgressInlineTypes.add(type);
645
- const schema = getSchemaForType(type, visibility);
547
+ const schema = getSchemaForType(type, context);
646
548
  inProgressInlineTypes.delete(type);
647
549
  return schema;
648
550
  }
@@ -685,11 +587,6 @@ function createOAPIEmitter(program, tcgcSdkContext, options) {
685
587
  // `resolveEncodedName` will return the original name if no @encodedName so we have to do that check
686
588
  return encodedName === type.name ? viaProjection ?? type.name : encodedName;
687
589
  }
688
- function getClientName(type) {
689
- const viaProjection = getProjectedName(program, type, "client");
690
- const clientName = getClientNameOverride(tcgcSdkContext, type);
691
- return clientName ?? viaProjection ?? type.name;
692
- }
693
590
  function emitEndpointParameters(methodParams, visibility) {
694
591
  const consumes = methodParams.body?.contentTypes ?? [];
695
592
  for (const httpOpParam of methodParams.parameters) {
@@ -701,7 +598,7 @@ function createOAPIEmitter(program, tcgcSdkContext, options) {
701
598
  if (httpOpParam.type === "header" && isContentTypeHeader(program, httpOpParam.param)) {
702
599
  continue;
703
600
  }
704
- emitParameter(httpOpParam.param, httpOpParam.type, visibility, httpOpParam.name);
601
+ emitParameter(httpOpParam.param, httpOpParam.type, { visibility, ignoreMetadataAnnotations: false }, httpOpParam.name);
705
602
  }
706
603
  if (consumes.length === 0 && methodParams.body) {
707
604
  // we didn't find an explicit content type anywhere, so infer from body.
@@ -714,21 +611,25 @@ function createOAPIEmitter(program, tcgcSdkContext, options) {
714
611
  }
715
612
  if (methodParams.body && !isVoidType(methodParams.body.type)) {
716
613
  const isBinary = isBinaryPayload(methodParams.body.type, consumes);
614
+ const schemaContext = {
615
+ visibility,
616
+ ignoreMetadataAnnotations: methodParams.body.isExplicit && methodParams.body.containsMetadataAnnotations,
617
+ };
717
618
  const schema = isBinary
718
619
  ? { type: "string", format: "binary" }
719
- : getSchemaOrRef(methodParams.body.type, visibility);
620
+ : getSchemaOrRef(methodParams.body.type, schemaContext);
720
621
  if (currentConsumes.has("multipart/form-data")) {
721
622
  const bodyModelType = methodParams.body.type;
722
623
  // Assert, this should never happen. Rest library guard against that.
723
624
  compilerAssert(bodyModelType.kind === "Model", "Body should always be a Model.");
724
625
  if (bodyModelType) {
725
626
  for (const param of bodyModelType.properties.values()) {
726
- emitParameter(param, "formData", visibility, getJsonName(param));
627
+ emitParameter(param, "formData", schemaContext, getJsonName(param));
727
628
  }
728
629
  }
729
630
  }
730
631
  else if (methodParams.body.parameter) {
731
- emitParameter(methodParams.body.parameter, "body", visibility, getJsonName(methodParams.body.parameter), schema);
632
+ emitParameter(methodParams.body.parameter, "body", { visibility, ignoreMetadataAnnotations: false }, getJsonName(methodParams.body.parameter), schema);
732
633
  }
733
634
  else {
734
635
  currentEndpoint.parameters.push({
@@ -755,7 +656,7 @@ function createOAPIEmitter(program, tcgcSdkContext, options) {
755
656
  }
756
657
  return undefined;
757
658
  }
758
- function emitParameter(param, kind, visibility, name, typeOverride) {
659
+ function emitParameter(param, kind, schemaContext, name, typeOverride) {
759
660
  if (isNeverType(param.type)) {
760
661
  return;
761
662
  }
@@ -763,11 +664,11 @@ function createOAPIEmitter(program, tcgcSdkContext, options) {
763
664
  currentEndpoint.parameters.push(ph);
764
665
  // If the parameter already has a $ref, don't bother populating it
765
666
  if (!("$ref" in ph)) {
766
- populateParameter(ph, param, kind, visibility, name, typeOverride);
667
+ populateParameter(ph, param, kind, schemaContext, name, typeOverride);
767
668
  }
768
669
  }
769
- function getSchemaForPrimitiveItems(type, visibility, paramName, multipart) {
770
- const fullSchema = getSchemaForType(type, visibility);
670
+ function getSchemaForPrimitiveItems(type, schemaContext, paramName, multipart) {
671
+ const fullSchema = getSchemaForType(type, schemaContext);
771
672
  if (fullSchema === undefined) {
772
673
  return undefined;
773
674
  }
@@ -781,7 +682,7 @@ function createOAPIEmitter(program, tcgcSdkContext, options) {
781
682
  }
782
683
  return fullSchema;
783
684
  }
784
- function getFormDataSchema(type, visibility, paramName) {
685
+ function getFormDataSchema(type, schemaContext, paramName) {
785
686
  if (isBytes(type)) {
786
687
  return { type: "file" };
787
688
  }
@@ -790,7 +691,7 @@ function createOAPIEmitter(program, tcgcSdkContext, options) {
790
691
  if (isBytes(elementType)) {
791
692
  return { type: "array", items: { type: "string", format: "binary" } };
792
693
  }
793
- const schema = getSchemaForPrimitiveItems(elementType, visibility, paramName, true);
694
+ const schema = getSchemaForPrimitiveItems(elementType, schemaContext, paramName, true);
794
695
  if (schema === undefined) {
795
696
  return undefined;
796
697
  }
@@ -801,14 +702,14 @@ function createOAPIEmitter(program, tcgcSdkContext, options) {
801
702
  };
802
703
  }
803
704
  else {
804
- const schema = getSchemaForPrimitiveItems(type, visibility, paramName, true);
705
+ const schema = getSchemaForPrimitiveItems(type, schemaContext, paramName, true);
805
706
  if (schema === undefined) {
806
707
  return undefined;
807
708
  }
808
709
  return schema;
809
710
  }
810
711
  }
811
- function getOpenAPI2Parameter(param, kind, visibility, name, bodySchema) {
712
+ function getOpenAPI2Parameter(param, kind, schemaContext, name, bodySchema) {
812
713
  const ph = {
813
714
  name: name ?? param.name,
814
715
  in: kind,
@@ -826,7 +727,7 @@ function createOAPIEmitter(program, tcgcSdkContext, options) {
826
727
  ph.schema = bodySchema;
827
728
  }
828
729
  else if (ph.in === "formData") {
829
- Object.assign(ph, getFormDataSchema(param.type, visibility, ph.name));
730
+ Object.assign(ph, getFormDataSchema(param.type, schemaContext, ph.name));
830
731
  }
831
732
  else {
832
733
  const collectionFormat = (kind === "query"
@@ -843,13 +744,13 @@ function createOAPIEmitter(program, tcgcSdkContext, options) {
843
744
  if (param.type.kind === "Model" && isArrayModelType(program, param.type)) {
844
745
  ph.type = "array";
845
746
  const schema = {
846
- ...getSchemaForPrimitiveItems(param.type.indexer.value, visibility, ph.name),
747
+ ...getSchemaForPrimitiveItems(param.type.indexer.value, schemaContext, ph.name),
847
748
  };
848
749
  delete schema.description;
849
750
  ph.items = schema;
850
751
  }
851
752
  else {
852
- Object.assign(ph, getSchemaForPrimitiveItems(param.type, visibility, ph.name));
753
+ Object.assign(ph, getSchemaForPrimitiveItems(param.type, schemaContext, ph.name));
853
754
  }
854
755
  }
855
756
  attachExtensions(param, ph);
@@ -860,8 +761,8 @@ function createOAPIEmitter(program, tcgcSdkContext, options) {
860
761
  Object.assign(ph, applyIntrinsicDecorators(param, { type: ph.type, format: ph.format }));
861
762
  return ph;
862
763
  }
863
- function populateParameter(ph, param, kind, visibility, name, bodySchema) {
864
- Object.assign(ph, getOpenAPI2Parameter(param, kind, visibility, name, bodySchema));
764
+ function populateParameter(ph, param, kind, schemaContext, name, bodySchema) {
765
+ Object.assign(ph, getOpenAPI2Parameter(param, kind, schemaContext, name, bodySchema));
865
766
  }
866
767
  function emitParameters() {
867
768
  for (const [property, param] of params) {
@@ -910,7 +811,10 @@ function createOAPIEmitter(program, tcgcSdkContext, options) {
910
811
  for (const [visibility, pending] of group) {
911
812
  processedSchemas.getOrAdd(type, visibility, () => ({
912
813
  ...pending,
913
- schema: getSchemaForType(type, visibility),
814
+ schema: getSchemaForType(type, {
815
+ visibility: visibility,
816
+ ignoreMetadataAnnotations: false,
817
+ }),
914
818
  }));
915
819
  }
916
820
  pendingSchemas.delete(type);
@@ -920,7 +824,7 @@ function createOAPIEmitter(program, tcgcSdkContext, options) {
920
824
  function processUnreferencedSchemas() {
921
825
  const addSchema = (type) => {
922
826
  if (!processedSchemas.has(type) && !paramModels.has(type) && !shouldInline(program, type)) {
923
- getSchemaOrRef(type, Visibility.Read);
827
+ getSchemaOrRef(type, { visibility: Visibility.Read, ignoreMetadataAnnotations: false });
924
828
  }
925
829
  };
926
830
  const skipSubNamespaces = isGlobalNamespace(program, serviceNamespace);
@@ -938,67 +842,7 @@ function createOAPIEmitter(program, tcgcSdkContext, options) {
938
842
  root.tags.push({ name: tag });
939
843
  }
940
844
  }
941
- async function loadExamples(version) {
942
- if (options.examplesDirectory) {
943
- const exampleDir = version
944
- ? resolvePath(options.examplesDirectory, version)
945
- : resolvePath(options.examplesDirectory);
946
- try {
947
- if (!(await program.host.stat(exampleDir)).isDirectory())
948
- return;
949
- }
950
- catch (err) {
951
- reportDiagnostic(program, {
952
- code: "example-loading",
953
- messageId: "noDirectory",
954
- format: { directory: exampleDir },
955
- target: NoTarget,
956
- });
957
- return;
958
- }
959
- const exampleFiles = await program.host.readDir(exampleDir);
960
- for (const fileName of exampleFiles) {
961
- try {
962
- const exampleFile = await program.host.readFile(resolvePath(exampleDir, fileName));
963
- const example = JSON.parse(exampleFile.text);
964
- if (!example.operationId || !example.title) {
965
- reportDiagnostic(program, {
966
- code: "example-loading",
967
- messageId: "noOperationId",
968
- format: { filename: fileName },
969
- target: NoTarget,
970
- });
971
- continue;
972
- }
973
- if (!operationExamplesMap.has(example.operationId)) {
974
- operationExamplesMap.set(example.operationId, {});
975
- }
976
- const examples = operationExamplesMap.get(example.operationId);
977
- if (example.title in examples) {
978
- reportDiagnostic(program, {
979
- code: "duplicate-example-file",
980
- target: NoTarget,
981
- format: {
982
- filename: fileName,
983
- operationId: example.operationId,
984
- title: example.title,
985
- },
986
- });
987
- }
988
- examples[example.title] = fileName;
989
- }
990
- catch (err) {
991
- reportDiagnostic(program, {
992
- code: "example-loading",
993
- messageId: "default",
994
- format: { filename: fileName, error: err?.toString() ?? "" },
995
- target: NoTarget,
996
- });
997
- }
998
- }
999
- }
1000
- }
1001
- function getSchemaForType(type, visibility) {
845
+ function getSchemaForType(type, schemaContext) {
1002
846
  const builtinType = getSchemaForLiterals(type);
1003
847
  if (builtinType !== undefined) {
1004
848
  return builtinType;
@@ -1007,15 +851,15 @@ function createOAPIEmitter(program, tcgcSdkContext, options) {
1007
851
  case "Intrinsic":
1008
852
  return getSchemaForIntrinsicType(type);
1009
853
  case "Model":
1010
- return getSchemaForModel(type, visibility);
854
+ return getSchemaForModel(type, schemaContext);
1011
855
  case "ModelProperty":
1012
- return getSchemaForType(type.type, visibility);
856
+ return getSchemaForType(type.type, schemaContext);
1013
857
  case "Scalar":
1014
858
  return getSchemaForScalar(type);
1015
859
  case "Union":
1016
- return getSchemaForUnion(type, visibility);
860
+ return getSchemaForUnion(type, schemaContext);
1017
861
  case "UnionVariant":
1018
- return getSchemaForUnionVariant(type, visibility);
862
+ return getSchemaForUnionVariant(type, schemaContext);
1019
863
  case "Enum":
1020
864
  return getSchemaForEnum(type);
1021
865
  case "Tuple":
@@ -1114,7 +958,7 @@ function createOAPIEmitter(program, tcgcSdkContext, options) {
1114
958
  }
1115
959
  return applyIntrinsicDecorators(union, schema);
1116
960
  }
1117
- function getSchemaForUnion(union, visibility) {
961
+ function getSchemaForUnion(union, schemaContext) {
1118
962
  const nonNullOptions = [...union.variants.values()]
1119
963
  .map((x) => x.type)
1120
964
  .filter((t) => !isNullType(t));
@@ -1126,7 +970,7 @@ function createOAPIEmitter(program, tcgcSdkContext, options) {
1126
970
  if (nonNullOptions.length === 1) {
1127
971
  const type = nonNullOptions[0];
1128
972
  // Get the schema for the model type
1129
- const schema = getSchemaOrRef(type, visibility);
973
+ const schema = getSchemaOrRef(type, schemaContext);
1130
974
  if (schema.$ref) {
1131
975
  if (type.kind === "Model") {
1132
976
  return { type: "object", allOf: [schema], "x-nullable": nullable };
@@ -1159,8 +1003,8 @@ function createOAPIEmitter(program, tcgcSdkContext, options) {
1159
1003
  return (getExtensions(program, array).has("x-ms-identifiers") ||
1160
1004
  getProperty(array.indexer.value, "id"));
1161
1005
  }
1162
- function getSchemaForUnionVariant(variant, visibility) {
1163
- return getSchemaForType(variant.type, visibility);
1006
+ function getSchemaForUnionVariant(variant, schemaContext) {
1007
+ return getSchemaForType(variant.type, schemaContext);
1164
1008
  }
1165
1009
  function getDefaultValue(type) {
1166
1010
  switch (type.kind) {
@@ -1220,8 +1064,8 @@ function createOAPIEmitter(program, tcgcSdkContext, options) {
1220
1064
  }
1221
1065
  return undefined;
1222
1066
  }
1223
- function getSchemaForModel(model, visibility) {
1224
- const array = getArrayType(model, visibility);
1067
+ function getSchemaForModel(model, schemaContext) {
1068
+ const array = getArrayType(model, schemaContext);
1225
1069
  if (array) {
1226
1070
  return array;
1227
1071
  }
@@ -1240,12 +1084,12 @@ function createOAPIEmitter(program, tcgcSdkContext, options) {
1240
1084
  }
1241
1085
  const properties = {};
1242
1086
  if (isRecordModelType(program, model)) {
1243
- modelSchema.additionalProperties = getSchemaOrRef(model.indexer.value, visibility);
1087
+ modelSchema.additionalProperties = getSchemaOrRef(model.indexer.value, schemaContext);
1244
1088
  }
1245
1089
  const derivedModels = model.derivedModels.filter(includeDerivedModel);
1246
1090
  // getSchemaOrRef on all children to push them into components.schemas
1247
1091
  for (const child of derivedModels) {
1248
- getSchemaOrRef(child, visibility);
1092
+ getSchemaOrRef(child, schemaContext);
1249
1093
  }
1250
1094
  const discriminator = getDiscriminator(program, model);
1251
1095
  if (discriminator) {
@@ -1262,7 +1106,7 @@ function createOAPIEmitter(program, tcgcSdkContext, options) {
1262
1106
  }
1263
1107
  applyExternalDocs(model, modelSchema);
1264
1108
  for (const prop of model.properties.values()) {
1265
- if (!metadataInfo.isPayloadProperty(prop, visibility)) {
1109
+ if (!metadataInfo.isPayloadProperty(prop, schemaContext.visibility, schemaContext.ignoreMetadataAnnotations)) {
1266
1110
  continue;
1267
1111
  }
1268
1112
  if (isNeverType(prop.type)) {
@@ -1270,7 +1114,7 @@ function createOAPIEmitter(program, tcgcSdkContext, options) {
1270
1114
  continue;
1271
1115
  }
1272
1116
  const jsonName = getJsonName(prop);
1273
- const clientName = getClientName(prop);
1117
+ const clientName = getClientName(context, prop);
1274
1118
  const description = getDoc(program, prop);
1275
1119
  // if this property is a discriminator property, remove it to keep autorest validation happy
1276
1120
  if (model.baseModel) {
@@ -1279,14 +1123,15 @@ function createOAPIEmitter(program, tcgcSdkContext, options) {
1279
1123
  continue;
1280
1124
  }
1281
1125
  }
1282
- if (!metadataInfo.isOptional(prop, visibility) || prop.name === discriminator?.propertyName) {
1126
+ if (!metadataInfo.isOptional(prop, schemaContext.visibility) ||
1127
+ prop.name === discriminator?.propertyName) {
1283
1128
  if (!modelSchema.required) {
1284
1129
  modelSchema.required = [];
1285
1130
  }
1286
1131
  modelSchema.required.push(jsonName);
1287
1132
  }
1288
1133
  // Apply decorators on the property to the type's schema
1289
- properties[jsonName] = resolveProperty(prop, visibility);
1134
+ properties[jsonName] = resolveProperty(prop, schemaContext);
1290
1135
  const property = properties[jsonName];
1291
1136
  if (jsonName !== clientName) {
1292
1137
  property["x-ms-client-name"] = clientName;
@@ -1331,11 +1176,11 @@ function createOAPIEmitter(program, tcgcSdkContext, options) {
1331
1176
  Object.keys(properties).length === 0) {
1332
1177
  // Take the base model schema but carry across the documentation property
1333
1178
  // that we set before
1334
- const baseSchema = getSchemaForType(model.baseModel, visibility);
1179
+ const baseSchema = getSchemaForType(model.baseModel, schemaContext);
1335
1180
  Object.assign(modelSchema, baseSchema, { description: modelSchema.description });
1336
1181
  }
1337
1182
  else if (model.baseModel) {
1338
- const baseSchema = getSchemaOrRef(model.baseModel, visibility);
1183
+ const baseSchema = getSchemaOrRef(model.baseModel, schemaContext);
1339
1184
  modelSchema.allOf = [baseSchema];
1340
1185
  }
1341
1186
  if (Object.keys(properties).length > 0) {
@@ -1357,7 +1202,7 @@ function createOAPIEmitter(program, tcgcSdkContext, options) {
1357
1202
  }
1358
1203
  return true;
1359
1204
  }
1360
- function resolveProperty(prop, visibility) {
1205
+ function resolveProperty(prop, context) {
1361
1206
  let propSchema;
1362
1207
  if (prop.type.kind === "Enum" && prop.default) {
1363
1208
  propSchema = getSchemaForEnum(prop.type);
@@ -1368,11 +1213,11 @@ function createOAPIEmitter(program, tcgcSdkContext, options) {
1368
1213
  propSchema = getSchemaForUnionEnum(prop.type, asEnum);
1369
1214
  }
1370
1215
  else {
1371
- propSchema = getSchemaOrRef(prop.type, visibility);
1216
+ propSchema = getSchemaOrRef(prop.type, context);
1372
1217
  }
1373
1218
  }
1374
1219
  else {
1375
- propSchema = getSchemaOrRef(prop.type, visibility);
1220
+ propSchema = getSchemaOrRef(prop.type, context);
1376
1221
  }
1377
1222
  return applyIntrinsicDecorators(prop, propSchema);
1378
1223
  }
@@ -1492,7 +1337,7 @@ function createOAPIEmitter(program, tcgcSdkContext, options) {
1492
1337
  }
1493
1338
  }
1494
1339
  if (typespecType.kind === "ModelProperty" &&
1495
- shouldFlattenProperty(tcgcSdkContext, typespecType)) {
1340
+ shouldFlattenProperty(context.tcgcSdkContext, typespecType)) {
1496
1341
  newTarget["x-ms-client-flatten"] = true;
1497
1342
  }
1498
1343
  attachExtensions(typespecType, newTarget);
@@ -1603,11 +1448,14 @@ function createOAPIEmitter(program, tcgcSdkContext, options) {
1603
1448
  /**
1604
1449
  * If the model is an array model return the OpenAPI2Schema for the array type.
1605
1450
  */
1606
- function getArrayType(typespecType, visibility) {
1451
+ function getArrayType(typespecType, context) {
1607
1452
  if (isArrayModelType(program, typespecType)) {
1608
1453
  const array = {
1609
1454
  type: "array",
1610
- items: getSchemaOrRef(typespecType.indexer.value, visibility | Visibility.Item),
1455
+ items: getSchemaOrRef(typespecType.indexer.value, {
1456
+ ...context,
1457
+ visibility: context.visibility | Visibility.Item,
1458
+ }),
1611
1459
  };
1612
1460
  if (!ifArrayItemContainsIdentifier(program, typespecType)) {
1613
1461
  array["x-ms-identifiers"] = [];
@@ -1766,7 +1614,7 @@ function createOAPIEmitter(program, tcgcSdkContext, options) {
1766
1614
  reportDiagnostic(program, {
1767
1615
  code: "unsupported-auth",
1768
1616
  format: { authType: auth.type },
1769
- target: currentService.type,
1617
+ target: service.type,
1770
1618
  });
1771
1619
  return undefined;
1772
1620
  }
@@ -1787,9 +1635,6 @@ function createOAPIEmitter(program, tcgcSdkContext, options) {
1787
1635
  }
1788
1636
  }
1789
1637
  }
1790
- function prettierOutput(output) {
1791
- return output + "\n";
1792
- }
1793
1638
  class ErrorTypeFoundError extends Error {
1794
1639
  constructor() {
1795
1640
  super("Error type found in evaluated TypeSpec output");
@@ -1801,24 +1646,71 @@ export function sortOpenAPIDocument(doc) {
1801
1646
  const sorted = sortWithJsonSchema(unsorted, AutorestOpenAPISchema, "#/$defs/AutorestOpenAPISchema");
1802
1647
  return sorted;
1803
1648
  }
1804
- function resolveOutputFile(program, service, multipleServices, options, version) {
1805
- const azureResourceProviderFolder = options.azureResourceProviderFolder;
1806
- if (azureResourceProviderFolder) {
1807
- const info = resolveInfo(program, service.type);
1808
- version = version ?? info?.version ?? "0000-00-00";
1809
- }
1810
- const interpolated = interpolatePath(options.outputFile, {
1811
- "azure-resource-provider-folder": azureResourceProviderFolder,
1812
- "service-name": multipleServices || azureResourceProviderFolder
1813
- ? getNamespaceFullName(service.type)
1814
- : undefined,
1815
- "version-status": azureResourceProviderFolder
1816
- ? version?.includes("preview")
1817
- ? "preview"
1818
- : "stable"
1819
- : undefined,
1820
- version,
1821
- });
1822
- return resolvePath(options.outputDir, interpolated);
1649
+ async function loadExamples(host, options, version) {
1650
+ const diagnostics = createDiagnosticCollector();
1651
+ if (!options.examplesDirectory) {
1652
+ return diagnostics.wrap(new Map());
1653
+ }
1654
+ const exampleDir = version
1655
+ ? resolvePath(options.examplesDirectory, version)
1656
+ : resolvePath(options.examplesDirectory);
1657
+ try {
1658
+ if (!(await host.stat(exampleDir)).isDirectory())
1659
+ return diagnostics.wrap(new Map());
1660
+ }
1661
+ catch (err) {
1662
+ diagnostics.add(createDiagnostic({
1663
+ code: "example-loading",
1664
+ messageId: "noDirectory",
1665
+ format: { directory: exampleDir },
1666
+ target: NoTarget,
1667
+ }));
1668
+ return diagnostics.wrap(new Map());
1669
+ }
1670
+ const map = new Map();
1671
+ const exampleFiles = await host.readDir(exampleDir);
1672
+ for (const fileName of exampleFiles) {
1673
+ try {
1674
+ const exampleFile = await host.readFile(resolvePath(exampleDir, fileName));
1675
+ const example = JSON.parse(exampleFile.text);
1676
+ if (!example.operationId || !example.title) {
1677
+ diagnostics.add(createDiagnostic({
1678
+ code: "example-loading",
1679
+ messageId: "noOperationId",
1680
+ format: { filename: fileName },
1681
+ target: NoTarget,
1682
+ }));
1683
+ continue;
1684
+ }
1685
+ if (!map.has(example.operationId)) {
1686
+ map.set(example.operationId, {});
1687
+ }
1688
+ const examples = map.get(example.operationId);
1689
+ if (example.title in examples) {
1690
+ diagnostics.add(createDiagnostic({
1691
+ code: "duplicate-example-file",
1692
+ target: NoTarget,
1693
+ format: {
1694
+ filename: fileName,
1695
+ operationId: example.operationId,
1696
+ title: example.title,
1697
+ },
1698
+ }));
1699
+ }
1700
+ examples[example.title] = {
1701
+ file: exampleFile,
1702
+ data: example,
1703
+ };
1704
+ }
1705
+ catch (err) {
1706
+ diagnostics.add(createDiagnostic({
1707
+ code: "example-loading",
1708
+ messageId: "default",
1709
+ format: { filename: fileName, error: err?.toString() ?? "" },
1710
+ target: NoTarget,
1711
+ }));
1712
+ }
1713
+ }
1714
+ return diagnostics.wrap(new Map());
1823
1715
  }
1824
1716
  //# sourceMappingURL=openapi.js.map