@azure-tools/typespec-autorest 0.64.0-dev.2 → 0.64.0-dev.3

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,5 +1,5 @@
1
1
  import { FinalStateValue, extractLroStates, getArmResourceIdentifierConfig, getAsEmbeddingVector, getLroMetadata, getUnionAsEnum, hasUniqueItems, } from "@azure-tools/typespec-azure-core";
2
- import { getArmCommonTypeOpenAPIRef, getArmIdentifiers, getArmKeyIdentifiers, getCustomResourceOptions, getExternalTypeRef, getInlineAzureType, isArmCommonType, isArmExternalType, isArmProviderNamespace, isAzureResource, } from "@azure-tools/typespec-azure-resource-manager";
2
+ import { getArmCommonTypeOpenAPIRef, getArmIdentifiers, getArmKeyIdentifiers, getCustomResourceOptions, getExternalTypeRef, getFeature, getInlineAzureType, getResourceFeatureSet, isArmCommonType, isArmExternalType, isArmProviderNamespace, isAzureResource, } from "@azure-tools/typespec-azure-resource-manager";
3
3
  import { getClientDefaultValue, getClientNameOverride, getLegacyHierarchyBuilding, getMarkAsLro, shouldFlattenProperty, } from "@azure-tools/typespec-client-generator-core";
4
4
  import { NoTarget, compilerAssert, createDiagnosticCollector, explainStringTemplateNotSerializable, getAllTags, getAnyExtensionFromPath, getDirectoryPath, getDiscriminator, getDoc, getEncode, getFormat, getLifecycleVisibilityEnum, getMaxItems, getMaxLength, getMaxValue, getMinItems, getMinLength, getMinValue, getNamespaceFullName, getPagingOperation, getPattern, getProperty, getRelativePathFromDirectory, getRootLength, getSummary, getVisibilityForClass, ignoreDiagnostics, interpolatePath, isArrayModelType, isDeprecated, isErrorModel, isErrorType, isGlobalNamespace, isList, isNeverType, isNullType, isNumeric, isRecordModelType, isSecret, isService, isTemplateDeclaration, isTemplateDeclarationOrInstance, isVoidType, joinPaths, navigateTypesInNamespace, normalizePath, reportDeprecated, resolveEncodedName, resolvePath, serializeValueAsJson, } from "@typespec/compiler";
5
5
  import { SyntaxKind } from "@typespec/compiler/ast";
@@ -12,22 +12,12 @@ import { AutorestOpenAPISchema } from "./autorest-openapi-schema.js";
12
12
  import { getExamples, getRef } from "./decorators.js";
13
13
  import { sortWithJsonSchema } from "./json-schema-sorter/sorter.js";
14
14
  import { createDiagnostic, reportDiagnostic } from "./lib.js";
15
+ import { LateBoundReference, } from "./types.js";
15
16
  import { getClientName, isSupportedAutorestFormat, resolveOperationId, } from "./utils.js";
16
17
  import { resolveXmlModule } from "./xml.js";
17
- /**
18
- * Represents a node that will hold a JSON reference. The value is computed
19
- * at the end so that we can defer decisions about the name that is
20
- * referenced.
21
- */
22
- class Ref {
23
- value;
24
- toJSON() {
25
- compilerAssert(this.value, "Reference value never set.");
26
- return this.value;
27
- }
28
- }
29
18
  export async function getOpenAPIForService(context, options) {
30
19
  const { program, service } = context;
20
+ const proxy = context.proxy ?? createDefaultDocumentProxy(program, service, options, context.version);
31
21
  const typeNameOptions = {
32
22
  // shorten type names by removing TypeSpec and service namespace
33
23
  namespaceFilter(ns) {
@@ -35,31 +25,15 @@ export async function getOpenAPIForService(context, options) {
35
25
  },
36
26
  };
37
27
  const httpService = ignoreDiagnostics(getHttpService(program, service.type));
38
- const info = resolveInfo(program, service.type);
28
+ proxy.addAdditionalInfo(resolveInfo(program, service.type));
39
29
  const auth = processAuth(service.type);
30
+ if (auth?.securitySchemes)
31
+ proxy.addSecuritySchemes(auth.securitySchemes);
32
+ if (auth?.security)
33
+ proxy.addSecurityRequirements(auth.security);
40
34
  const xml = await resolveXmlModule();
41
35
  const xmlStrategy = options.xmlStrategy;
42
- const root = {
43
- swagger: "2.0",
44
- info: {
45
- title: "(title)",
46
- ...info,
47
- version: context.version ?? info?.version ?? "0000-00-00",
48
- "x-typespec-generated": [{ emitter: "@azure-tools/typespec-autorest" }],
49
- },
50
- schemes: ["https"],
51
- ...resolveHost(program, service.type),
52
- externalDocs: getExternalDocs(program, service.type),
53
- produces: [], // Pre-initialize produces and consumes so that
54
- consumes: [], // they show up at the top of the document
55
- security: auth?.security,
56
- securityDefinitions: auth?.securitySchemes ?? {},
57
- tags: [],
58
- paths: {},
59
- "x-ms-paths": {},
60
- definitions: {},
61
- parameters: {},
62
- };
36
+ proxy.addHostInfo(resolveHost(program, service.type));
63
37
  let currentEndpoint;
64
38
  let currentConsumes;
65
39
  let currentProduces;
@@ -84,8 +58,6 @@ export async function getOpenAPIForService(context, options) {
84
58
  // - Models that have had properties spread into parameters.
85
59
  // - Multipart models
86
60
  const indirectlyProcessedTypes = new Set();
87
- // De-dupe the per-endpoint tags that will be added into the #/tags
88
- const tags = new Set();
89
61
  const operationIdsWithExample = new Set();
90
62
  const [exampleMap, diagnostics] = await loadExamples(program, options, context.version);
91
63
  program.reportDiagnostics(diagnostics);
@@ -120,45 +92,10 @@ export async function getOpenAPIForService(context, options) {
120
92
  routes.forEach(emitOperation);
121
93
  emitParameters();
122
94
  emitSchemas(service.type);
123
- emitTags();
124
- // Finalize global produces/consumes
125
- if (globalProduces.size > 0) {
126
- root.produces = [...globalProduces.values()];
127
- }
128
- else {
129
- delete root.produces;
130
- }
131
- if (globalConsumes.size > 0) {
132
- root.consumes = [...globalConsumes.values()];
133
- }
134
- else {
135
- delete root.consumes;
136
- }
137
- // Clean up empty entries
138
- if (root["x-ms-paths"] && Object.keys(root["x-ms-paths"]).length === 0) {
139
- delete root["x-ms-paths"];
140
- }
141
- if (root.security && Object.keys(root.security).length === 0) {
142
- delete root["security"];
143
- }
144
- if (root.securityDefinitions && Object.keys(root.securityDefinitions).length === 0) {
145
- delete root["securityDefinitions"];
146
- }
147
- return {
148
- document: root,
149
- operationExamples: [...operationIdsWithExample]
150
- .map((operationId) => {
151
- const data = exampleMap.get(operationId);
152
- if (data) {
153
- return { operationId, examples: Object.values(data) };
154
- }
155
- else {
156
- return undefined;
157
- }
158
- })
159
- .filter((x) => x),
160
- outputFile: context.outputFile,
161
- };
95
+ proxy.setGlobalConsumes([...globalConsumes]);
96
+ proxy.setGlobalProduces([...globalProduces]);
97
+ proxy.writeExamples(exampleMap, operationIdsWithExample);
98
+ return proxy.resolveDocuments(context);
162
99
  function resolveHost(program, namespace) {
163
100
  const servers = getServers(program, namespace);
164
101
  if (servers === undefined) {
@@ -238,13 +175,6 @@ export async function getOpenAPIForService(context, options) {
238
175
  }
239
176
  return undefined;
240
177
  }
241
- function requiresXMsPaths(path, operation) {
242
- const isShared = isSharedRoute(program, operation) ?? false;
243
- if (path.includes("?")) {
244
- return true;
245
- }
246
- return isShared;
247
- }
248
178
  function getFinalStateVia(metadata) {
249
179
  switch (metadata.finalStateVia) {
250
180
  case FinalStateValue.azureAsyncOperation:
@@ -266,65 +196,31 @@ export async function getOpenAPIForService(context, options) {
266
196
  const model = metadata.finalResult;
267
197
  const schemaOrRef = resolveExternalRef(metadata.finalResult);
268
198
  if (schemaOrRef !== undefined) {
269
- const ref = new Ref();
270
- ref.value = schemaOrRef.$ref;
199
+ const ref = proxy.createExternalRef(schemaOrRef.$ref);
271
200
  return { "final-state-schema": ref };
272
201
  }
273
202
  const pending = pendingSchemas.getOrAdd(metadata.finalResult, Visibility.Read, () => ({
274
203
  type: model,
275
204
  visibility: Visibility.Read,
276
- ref: refs.getOrAdd(model, Visibility.Read, () => new Ref()),
205
+ ref: refs.getOrAdd(model, Visibility.Read, () => proxy.createLocalRef(model)),
277
206
  }));
278
207
  return { "final-state-schema": pending.ref };
279
208
  }
280
209
  return undefined;
281
210
  }
282
- /** Initialize the openapi PathItem object where this operation should be added. */
283
- function initPathItem(operation) {
284
- let { path, operation: op, verb } = operation;
285
- let pathsObject = root.paths;
286
- if (root.paths[path]?.[verb] === undefined && !path.includes("?")) {
287
- pathsObject = root.paths;
288
- }
289
- else if (requiresXMsPaths(path, op)) {
290
- // if the key already exists in x-ms-paths, append the operation id.
291
- if (path.includes("?")) {
292
- if (root["x-ms-paths"]?.[path] !== undefined) {
293
- path += `&_overload=${operation.operation.name}`;
294
- }
295
- }
296
- else {
297
- path += `?_overload=${operation.operation.name}`;
298
- }
299
- pathsObject = root["x-ms-paths"];
300
- }
301
- else {
302
- // This should not happen because http library should have already validated duplicate path or the routes must have been using shared routes and so goes in previous condition.
303
- compilerAssert(false, `Duplicate route "${path}". This is unexpected.`);
304
- }
305
- if (!pathsObject[path]) {
306
- pathsObject[path] = {};
307
- }
308
- return pathsObject[path];
309
- }
310
211
  function emitOperation(operation) {
311
212
  const { operation: op, verb, parameters } = operation;
312
- const currentPath = initPathItem(operation);
313
- if (!currentPath[verb]) {
314
- currentPath[verb] = {};
315
- }
316
- currentEndpoint = currentPath[verb];
213
+ currentEndpoint = proxy.createOrGetEndpoint(operation, context);
317
214
  currentConsumes = new Set();
318
215
  currentProduces = new Set();
319
216
  const currentTags = getAllTags(program, op);
320
217
  if (currentTags) {
321
- currentEndpoint.tags = currentTags;
218
+ currentEndpoint.tags = [...currentTags.values()];
322
219
  for (const tag of currentTags) {
323
220
  // Add to root tags if not already there
324
- tags.add(tag);
221
+ proxy.addTag(tag, op);
325
222
  }
326
223
  }
327
- currentEndpoint.operationId = resolveOperationId(context, op);
328
224
  applyExternalDocs(op, currentEndpoint);
329
225
  // Set up basic endpoint fields
330
226
  currentEndpoint.summary = getSummary(program, op);
@@ -637,7 +533,7 @@ export async function getOpenAPIForService(context, options) {
637
533
  const pending = pendingSchemas.getOrAdd(type, schemaContext.visibility, () => ({
638
534
  type,
639
535
  visibility: schemaContext.visibility,
640
- ref: refs.getOrAdd(type, schemaContext.visibility, () => new Ref()),
536
+ ref: refs.getOrAdd(type, schemaContext.visibility, () => proxy.createLocalRef(type)),
641
537
  getSchemaNameOverride: schemaNameOverride,
642
538
  }));
643
539
  return { $ref: pending.ref };
@@ -1022,8 +918,8 @@ export async function getOpenAPIForService(context, options) {
1022
918
  if (param["x-ms-parameter-location"] === undefined) {
1023
919
  param["x-ms-parameter-location"] = "method";
1024
920
  }
1025
- const key = getParameterKey(program, property, param, root.parameters, typeNameOptions);
1026
- root.parameters[key] = { ...param };
921
+ const key = getParameterKey(program, property, param, proxy.getParameterMap(), typeNameOptions);
922
+ proxy.writeParameter(key, property, param);
1027
923
  const refedParam = param;
1028
924
  for (const key of Object.keys(param)) {
1029
925
  delete refedParam[key];
@@ -1052,12 +948,12 @@ export async function getOpenAPIForService(context, options) {
1052
948
  else if (group.size > 1) {
1053
949
  name += getVisibilitySuffix(visibility, Visibility.Read);
1054
950
  }
1055
- checkDuplicateTypeName(program, processed.type, name, root.definitions);
1056
- processed.ref.value = "#/definitions/" + encodeURIComponent(name);
951
+ checkDuplicateTypeName(program, processed.type, name, proxy.getDefinitionMap());
952
+ processed.ref.setLocalValue(program, encodeURIComponent(name), processed.type);
1057
953
  if (processed.schema) {
1058
954
  if (shouldEmitXml)
1059
955
  attachXml(processed.type, name, processed);
1060
- root.definitions[name] = processed.schema;
956
+ proxy.writeDefinition(name, processed, processed.schema);
1061
957
  }
1062
958
  }
1063
959
  }
@@ -1114,11 +1010,6 @@ export async function getOpenAPIForService(context, options) {
1114
1010
  }
1115
1011
  return false;
1116
1012
  }
1117
- function emitTags() {
1118
- for (const tag of tags) {
1119
- root.tags.push({ name: tag });
1120
- }
1121
- }
1122
1013
  function getSchemaForType(type, schemaContext, namespace) {
1123
1014
  const builtinType = getSchemaForLiterals(type);
1124
1015
  if (builtinType !== undefined) {
@@ -2204,4 +2095,394 @@ async function loadExamples(program, options, version) {
2204
2095
  function isHttpParameterProperty(httpProperty) {
2205
2096
  return ["header", "query", "path", "cookie"].includes(httpProperty.kind);
2206
2097
  }
2098
+ export function createDocumentProxy(program, service, options, version) {
2099
+ const features = getResourceFeatureSet(program, service.type);
2100
+ if (options.outputSplitting === undefined ||
2101
+ options.outputSplitting !== "legacy-feature-files" ||
2102
+ features === undefined ||
2103
+ features.size < 2) {
2104
+ return createDefaultDocumentProxy(program, service, options, version);
2105
+ }
2106
+ else {
2107
+ return createFeatureDocumentProxy(program, service, options, version);
2108
+ }
2109
+ }
2110
+ export function createDefaultDocumentProxy(program, service, options, version) {
2111
+ const root = initializeOpenApi2Document(program, service, version);
2112
+ const tags = new Set();
2113
+ const definitions = new Map();
2114
+ const parameters = new Map();
2115
+ let examples = new Map();
2116
+ let operationIdsWithExamples = new Set();
2117
+ return {
2118
+ getDefinitionMap() {
2119
+ const result = {};
2120
+ for (const [name, schema] of definitions) {
2121
+ result[name] = schema;
2122
+ }
2123
+ return result;
2124
+ },
2125
+ writeDefinition: (name, processed, schema) => {
2126
+ definitions.set(name, schema);
2127
+ },
2128
+ getParameterMap() {
2129
+ const result = {};
2130
+ for (const [name, [_, parameter]] of parameters) {
2131
+ result[name] = parameter;
2132
+ }
2133
+ return result;
2134
+ },
2135
+ writeParameter(key, prop, parameter) {
2136
+ parameters.set(key, [prop, parameter]);
2137
+ let defaultParameters = root.parameters;
2138
+ if (defaultParameters === undefined) {
2139
+ defaultParameters = {};
2140
+ root.parameters = defaultParameters;
2141
+ }
2142
+ defaultParameters[key] = { ...parameter };
2143
+ },
2144
+ createOrGetEndpoint(op, context) {
2145
+ const pathItem = initPathItem(program, op, root);
2146
+ if (!pathItem[op.verb]) {
2147
+ pathItem[op.verb] = { parameters: [] };
2148
+ }
2149
+ const resolvedOp = pathItem[op.verb];
2150
+ resolvedOp.operationId = resolveOperationId(context, op.operation);
2151
+ return resolvedOp;
2152
+ },
2153
+ addTag(tag, op) {
2154
+ tags.add(tag);
2155
+ },
2156
+ setGlobalConsumes(consumes) {
2157
+ root.consumes = consumes;
2158
+ },
2159
+ setGlobalProduces(produces) {
2160
+ root.produces = produces;
2161
+ },
2162
+ addAdditionalInfo(info) {
2163
+ if (info !== undefined) {
2164
+ Object.assign(root.info, info);
2165
+ }
2166
+ },
2167
+ addHostInfo(hostInfo) {
2168
+ Object.assign(root, hostInfo);
2169
+ },
2170
+ addSecurityRequirements(requirements) {
2171
+ if (requirements !== undefined && requirements.length > 0) {
2172
+ root.security = requirements;
2173
+ }
2174
+ },
2175
+ addSecuritySchemes(schemes) {
2176
+ if (schemes !== undefined && Object.keys(schemes).length > 0) {
2177
+ root.securityDefinitions = schemes;
2178
+ }
2179
+ },
2180
+ writeExamples(inExamples, exampleIds) {
2181
+ examples = inExamples;
2182
+ operationIdsWithExamples = exampleIds;
2183
+ },
2184
+ resolveDocuments(context) {
2185
+ root.definitions = {};
2186
+ for (const [name, schema] of definitions) {
2187
+ root.definitions[name] = schema;
2188
+ }
2189
+ finalizeOpenApi2Document(root, tags);
2190
+ return Promise.resolve([
2191
+ {
2192
+ document: root,
2193
+ operationExamples: [...operationIdsWithExamples]
2194
+ .map((operationId) => {
2195
+ const data = examples.get(operationId);
2196
+ if (data) {
2197
+ return { operationId, examples: Object.values(data) };
2198
+ }
2199
+ else {
2200
+ return undefined;
2201
+ }
2202
+ })
2203
+ .filter((x) => x),
2204
+ outputFile: context.outputFile,
2205
+ context: context,
2206
+ },
2207
+ ]);
2208
+ },
2209
+ createLocalRef(type) {
2210
+ const feature = getFeature(program, type);
2211
+ const result = new LateBoundReference();
2212
+ result.file = feature.fileName;
2213
+ return result;
2214
+ },
2215
+ createExternalRef(absoluteRef) {
2216
+ const result = new LateBoundReference();
2217
+ result.setRemoteValue(absoluteRef);
2218
+ return result;
2219
+ },
2220
+ getCurrentFeature() {
2221
+ return undefined;
2222
+ },
2223
+ setCurrentFeature(feature) {
2224
+ return;
2225
+ },
2226
+ getParameterRef(key) {
2227
+ return `#/parameters/${encodeURIComponent(key)}`;
2228
+ },
2229
+ };
2230
+ }
2231
+ function createFeatureDocumentProxy(program, service, options, version) {
2232
+ const features = getResourceFeatureSet(program, service.type);
2233
+ if (features === undefined || features.size < 2)
2234
+ return createDefaultDocumentProxy(program, service, options, version);
2235
+ const root = new Map();
2236
+ const operationFeatures = new Map();
2237
+ let examples = new Map();
2238
+ let operationIdsWithExamples = new Set();
2239
+ for (const featureName of features.keys()) {
2240
+ const featureOptions = features.get(featureName);
2241
+ root.set(featureName.toLowerCase(), initializeOpenAPIDocumentItem(program, service, featureOptions, version));
2242
+ }
2243
+ const defaultFeature = [...root.entries()].filter(([key, _]) => key.toLowerCase() === "common")[0][1];
2244
+ const definitions = new Map();
2245
+ const resolvedParameters = new Map();
2246
+ let currentFeature = "";
2247
+ return {
2248
+ getDefinitionMap() {
2249
+ const result = {};
2250
+ for (const [name, [_, schema]] of definitions) {
2251
+ result[name] = schema;
2252
+ }
2253
+ return result;
2254
+ },
2255
+ writeDefinition: (name, processed, schema) => {
2256
+ const feature = getFeatureKey(program, processed.type);
2257
+ definitions.set(name, [feature, schema]);
2258
+ },
2259
+ getParameterMap() {
2260
+ const result = {};
2261
+ for (const [name, [_, parameter]] of resolvedParameters) {
2262
+ result[name] = parameter;
2263
+ }
2264
+ return result;
2265
+ },
2266
+ writeParameter(key, prop, parameter) {
2267
+ resolvedParameters.set(key, [prop, parameter]);
2268
+ let defaultParameters = defaultFeature.document.parameters;
2269
+ if (defaultParameters === undefined) {
2270
+ defaultParameters = {};
2271
+ defaultFeature.document.parameters = defaultParameters;
2272
+ }
2273
+ defaultParameters[key] = { ...parameter };
2274
+ },
2275
+ createOrGetEndpoint(op, context) {
2276
+ const options = getFeature(program, op.operation);
2277
+ const item = root.get(options.featureName.toLowerCase());
2278
+ const pathItem = initPathItem(program, op, item.document);
2279
+ if (!pathItem[op.verb]) {
2280
+ pathItem[op.verb] = { parameters: [] };
2281
+ }
2282
+ const resolvedOp = pathItem[op.verb];
2283
+ const opId = resolveOperationId(context, op.operation);
2284
+ addFeatureOperation(opId, options.featureName);
2285
+ resolvedOp.operationId = opId;
2286
+ return resolvedOp;
2287
+ },
2288
+ setGlobalConsumes(mimeTypes) {
2289
+ for (const featureItem of root.values()) {
2290
+ featureItem.document.consumes = [];
2291
+ for (const mimeType of mimeTypes) {
2292
+ featureItem.document.consumes.push(mimeType);
2293
+ }
2294
+ }
2295
+ },
2296
+ setGlobalProduces(mimeTypes) {
2297
+ for (const featureItem of root.values()) {
2298
+ featureItem.document.produces = [];
2299
+ for (const mimeType of mimeTypes) {
2300
+ featureItem.document.produces.push(mimeType);
2301
+ }
2302
+ }
2303
+ },
2304
+ addTag(tag, op) {
2305
+ const feature = getFeatureKey(program, op);
2306
+ const item = root.get(feature);
2307
+ item.tags.add(tag);
2308
+ },
2309
+ addAdditionalInfo(info) {
2310
+ if (info !== undefined) {
2311
+ for (const featureItem of root.values())
2312
+ Object.assign(featureItem.document.info, info);
2313
+ }
2314
+ },
2315
+ addHostInfo(hostInfo) {
2316
+ for (const featureItem of root.values())
2317
+ Object.assign(featureItem.document, hostInfo);
2318
+ },
2319
+ addSecurityRequirements(requirements) {
2320
+ if (requirements !== undefined && requirements.length > 0) {
2321
+ for (const featureItem of root.values())
2322
+ featureItem.document.security = requirements;
2323
+ }
2324
+ },
2325
+ addSecuritySchemes(schemes) {
2326
+ if (schemes !== undefined && Object.keys(schemes).length > 0) {
2327
+ for (const featureItem of root.values())
2328
+ featureItem.document.securityDefinitions = schemes;
2329
+ }
2330
+ },
2331
+ writeExamples(inExamples, exampleIds) {
2332
+ examples = inExamples;
2333
+ operationIdsWithExamples = exampleIds;
2334
+ },
2335
+ resolveDocuments(context) {
2336
+ const docs = [];
2337
+ for (const [featureName, featureItem] of root.entries()) {
2338
+ const exampleIds = operationFeatures.get(featureName) || new Set();
2339
+ const featureExamples = [...exampleIds]
2340
+ .filter((id) => operationIdsWithExamples.has(id))
2341
+ .map((operationId) => {
2342
+ const data = examples.get(operationId);
2343
+ if (data) {
2344
+ return { operationId, examples: Object.values(data) };
2345
+ }
2346
+ else {
2347
+ return undefined;
2348
+ }
2349
+ })
2350
+ .filter((x) => x);
2351
+ const definitionsForFeature = Array.from(definitions.entries()).filter(([_, [definitionFeature, __]]) => definitionFeature === featureName);
2352
+ featureItem.document.definitions = {};
2353
+ for (const [defName, [_, defSchema]] of definitionsForFeature) {
2354
+ featureItem.document.definitions[defName] = defSchema;
2355
+ }
2356
+ finalizeOpenApi2Document(featureItem.document, featureItem.tags);
2357
+ docs.push({
2358
+ document: featureItem.document,
2359
+ operationExamples: featureExamples,
2360
+ outputFile: context.outputFile,
2361
+ feature: featureItem.options.fileName,
2362
+ context: context,
2363
+ });
2364
+ }
2365
+ // Collect operation examples for this feature
2366
+ return Promise.resolve(docs);
2367
+ },
2368
+ createLocalRef(type) {
2369
+ const feature = getFeature(program, type);
2370
+ currentFeature = feature.featureName;
2371
+ const result = new LateBoundReference();
2372
+ result.useFeatures = true;
2373
+ result.file = feature.fileName;
2374
+ result.getFileContext = () => this.getCurrentFeature();
2375
+ return result;
2376
+ },
2377
+ createExternalRef(absoluteRef) {
2378
+ const result = new LateBoundReference();
2379
+ result.setRemoteValue(absoluteRef);
2380
+ return result;
2381
+ },
2382
+ getCurrentFeature() {
2383
+ return currentFeature;
2384
+ },
2385
+ setCurrentFeature(feature) {
2386
+ currentFeature = feature;
2387
+ },
2388
+ getParameterRef(key) {
2389
+ return `./common.json/parameters/${encodeURIComponent(key)}`;
2390
+ },
2391
+ };
2392
+ function getFeatureKey(program, type) {
2393
+ const feature = getFeature(program, type);
2394
+ return feature.featureName.toLowerCase();
2395
+ }
2396
+ function addFeatureOperation(operationId, featureName) {
2397
+ featureName = featureName.toLowerCase();
2398
+ if (!operationFeatures.has(featureName)) {
2399
+ operationFeatures.set(featureName, new Set([operationId]));
2400
+ return;
2401
+ }
2402
+ const ops = operationFeatures.get(featureName);
2403
+ ops.add(operationId);
2404
+ }
2405
+ }
2406
+ function initializeOpenAPIDocumentItem(program, service, options, version) {
2407
+ return {
2408
+ document: initializeOpenApi2Document(program, service, version),
2409
+ operationExamples: new Map(),
2410
+ tags: new Set(),
2411
+ options,
2412
+ };
2413
+ }
2414
+ function initializeOpenApi2Document(program, service, version) {
2415
+ return {
2416
+ swagger: "2.0",
2417
+ info: {
2418
+ title: "(title)",
2419
+ version: version ?? "0000-00-00",
2420
+ "x-typespec-generated": [{ emitter: "@azure-tools/typespec-autorest" }],
2421
+ },
2422
+ schemes: ["https"],
2423
+ externalDocs: getExternalDocs(program, service.type),
2424
+ produces: [], // Pre-initialize produces and consumes so that
2425
+ consumes: [], // they show up at the top of the document
2426
+ tags: [],
2427
+ paths: {},
2428
+ "x-ms-paths": {},
2429
+ definitions: {},
2430
+ parameters: {},
2431
+ };
2432
+ }
2433
+ function finalizeOpenApi2Document(root, tags) {
2434
+ const xMsPaths = root["x-ms-paths"];
2435
+ if (xMsPaths && Object.keys(xMsPaths).length === 0) {
2436
+ delete root["x-ms-paths"];
2437
+ }
2438
+ const rootSecurity = root.security;
2439
+ if (rootSecurity && Object.keys(rootSecurity).length === 0) {
2440
+ delete root.security;
2441
+ }
2442
+ const securityDefs = root.securityDefinitions;
2443
+ if (securityDefs && Object.keys(securityDefs).length === 0) {
2444
+ delete root.securityDefinitions;
2445
+ }
2446
+ if (root.consumes !== undefined && root.consumes.length === 0) {
2447
+ delete root.consumes;
2448
+ }
2449
+ if (root.produces !== undefined && root.produces.length === 0) {
2450
+ delete root.produces;
2451
+ }
2452
+ root.tags = Array.from(tags).map((tagName) => ({ name: tagName }));
2453
+ }
2454
+ function initPathItem(program, operation, root) {
2455
+ let { path, operation: op, verb } = operation;
2456
+ let pathsObject = root.paths;
2457
+ if (root.paths[path]?.[verb] === undefined && !path.includes("?")) {
2458
+ pathsObject = root.paths;
2459
+ }
2460
+ else if (requiresXMsPaths(program, path, op)) {
2461
+ // if the key already exists in x-ms-paths, append the operation id.
2462
+ if (path.includes("?")) {
2463
+ if (root["x-ms-paths"]?.[path] !== undefined) {
2464
+ path += `&_overload=${operation.operation.name}`;
2465
+ }
2466
+ }
2467
+ else {
2468
+ path += `?_overload=${operation.operation.name}`;
2469
+ }
2470
+ pathsObject = root["x-ms-paths"];
2471
+ }
2472
+ else {
2473
+ // This should not happen because http library should have already validated duplicate path or the routes must have been using shared routes and so goes in previous condition.
2474
+ compilerAssert(false, `Duplicate route "${path}". This is unexpected.`);
2475
+ }
2476
+ if (!pathsObject[path]) {
2477
+ pathsObject[path] = {};
2478
+ }
2479
+ return pathsObject[path];
2480
+ }
2481
+ function requiresXMsPaths(program, path, operation) {
2482
+ const isShared = isSharedRoute(program, operation) ?? false;
2483
+ if (path.includes("?")) {
2484
+ return true;
2485
+ }
2486
+ return isShared;
2487
+ }
2207
2488
  //# sourceMappingURL=openapi.js.map