microsoft/typespec

Public

mirrored from https://github.com/microsoft/typespecAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
4d92e0825d81d6432d29b0fade7b161a2e2aafb7

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

packages/openapi/src/helpers.ts

137lines · modecode

1import {
2 getFriendlyName,
3 getServiceNamespace,
4 isTemplateInstance,
5 ModelTypeProperty,
6 OperationType,
7 Program,
8 Type,
9 TypeNameOptions,
10} from "@cadl-lang/compiler";
11import { getOperationId } from "./decorators.js";
12import { reportDiagnostic } from "./lib.js";
13
14/**
15 * Determines whether a type will be inlined in OpenAPI rather than defined
16 * as a schema and referenced.
17 *
18 * All anonymous types (anonymous models, arrays, tuples, etc.) are inlined.
19 *
20 * Template instantiations are inlined unless they have a friendly name.
21 *
22 * A friendly name can be provided by the user using `@friendlyName`
23 * decorator, or chosen by default in simple cases.
24 */
25export function shouldInline(program: Program, type: Type): boolean {
26 if (getFriendlyName(program, type)) {
27 return false;
28 }
29 switch (type.kind) {
30 case "Model":
31 return (
32 !type.name ||
33 isTemplateInstance(type) ||
34 program.checker.isStdType(type, "Array") ||
35 program.checker.isStdType(type, "Record")
36 );
37 case "Enum":
38 case "Union":
39 return !type.name;
40 default:
41 return true;
42 }
43}
44
45/**
46 * Gets the name of a type to be used in OpenAPI.
47 *
48 * For inlined types: this is the Cadl-native name written to `x-cadl-name`.
49 *
50 * For non-inlined types: this is either the friendly name or the Cadl-native name.
51 *
52 * Cadl-native names are shortened to exclude root `Cadl` namespace and service
53 * namespace using the provided `TypeNameOptions`.
54 */
55export function getTypeName(
56 program: Program,
57 type: Type,
58 options: TypeNameOptions,
59 existing?: Record<string, any>
60): string {
61 const name = getFriendlyName(program, type) ?? program.checker.getTypeName(type, options);
62
63 if (existing && existing[name]) {
64 reportDiagnostic(program, {
65 code: "duplicate-type-name",
66 format: {
67 value: name,
68 },
69 target: type,
70 });
71 }
72
73 return name;
74}
75
76/**
77 * Gets the key that is used to define a parameter in OpenAPI.
78 */
79export function getParameterKey(
80 program: Program,
81 propery: ModelTypeProperty,
82 newParam: unknown,
83 existingParams: Record<string, unknown>,
84 options: TypeNameOptions
85): string {
86 const parent = propery.model!;
87 let key = getTypeName(program, parent, options);
88
89 if (parent.properties.size > 1) {
90 key += `.${propery.name}`;
91 }
92
93 // JSON check is workaround for https://github.com/microsoft/cadl/issues/462
94 if (existingParams[key] && JSON.stringify(newParam) !== JSON.stringify(existingParams[key])) {
95 reportDiagnostic(program, {
96 code: "duplicate-type-name",
97 messageId: "parameter",
98 format: {
99 value: key,
100 },
101 target: propery,
102 });
103 }
104
105 return key;
106}
107
108/**
109 * Resolve the OpenAPI operation ID for the given operation using the following logic:
110 * - If @operationId was specified use that value
111 * - If operation is defined at the root or under the service namespace return <operation.name>
112 * - Otherwise(operation is under another namespace or interface) return <namespace/interface.name>_<opration.name>
113 *
114 * @param program Cadl Program
115 * @param operation Operation
116 * @returns Operation ID in this format <name> or <group>_<name>
117 */
118export function resolveOperationId(program: Program, operation: OperationType) {
119 const explicitOperationId = getOperationId(program, operation);
120 if (explicitOperationId) {
121 return explicitOperationId;
122 }
123
124 if (operation.interface) {
125 return `${operation.interface.name}_${operation.name}`;
126 }
127 const namespace = operation.namespace;
128 if (
129 namespace === undefined ||
130 namespace === program.checker.getGlobalNamespaceType() ||
131 namespace === getServiceNamespace(program)
132 ) {
133 return operation.name;
134 }
135
136 return `${namespace.name}_${operation.name}`;
137}
138