@orval/angular 8.3.0 → 8.4.0
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.
- package/dist/index.mjs +98 -39
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -3
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { generateFormDataAndUrlEncodedFunction, generateMutatorConfig, generateMutatorRequestOptions, generateOptions, generateVerbImports, getDefaultContentType, isBoolean, pascal, sanitize, toObjectString } from "@orval/core";
|
|
1
|
+
import { generateFormDataAndUrlEncodedFunction, generateMutatorConfig, generateMutatorRequestOptions, generateOptions, generateVerbImports, getAngularFilteredParamsCallExpression, getAngularFilteredParamsHelperBody, getDefaultContentType, isBoolean, pascal, sanitize, toObjectString } from "@orval/core";
|
|
2
2
|
|
|
3
3
|
//#region src/index.ts
|
|
4
4
|
const ANGULAR_DEPENDENCIES = [
|
|
@@ -8,7 +8,10 @@ const ANGULAR_DEPENDENCIES = [
|
|
|
8
8
|
name: "HttpClient",
|
|
9
9
|
values: true
|
|
10
10
|
},
|
|
11
|
-
{
|
|
11
|
+
{
|
|
12
|
+
name: "HttpHeaders",
|
|
13
|
+
values: true
|
|
14
|
+
},
|
|
12
15
|
{ name: "HttpParams" },
|
|
13
16
|
{ name: "HttpContext" },
|
|
14
17
|
{
|
|
@@ -35,24 +38,21 @@ const ANGULAR_DEPENDENCIES = [
|
|
|
35
38
|
values: true
|
|
36
39
|
}],
|
|
37
40
|
dependency: "rxjs"
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
exports: [{ name: "DeepNonNullable" }],
|
|
41
|
-
dependency: "@orval/core"
|
|
42
41
|
}
|
|
43
42
|
];
|
|
44
|
-
const
|
|
45
|
-
const getAngularDependencies = () => ANGULAR_DEPENDENCIES;
|
|
43
|
+
const getAngularDependencies = () => [...ANGULAR_DEPENDENCIES];
|
|
46
44
|
const generateAngularTitle = (title) => {
|
|
47
45
|
return `${pascal(sanitize(title))}Service`;
|
|
48
46
|
};
|
|
49
|
-
const
|
|
47
|
+
const createAngularHeader = () => ({ title, isRequestOptions, isMutator, isGlobalMutator, provideIn, verbOptions, tag }) => {
|
|
48
|
+
const hasQueryParams = (tag ? Object.values(verbOptions).filter((v) => v.tags.includes(tag)) : Object.values(verbOptions)).some((v) => v.queryParams);
|
|
49
|
+
return `
|
|
50
50
|
${isRequestOptions && !isGlobalMutator ? `interface HttpClientOptions {
|
|
51
51
|
headers?: HttpHeaders | Record<string, string | string[]>;
|
|
52
52
|
context?: HttpContext;
|
|
53
53
|
params?:
|
|
54
54
|
| HttpParams
|
|
55
|
-
|
|
55
|
+
| Record<string, string | number | boolean | Array<string | number | boolean>>;
|
|
56
56
|
reportProgress?: boolean;
|
|
57
57
|
withCredentials?: boolean;
|
|
58
58
|
credentials?: RequestCredentials;
|
|
@@ -63,9 +63,11 @@ ${isRequestOptions && !isGlobalMutator ? `interface HttpClientOptions {
|
|
|
63
63
|
redirect?: RequestRedirect;
|
|
64
64
|
referrer?: string;
|
|
65
65
|
integrity?: string;
|
|
66
|
+
referrerPolicy?: ReferrerPolicy;
|
|
66
67
|
transferCache?: {includeHeaders?: string[]} | boolean;
|
|
67
|
-
|
|
68
|
-
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
${hasQueryParams ? getAngularFilteredParamsHelperBody() : ""}` : ""}
|
|
69
71
|
|
|
70
72
|
${isRequestOptions && isMutator ? `// eslint-disable-next-line
|
|
71
73
|
type ThirdParameter<T extends (...args: any) => any> = T extends (
|
|
@@ -80,12 +82,16 @@ ${isRequestOptions && isMutator ? `// eslint-disable-next-line
|
|
|
80
82
|
export class ${title} {
|
|
81
83
|
private readonly http = inject(HttpClient);
|
|
82
84
|
`;
|
|
83
|
-
|
|
85
|
+
};
|
|
86
|
+
const generateAngularHeader = (params) => createAngularHeader()(params);
|
|
87
|
+
const standaloneFooterReturnTypesToWrite = /* @__PURE__ */ new Map();
|
|
88
|
+
const createAngularFooter = (returnTypesToWrite) => ({ operationNames }) => {
|
|
84
89
|
let footer = "};\n\n";
|
|
85
90
|
for (const operationName of operationNames) if (returnTypesToWrite.has(operationName)) footer += returnTypesToWrite.get(operationName) + "\n";
|
|
86
91
|
return footer;
|
|
87
92
|
};
|
|
88
|
-
const
|
|
93
|
+
const generateAngularFooter = (params) => createAngularFooter(standaloneFooterReturnTypesToWrite)(params);
|
|
94
|
+
const generateImplementation = (returnTypesToWrite, { headers, queryParams, operationName, response, mutator, body, props, verb, override, formData, formUrlEncoded, paramsSerializer }, { route, context }) => {
|
|
89
95
|
const isRequestOptions = override.requestOptions !== false;
|
|
90
96
|
const isFormData = !override.formData.disabled;
|
|
91
97
|
const isFormUrlEncoded = override.formUrlEncoded !== false;
|
|
@@ -110,7 +116,8 @@ const generateImplementation = ({ headers, queryParams, operationName, response,
|
|
|
110
116
|
isFormData,
|
|
111
117
|
isFormUrlEncoded,
|
|
112
118
|
hasSignal: false,
|
|
113
|
-
isExactOptionalPropertyTypes
|
|
119
|
+
isExactOptionalPropertyTypes,
|
|
120
|
+
isAngular: true
|
|
114
121
|
});
|
|
115
122
|
const requestOptions = isRequestOptions ? generateMutatorRequestOptions(override.requestOptions, mutator.hasThirdArg) : "";
|
|
116
123
|
return ` ${operationName}<TData = ${dataType}>(\n ${mutator.bodyTypeName && body.definition ? toObjectString(props, "implementation").replace(new RegExp(String.raw`(\w*):\s?${body.definition}`), `$1: ${mutator.bodyTypeName}<${body.definition}>`) : toObjectString(props, "implementation")}\n ${isRequestOptions && mutator.hasThirdArg ? `options?: ThirdParameter<typeof ${mutator.name}>` : ""}) {${bodyForm}
|
|
@@ -121,7 +128,7 @@ const generateImplementation = ({ headers, queryParams, operationName, response,
|
|
|
121
128
|
}
|
|
122
129
|
`;
|
|
123
130
|
}
|
|
124
|
-
const
|
|
131
|
+
const optionsBase = {
|
|
125
132
|
route,
|
|
126
133
|
body,
|
|
127
134
|
headers,
|
|
@@ -136,13 +143,42 @@ const generateImplementation = ({ headers, queryParams, operationName, response,
|
|
|
136
143
|
isAngular: true,
|
|
137
144
|
isExactOptionalPropertyTypes,
|
|
138
145
|
hasSignal: false
|
|
139
|
-
}
|
|
146
|
+
};
|
|
140
147
|
const propsDefinition = toObjectString(props, "definition");
|
|
141
148
|
const successTypes = response.types.success;
|
|
142
149
|
const uniqueContentTypes = [...new Set(successTypes.map((t) => t.contentType).filter(Boolean))];
|
|
143
150
|
const hasMultipleContentTypes = uniqueContentTypes.length > 1;
|
|
144
|
-
const
|
|
145
|
-
const
|
|
151
|
+
const needsObserveBranching = isRequestOptions && !hasMultipleContentTypes;
|
|
152
|
+
const angularParamsRef = needsObserveBranching && queryParams ? "filteredParams" : void 0;
|
|
153
|
+
let paramsDeclaration = "";
|
|
154
|
+
if (angularParamsRef && queryParams) {
|
|
155
|
+
const callExpr = getAngularFilteredParamsCallExpression("{...params, ...options?.params}", queryParams.requiredNullableKeys ?? []);
|
|
156
|
+
paramsDeclaration = paramsSerializer ? `const ${angularParamsRef} = ${paramsSerializer.name}(${callExpr});\n\n ` : `const ${angularParamsRef} = ${callExpr};\n\n `;
|
|
157
|
+
}
|
|
158
|
+
const options = generateOptions({
|
|
159
|
+
...optionsBase,
|
|
160
|
+
...angularParamsRef ? { angularParamsRef } : {}
|
|
161
|
+
});
|
|
162
|
+
const defaultContentType = hasMultipleContentTypes ? uniqueContentTypes.includes("text/plain") ? "text/plain" : getDefaultContentType(uniqueContentTypes) : uniqueContentTypes[0] ?? "application/json";
|
|
163
|
+
const getContentTypeReturnType = (contentType, value) => {
|
|
164
|
+
if (!contentType) return value;
|
|
165
|
+
if (contentType.includes("json") || contentType.includes("+json")) return value;
|
|
166
|
+
if (contentType.startsWith("text/") || contentType.includes("xml")) return "string";
|
|
167
|
+
return "Blob";
|
|
168
|
+
};
|
|
169
|
+
const jsonSuccessValues = [...new Set(successTypes.filter(({ contentType }) => !!contentType && (contentType.includes("json") || contentType.includes("+json"))).map(({ value }) => value))];
|
|
170
|
+
const jsonReturnType = jsonSuccessValues.length > 0 ? jsonSuccessValues.join(" | ") : "unknown";
|
|
171
|
+
const multiImplementationReturnType = `Observable<${jsonReturnType} | string | Blob>`;
|
|
172
|
+
const withObserveMode = (generatedOptions, observeMode) => {
|
|
173
|
+
const spreadPattern = "...(options as Omit<NonNullable<typeof options>, 'observe'>),";
|
|
174
|
+
if (generatedOptions.includes(spreadPattern)) return generatedOptions.replace(spreadPattern, `${spreadPattern}\n observe: '${observeMode}',`);
|
|
175
|
+
return generatedOptions.replace("(options as Omit<NonNullable<typeof options>, 'observe'>)", `{ ...(options as Omit<NonNullable<typeof options>, 'observe'>), observe: '${observeMode}' }`);
|
|
176
|
+
};
|
|
177
|
+
const observeOptions = needsObserveBranching ? {
|
|
178
|
+
body: withObserveMode(options, "body"),
|
|
179
|
+
events: withObserveMode(options, "events"),
|
|
180
|
+
response: withObserveMode(options, "response")
|
|
181
|
+
} : void 0;
|
|
146
182
|
const isModelType = dataType !== "Blob" && dataType !== "string";
|
|
147
183
|
let functionName = operationName;
|
|
148
184
|
if (isModelType && !hasMultipleContentTypes) functionName += `<TData = ${dataType}>`;
|
|
@@ -151,23 +187,26 @@ const generateImplementation = ({ headers, queryParams, operationName, response,
|
|
|
151
187
|
const requiredProps = props.filter((p) => p.required && !p.default);
|
|
152
188
|
const optionalProps = props.filter((p) => !p.required || p.default);
|
|
153
189
|
contentTypeOverloads = successTypes.filter((t) => t.contentType).map(({ contentType, value }) => {
|
|
190
|
+
const returnType = getContentTypeReturnType(contentType, value);
|
|
154
191
|
return `${operationName}(${[
|
|
155
192
|
requiredProps.map((p) => p.definition).join(",\n "),
|
|
156
193
|
`accept: '${contentType}'`,
|
|
157
194
|
optionalProps.map((p) => p.definition).join(",\n ")
|
|
158
|
-
].filter(Boolean).join(",\n ")}, options?: HttpClientOptions): Observable<${
|
|
195
|
+
].filter(Boolean).join(",\n ")}, options?: HttpClientOptions): Observable<${returnType}>;`;
|
|
159
196
|
}).join("\n ");
|
|
160
197
|
const allParams = [
|
|
161
198
|
requiredProps.map((p) => p.definition).join(",\n "),
|
|
162
199
|
"accept?: string",
|
|
163
200
|
optionalProps.map((p) => p.definition).join(",\n ")
|
|
164
201
|
].filter(Boolean).join(",\n ");
|
|
165
|
-
contentTypeOverloads += `\n ${operationName}(${allParams}, options?: HttpClientOptions):
|
|
202
|
+
contentTypeOverloads += `\n ${operationName}(${allParams}, options?: HttpClientOptions): ${multiImplementationReturnType};`;
|
|
166
203
|
}
|
|
167
204
|
const observeOverloads = isRequestOptions && !hasMultipleContentTypes ? `${functionName}(${propsDefinition} options?: HttpClientOptions & { observe?: 'body' }): Observable<${isModelType ? "TData" : dataType}>;
|
|
168
205
|
${functionName}(${propsDefinition} options?: HttpClientOptions & { observe: 'events' }): Observable<HttpEvent<${isModelType ? "TData" : dataType}>>;
|
|
169
206
|
${functionName}(${propsDefinition} options?: HttpClientOptions & { observe: 'response' }): Observable<AngularHttpResponse<${isModelType ? "TData" : dataType}>>;` : "";
|
|
170
207
|
const overloads = contentTypeOverloads || observeOverloads;
|
|
208
|
+
const observableDataType = isModelType ? "TData" : dataType;
|
|
209
|
+
const singleImplementationReturnType = isRequestOptions ? `Observable<${observableDataType} | HttpEvent<${observableDataType}> | AngularHttpResponse<${observableDataType}>>` : `Observable<${observableDataType}>`;
|
|
171
210
|
if (hasMultipleContentTypes) {
|
|
172
211
|
const requiredProps = props.filter((p) => p.required && !p.default);
|
|
173
212
|
const optionalProps = props.filter((p) => !p.required || p.default);
|
|
@@ -181,51 +220,71 @@ const generateImplementation = ({ headers, queryParams, operationName, response,
|
|
|
181
220
|
optionalPart
|
|
182
221
|
].filter(Boolean).join(",\n ")},
|
|
183
222
|
${isRequestOptions ? "options?: HttpClientOptions" : ""}
|
|
184
|
-
):
|
|
223
|
+
): ${multiImplementationReturnType} {${bodyForm}
|
|
224
|
+
const headers = options?.headers instanceof HttpHeaders
|
|
225
|
+
? options.headers.set('Accept', accept)
|
|
226
|
+
: { ...(options?.headers ?? {}), Accept: accept };
|
|
227
|
+
|
|
185
228
|
if (accept.includes('json') || accept.includes('+json')) {
|
|
186
|
-
return this.http.${verb}
|
|
229
|
+
return this.http.${verb}<${jsonReturnType}>(\`${route}\`, {
|
|
187
230
|
...options,
|
|
188
231
|
responseType: 'json',
|
|
189
|
-
headers
|
|
232
|
+
headers,
|
|
190
233
|
});
|
|
191
234
|
} else if (accept.startsWith('text/') || accept.includes('xml')) {
|
|
192
235
|
return this.http.${verb}(\`${route}\`, {
|
|
193
236
|
...options,
|
|
194
237
|
responseType: 'text',
|
|
195
|
-
headers
|
|
196
|
-
}) as
|
|
238
|
+
headers,
|
|
239
|
+
}) as Observable<string>;
|
|
197
240
|
} else {
|
|
198
241
|
return this.http.${verb}(\`${route}\`, {
|
|
199
242
|
...options,
|
|
200
243
|
responseType: 'blob',
|
|
201
|
-
headers
|
|
202
|
-
}) as
|
|
244
|
+
headers,
|
|
245
|
+
}) as Observable<Blob>;
|
|
203
246
|
}
|
|
204
247
|
}
|
|
205
248
|
`;
|
|
206
249
|
}
|
|
250
|
+
const observeImplementation = isRequestOptions ? `${paramsDeclaration}if (options?.observe === 'events') {
|
|
251
|
+
return this.http.${verb}${isModelType ? "<TData>" : ""}(${observeOptions?.events ?? options});
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if (options?.observe === 'response') {
|
|
255
|
+
return this.http.${verb}${isModelType ? "<TData>" : ""}(${observeOptions?.response ?? options});
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return this.http.${verb}${isModelType ? "<TData>" : ""}(${observeOptions?.body ?? options});` : `return this.http.${verb}${isModelType ? "<TData>" : ""}(${options});`;
|
|
207
259
|
return ` ${overloads}
|
|
208
260
|
${functionName}(
|
|
209
|
-
${toObjectString(props, "implementation")} ${isRequestOptions ? `options?: HttpClientOptions & { observe?:
|
|
210
|
-
|
|
261
|
+
${toObjectString(props, "implementation")} ${isRequestOptions ? `options?: HttpClientOptions & { observe?: 'body' | 'events' | 'response' }` : ""}): ${singleImplementationReturnType} {${bodyForm}
|
|
262
|
+
${observeImplementation}
|
|
211
263
|
}
|
|
212
264
|
`;
|
|
213
265
|
};
|
|
214
|
-
const
|
|
266
|
+
const createAngularClient = (returnTypesToWrite) => (verbOptions, options, _outputClient, _output) => {
|
|
215
267
|
const imports = generateVerbImports(verbOptions);
|
|
216
268
|
return {
|
|
217
|
-
implementation: generateImplementation(verbOptions, options),
|
|
269
|
+
implementation: generateImplementation(returnTypesToWrite, verbOptions, options),
|
|
218
270
|
imports
|
|
219
271
|
};
|
|
220
272
|
};
|
|
221
|
-
const
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
273
|
+
const standaloneReturnTypesToWrite = /* @__PURE__ */ new Map();
|
|
274
|
+
const generateAngular = (verbOptions, options, outputClient, output) => createAngularClient(standaloneReturnTypesToWrite)(verbOptions, options, outputClient, output);
|
|
275
|
+
const createAngularClientBuilder = () => {
|
|
276
|
+
const returnTypesToWrite = /* @__PURE__ */ new Map();
|
|
277
|
+
return {
|
|
278
|
+
client: createAngularClient(returnTypesToWrite),
|
|
279
|
+
header: createAngularHeader(),
|
|
280
|
+
dependencies: getAngularDependencies,
|
|
281
|
+
footer: createAngularFooter(returnTypesToWrite),
|
|
282
|
+
title: generateAngularTitle
|
|
283
|
+
};
|
|
284
|
+
};
|
|
285
|
+
const builder = () => {
|
|
286
|
+
return () => createAngularClientBuilder();
|
|
227
287
|
};
|
|
228
|
-
const builder = () => () => angularClientBuilder;
|
|
229
288
|
var src_default = builder;
|
|
230
289
|
|
|
231
290
|
//#endregion
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["ANGULAR_DEPENDENCIES: GeneratorDependency[]","getAngularDependencies: ClientDependenciesBuilder","generateAngularTitle: ClientTitleBuilder","generateAngularHeader: ClientHeaderBuilder","generateAngularFooter: ClientFooterBuilder","generateAngular: ClientBuilder","angularClientBuilder: ClientGeneratorsBuilder"],"sources":["../src/index.ts"],"sourcesContent":["import {\n type ClientBuilder,\n type ClientDependenciesBuilder,\n type ClientFooterBuilder,\n type ClientGeneratorsBuilder,\n type ClientHeaderBuilder,\n type ClientTitleBuilder,\n generateFormDataAndUrlEncodedFunction,\n generateMutatorConfig,\n generateMutatorRequestOptions,\n generateOptions,\n generateVerbImports,\n type GeneratorDependency,\n type GeneratorOptions,\n type GeneratorVerbOptions,\n getDefaultContentType,\n isBoolean,\n pascal,\n sanitize,\n toObjectString,\n} from '@orval/core';\n\nconst ANGULAR_DEPENDENCIES: GeneratorDependency[] = [\n {\n exports: [\n { name: 'HttpClient', values: true },\n { name: 'HttpHeaders' },\n { name: 'HttpParams' },\n { name: 'HttpContext' },\n { name: 'HttpResponse', alias: 'AngularHttpResponse' }, // alias to prevent naming conflict with msw\n { name: 'HttpEvent' },\n ],\n dependency: '@angular/common/http',\n },\n {\n exports: [\n { name: 'Injectable', values: true },\n { name: 'inject', values: true },\n ],\n dependency: '@angular/core',\n },\n {\n exports: [{ name: 'Observable', values: true }],\n dependency: 'rxjs',\n },\n {\n exports: [{ name: 'DeepNonNullable' }],\n dependency: '@orval/core',\n },\n];\n\nconst returnTypesToWrite = new Map<string, string>();\n\nexport const getAngularDependencies: ClientDependenciesBuilder = () =>\n ANGULAR_DEPENDENCIES;\n\nexport const generateAngularTitle: ClientTitleBuilder = (title) => {\n const sanTitle = sanitize(title);\n return `${pascal(sanTitle)}Service`;\n};\n\nexport const generateAngularHeader: ClientHeaderBuilder = ({\n title,\n isRequestOptions,\n isMutator,\n isGlobalMutator,\n provideIn,\n}) => `\n${\n isRequestOptions && !isGlobalMutator\n ? `interface HttpClientOptions {\n headers?: HttpHeaders | Record<string, string | string[]>;\n context?: HttpContext;\n params?:\n | HttpParams\n | Record<string, string | number | boolean | ReadonlyArray<string | number | boolean>>;\n reportProgress?: boolean;\n withCredentials?: boolean;\n credentials?: RequestCredentials;\n keepalive?: boolean;\n priority?: RequestPriority;\n cache?: RequestCache;\n mode?: RequestMode;\n redirect?: RequestRedirect;\n referrer?: string;\n integrity?: string;\n transferCache?: {includeHeaders?: string[]} | boolean;\n timeout?: number;\n}`\n : ''\n}\n\n${\n isRequestOptions && isMutator\n ? `// eslint-disable-next-line\n type ThirdParameter<T extends (...args: any) => any> = T extends (\n config: any,\n httpClient: any,\n args: infer P,\n) => any\n ? P\n : never;`\n : ''\n}\n\n@Injectable(${\n provideIn\n ? `{ providedIn: '${isBoolean(provideIn) ? 'root' : provideIn}' }`\n : ''\n})\nexport class ${title} {\n private readonly http = inject(HttpClient);\n`;\n\nexport const generateAngularFooter: ClientFooterBuilder = ({\n operationNames,\n}) => {\n let footer = '};\\n\\n';\n\n for (const operationName of operationNames) {\n if (returnTypesToWrite.has(operationName)) {\n // Map.has ensures Map.get will not return undefined, but TS still complains\n // bug https://github.com/microsoft/TypeScript/issues/13086\n // eslint-disable-next-line @typescript-eslint/restrict-plus-operands\n footer += returnTypesToWrite.get(operationName) + '\\n';\n }\n }\n\n return footer;\n};\n\nconst generateImplementation = (\n {\n headers,\n queryParams,\n operationName,\n response,\n mutator,\n body,\n props,\n verb,\n override,\n formData,\n formUrlEncoded,\n paramsSerializer,\n }: GeneratorVerbOptions,\n { route, context }: GeneratorOptions,\n) => {\n const isRequestOptions = override.requestOptions !== false;\n const isFormData = !override.formData.disabled;\n const isFormUrlEncoded = override.formUrlEncoded !== false;\n const isExactOptionalPropertyTypes =\n !!context.output.tsconfig?.compilerOptions?.exactOptionalPropertyTypes;\n const bodyForm = generateFormDataAndUrlEncodedFunction({\n formData,\n formUrlEncoded,\n body,\n isFormData,\n isFormUrlEncoded,\n });\n\n const dataType = response.definition.success || 'unknown';\n\n returnTypesToWrite.set(\n operationName,\n `export type ${pascal(\n operationName,\n )}ClientResult = NonNullable<${dataType}>`,\n );\n\n if (mutator) {\n const mutatorConfig = generateMutatorConfig({\n route,\n body,\n headers,\n queryParams,\n response,\n verb,\n isFormData,\n isFormUrlEncoded,\n hasSignal: false,\n isExactOptionalPropertyTypes,\n });\n\n const requestOptions = isRequestOptions\n ? generateMutatorRequestOptions(\n override.requestOptions,\n mutator.hasThirdArg,\n )\n : '';\n\n const propsImplementation =\n mutator.bodyTypeName && body.definition\n ? toObjectString(props, 'implementation').replace(\n new RegExp(String.raw`(\\w*):\\s?${body.definition}`),\n `$1: ${mutator.bodyTypeName}<${body.definition}>`,\n )\n : toObjectString(props, 'implementation');\n\n return ` ${operationName}<TData = ${dataType}>(\\n ${propsImplementation}\\n ${\n isRequestOptions && mutator.hasThirdArg\n ? `options?: ThirdParameter<typeof ${mutator.name}>`\n : ''\n }) {${bodyForm}\n return ${mutator.name}<TData>(\n ${mutatorConfig},\n this.http,\n ${requestOptions});\n }\n `;\n }\n\n const options = generateOptions({\n route,\n body,\n headers,\n queryParams,\n response,\n verb,\n requestOptions: override.requestOptions,\n isFormData,\n isFormUrlEncoded,\n paramsSerializer,\n paramsSerializerOptions: override.paramsSerializerOptions,\n isAngular: true,\n isExactOptionalPropertyTypes,\n hasSignal: false,\n });\n\n const propsDefinition = toObjectString(props, 'definition');\n\n // Check for multiple content types in success responses\n const successTypes = response.types.success;\n const uniqueContentTypes = [\n ...new Set(successTypes.map((t) => t.contentType).filter(Boolean)),\n ];\n const hasMultipleContentTypes = uniqueContentTypes.length > 1;\n\n // For multiple content types, determine the default\n const defaultContentType = hasMultipleContentTypes\n ? getDefaultContentType(uniqueContentTypes)\n : (uniqueContentTypes[0] ?? 'application/json');\n const defaultType = hasMultipleContentTypes\n ? successTypes.find((t) => t.contentType === defaultContentType)\n : undefined;\n const defaultReturnType = defaultType?.value ?? dataType;\n\n const isModelType = dataType !== 'Blob' && dataType !== 'string';\n let functionName = operationName;\n if (isModelType && !hasMultipleContentTypes) {\n functionName += `<TData = ${dataType}>`;\n }\n\n let contentTypeOverloads = '';\n if (hasMultipleContentTypes && isRequestOptions) {\n const requiredProps = props.filter((p) => p.required && !p.default);\n const optionalProps = props.filter((p) => !p.required || p.default);\n\n contentTypeOverloads = successTypes\n .filter((t) => t.contentType)\n .map(({ contentType, value }) => {\n const requiredPart = requiredProps\n .map((p) => p.definition)\n .join(',\\n ');\n const acceptPart = `accept: '${contentType}'`;\n const optionalPart = optionalProps\n .map((p) => p.definition)\n .join(',\\n ');\n\n const allParams = [requiredPart, acceptPart, optionalPart]\n .filter(Boolean)\n .join(',\\n ');\n return `${operationName}(${allParams}, options?: HttpClientOptions): Observable<${value}>;`;\n })\n .join('\\n ');\n\n const requiredPart = requiredProps.map((p) => p.definition).join(',\\n ');\n const optionalPart = optionalProps.map((p) => p.definition).join(',\\n ');\n const allParams = [requiredPart, 'accept?: string', optionalPart]\n .filter(Boolean)\n .join(',\\n ');\n contentTypeOverloads += `\\n ${operationName}(${allParams}, options?: HttpClientOptions): Observable<${defaultReturnType}>;`;\n }\n\n const observeOverloads =\n isRequestOptions && !hasMultipleContentTypes\n ? `${functionName}(${propsDefinition} options?: HttpClientOptions & { observe?: 'body' }): Observable<${isModelType ? 'TData' : dataType}>;\n ${functionName}(${propsDefinition} options?: HttpClientOptions & { observe: 'events' }): Observable<HttpEvent<${isModelType ? 'TData' : dataType}>>;\n ${functionName}(${propsDefinition} options?: HttpClientOptions & { observe: 'response' }): Observable<AngularHttpResponse<${isModelType ? 'TData' : dataType}>>;`\n : '';\n\n const overloads = contentTypeOverloads || observeOverloads;\n\n if (hasMultipleContentTypes) {\n const requiredProps = props.filter((p) => p.required && !p.default);\n const optionalProps = props.filter((p) => !p.required || p.default);\n\n const requiredPart = requiredProps\n .map((p) => p.implementation)\n .join(',\\n ');\n const optionalPart = optionalProps\n .map((p) => p.implementation)\n .join(',\\n ');\n const allParams = [\n requiredPart,\n `accept: string = '${defaultContentType}'`,\n optionalPart,\n ]\n .filter(Boolean)\n .join(',\\n ');\n\n return ` ${overloads}\n ${operationName}(\n ${allParams},\n ${isRequestOptions ? 'options?: HttpClientOptions' : ''}\n ): Observable<any> {${bodyForm}\n if (accept.includes('json') || accept.includes('+json')) {\n return this.http.${verb}<any>(\\`${route}\\`, {\n ...options,\n responseType: 'json',\n headers: { Accept: accept, ...options?.headers },\n });\n } else if (accept.startsWith('text/') || accept.includes('xml')) {\n return this.http.${verb}(\\`${route}\\`, {\n ...options,\n responseType: 'text',\n headers: { Accept: accept, ...options?.headers },\n }) as any;\n } else {\n return this.http.${verb}(\\`${route}\\`, {\n ...options,\n responseType: 'blob',\n headers: { Accept: accept, ...options?.headers },\n }) as any;\n }\n }\n`;\n }\n\n return ` ${overloads}\n ${functionName}(\n ${toObjectString(props, 'implementation')} ${\n isRequestOptions ? `options?: HttpClientOptions & { observe?: any }` : ''\n }): Observable<any> {${bodyForm}\n return this.http.${verb}${isModelType ? '<TData>' : ''}(${options});\n }\n`;\n};\n\nexport const generateAngular: ClientBuilder = (verbOptions, options) => {\n const imports = generateVerbImports(verbOptions);\n const implementation = generateImplementation(verbOptions, options);\n\n return { implementation, imports };\n};\n\nconst angularClientBuilder: ClientGeneratorsBuilder = {\n client: generateAngular,\n header: generateAngularHeader,\n dependencies: getAngularDependencies,\n footer: generateAngularFooter,\n title: generateAngularTitle,\n};\n\nexport const builder = () => () => angularClientBuilder;\n\nexport default builder;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["getAngularDependencies: ClientDependenciesBuilder","generateAngularTitle: ClientTitleBuilder","generateAngularHeader: ClientHeaderBuilder","generateAngularFooter: ClientFooterBuilder","generateAngular: ClientBuilder","builder: () => () => ClientGeneratorsBuilder"],"sources":["../src/index.ts"],"sourcesContent":["import {\n type ClientBuilder,\n type ClientDependenciesBuilder,\n type ClientFooterBuilder,\n type ClientGeneratorsBuilder,\n type ClientHeaderBuilder,\n type ClientTitleBuilder,\n generateFormDataAndUrlEncodedFunction,\n generateMutatorConfig,\n generateMutatorRequestOptions,\n generateOptions,\n generateVerbImports,\n type GeneratorDependency,\n type GeneratorOptions,\n type GeneratorVerbOptions,\n getAngularFilteredParamsCallExpression,\n getAngularFilteredParamsHelperBody,\n getDefaultContentType,\n isBoolean,\n pascal,\n sanitize,\n toObjectString,\n} from '@orval/core';\n\nconst ANGULAR_DEPENDENCIES = [\n {\n exports: [\n { name: 'HttpClient', values: true },\n { name: 'HttpHeaders', values: true },\n { name: 'HttpParams' },\n { name: 'HttpContext' },\n { name: 'HttpResponse', alias: 'AngularHttpResponse' }, // alias to prevent naming conflict with msw\n { name: 'HttpEvent' },\n ],\n dependency: '@angular/common/http',\n },\n {\n exports: [\n { name: 'Injectable', values: true },\n { name: 'inject', values: true },\n ],\n dependency: '@angular/core',\n },\n {\n exports: [{ name: 'Observable', values: true }],\n dependency: 'rxjs',\n },\n] as const satisfies readonly GeneratorDependency[];\n\ntype ReturnTypesToWrite = Map<string, string>;\n\nexport const getAngularDependencies: ClientDependenciesBuilder = () => [\n ...ANGULAR_DEPENDENCIES,\n];\n\nexport const generateAngularTitle: ClientTitleBuilder = (title) => {\n const sanTitle = sanitize(title);\n return `${pascal(sanTitle)}Service`;\n};\n\nconst createAngularHeader =\n (): ClientHeaderBuilder =>\n ({\n title,\n isRequestOptions,\n isMutator,\n isGlobalMutator,\n provideIn,\n verbOptions,\n tag,\n }) => {\n const relevantVerbs = tag\n ? Object.values(verbOptions).filter((v) => v.tags.includes(tag as string))\n : Object.values(verbOptions);\n const hasQueryParams = relevantVerbs.some((v) => v.queryParams);\n return `\n${\n isRequestOptions && !isGlobalMutator\n ? `interface HttpClientOptions {\n headers?: HttpHeaders | Record<string, string | string[]>;\n context?: HttpContext;\n params?:\n | HttpParams\n | Record<string, string | number | boolean | Array<string | number | boolean>>;\n reportProgress?: boolean;\n withCredentials?: boolean;\n credentials?: RequestCredentials;\n keepalive?: boolean;\n priority?: RequestPriority;\n cache?: RequestCache;\n mode?: RequestMode;\n redirect?: RequestRedirect;\n referrer?: string;\n integrity?: string;\n referrerPolicy?: ReferrerPolicy;\n transferCache?: {includeHeaders?: string[]} | boolean;\n}\n\n${hasQueryParams ? getAngularFilteredParamsHelperBody() : ''}`\n : ''\n}\n\n${\n isRequestOptions && isMutator\n ? `// eslint-disable-next-line\n type ThirdParameter<T extends (...args: any) => any> = T extends (\n config: any,\n httpClient: any,\n args: infer P,\n) => any\n ? P\n : never;`\n : ''\n}\n\n@Injectable(${provideIn ? `{ providedIn: '${isBoolean(provideIn) ? 'root' : provideIn}' }` : ''})\nexport class ${title} {\n private readonly http = inject(HttpClient);\n`;\n };\n\nexport const generateAngularHeader: ClientHeaderBuilder = (params) =>\n createAngularHeader()(params);\n\nconst standaloneFooterReturnTypesToWrite = new Map<string, string>();\n\nconst createAngularFooter =\n (returnTypesToWrite: ReturnTypesToWrite): ClientFooterBuilder =>\n ({ operationNames }) => {\n let footer = '};\\n\\n';\n\n for (const operationName of operationNames) {\n if (returnTypesToWrite.has(operationName)) {\n // Map.has ensures Map.get will not return undefined, but TS still complains\n // bug https://github.com/microsoft/TypeScript/issues/13086\n // eslint-disable-next-line @typescript-eslint/restrict-plus-operands\n footer += returnTypesToWrite.get(operationName) + '\\n';\n }\n }\n\n return footer;\n };\n\nexport const generateAngularFooter: ClientFooterBuilder = (params) =>\n createAngularFooter(standaloneFooterReturnTypesToWrite)(params);\n\nconst generateImplementation = (\n returnTypesToWrite: ReturnTypesToWrite,\n {\n headers,\n queryParams,\n operationName,\n response,\n mutator,\n body,\n props,\n verb,\n override,\n formData,\n formUrlEncoded,\n paramsSerializer,\n }: GeneratorVerbOptions,\n { route, context }: GeneratorOptions,\n) => {\n const isRequestOptions = override.requestOptions !== false;\n const isFormData = !override.formData.disabled;\n const isFormUrlEncoded = override.formUrlEncoded !== false;\n const isExactOptionalPropertyTypes =\n !!context.output.tsconfig?.compilerOptions?.exactOptionalPropertyTypes;\n const bodyForm = generateFormDataAndUrlEncodedFunction({\n formData,\n formUrlEncoded,\n body,\n isFormData,\n isFormUrlEncoded,\n });\n\n const dataType = response.definition.success || 'unknown';\n\n returnTypesToWrite.set(\n operationName,\n `export type ${pascal(\n operationName,\n )}ClientResult = NonNullable<${dataType}>`,\n );\n\n if (mutator) {\n const mutatorConfig = generateMutatorConfig({\n route,\n body,\n headers,\n queryParams,\n response,\n verb,\n isFormData,\n isFormUrlEncoded,\n hasSignal: false,\n isExactOptionalPropertyTypes,\n isAngular: true,\n });\n\n const requestOptions = isRequestOptions\n ? generateMutatorRequestOptions(\n override.requestOptions,\n mutator.hasThirdArg,\n )\n : '';\n\n const propsImplementation =\n mutator.bodyTypeName && body.definition\n ? toObjectString(props, 'implementation').replace(\n new RegExp(String.raw`(\\w*):\\s?${body.definition}`),\n `$1: ${mutator.bodyTypeName}<${body.definition}>`,\n )\n : toObjectString(props, 'implementation');\n\n return ` ${operationName}<TData = ${dataType}>(\\n ${propsImplementation}\\n ${\n isRequestOptions && mutator.hasThirdArg\n ? `options?: ThirdParameter<typeof ${mutator.name}>`\n : ''\n }) {${bodyForm}\n return ${mutator.name}<TData>(\n ${mutatorConfig},\n this.http,\n ${requestOptions});\n }\n `;\n }\n\n const optionsBase = {\n route,\n body,\n headers,\n queryParams,\n response,\n verb,\n requestOptions: override.requestOptions,\n isFormData,\n isFormUrlEncoded,\n paramsSerializer,\n paramsSerializerOptions: override.paramsSerializerOptions,\n isAngular: true,\n isExactOptionalPropertyTypes,\n hasSignal: false,\n } as const;\n\n const propsDefinition = toObjectString(props, 'definition');\n\n // Check for multiple content types in success responses\n const successTypes = response.types.success;\n const uniqueContentTypes = [\n ...new Set(successTypes.map((t) => t.contentType).filter(Boolean)),\n ];\n const hasMultipleContentTypes = uniqueContentTypes.length > 1;\n\n // When observe branching is active AND there are query params, extract\n // the params computation to a local const to avoid duplicating it in\n // every observe branch.\n const needsObserveBranching = isRequestOptions && !hasMultipleContentTypes;\n const angularParamsRef =\n needsObserveBranching && queryParams ? 'filteredParams' : undefined;\n\n let paramsDeclaration = '';\n if (angularParamsRef && queryParams) {\n const callExpr = getAngularFilteredParamsCallExpression(\n '{...params, ...options?.params}',\n queryParams.requiredNullableKeys ?? [],\n );\n paramsDeclaration = paramsSerializer\n ? `const ${angularParamsRef} = ${paramsSerializer.name}(${callExpr});\\n\\n `\n : `const ${angularParamsRef} = ${callExpr};\\n\\n `;\n }\n\n const options = generateOptions({\n ...optionsBase,\n ...(angularParamsRef ? { angularParamsRef } : {}),\n });\n\n // For multiple content types, determine the default\n const defaultContentType = hasMultipleContentTypes\n ? uniqueContentTypes.includes('text/plain')\n ? 'text/plain'\n : getDefaultContentType(uniqueContentTypes)\n : (uniqueContentTypes[0] ?? 'application/json');\n const getContentTypeReturnType = (\n contentType: string | undefined,\n value: string,\n ): string => {\n if (!contentType) {\n return value;\n }\n\n if (contentType.includes('json') || contentType.includes('+json')) {\n return value;\n }\n\n if (contentType.startsWith('text/') || contentType.includes('xml')) {\n return 'string';\n }\n\n return 'Blob';\n };\n\n const jsonSuccessValues = [\n ...new Set(\n successTypes\n .filter(\n ({ contentType }) =>\n !!contentType &&\n (contentType.includes('json') || contentType.includes('+json')),\n )\n .map(({ value }) => value),\n ),\n ];\n\n const jsonReturnType =\n jsonSuccessValues.length > 0 ? jsonSuccessValues.join(' | ') : 'unknown';\n const multiImplementationReturnType = `Observable<${jsonReturnType} | string | Blob>`;\n\n const withObserveMode = (\n generatedOptions: string,\n observeMode: 'body' | 'events' | 'response',\n ): string => {\n const spreadPattern =\n \"...(options as Omit<NonNullable<typeof options>, 'observe'>),\";\n\n if (generatedOptions.includes(spreadPattern)) {\n return generatedOptions.replace(\n spreadPattern,\n `${spreadPattern}\\n observe: '${observeMode}',`,\n );\n }\n\n return generatedOptions.replace(\n \"(options as Omit<NonNullable<typeof options>, 'observe'>)\",\n `{ ...(options as Omit<NonNullable<typeof options>, 'observe'>), observe: '${observeMode}' }`,\n );\n };\n\n const observeOptions = needsObserveBranching\n ? {\n body: withObserveMode(options, 'body'),\n events: withObserveMode(options, 'events'),\n response: withObserveMode(options, 'response'),\n }\n : undefined;\n\n const isModelType = dataType !== 'Blob' && dataType !== 'string';\n let functionName = operationName;\n if (isModelType && !hasMultipleContentTypes) {\n functionName += `<TData = ${dataType}>`;\n }\n\n let contentTypeOverloads = '';\n if (hasMultipleContentTypes && isRequestOptions) {\n const requiredProps = props.filter((p) => p.required && !p.default);\n const optionalProps = props.filter((p) => !p.required || p.default);\n\n contentTypeOverloads = successTypes\n .filter((t) => t.contentType)\n .map(({ contentType, value }) => {\n const returnType = getContentTypeReturnType(contentType, value);\n const requiredPart = requiredProps\n .map((p) => p.definition)\n .join(',\\n ');\n const acceptPart = `accept: '${contentType}'`;\n const optionalPart = optionalProps\n .map((p) => p.definition)\n .join(',\\n ');\n\n const allParams = [requiredPart, acceptPart, optionalPart]\n .filter(Boolean)\n .join(',\\n ');\n return `${operationName}(${allParams}, options?: HttpClientOptions): Observable<${returnType}>;`;\n })\n .join('\\n ');\n\n const requiredPart = requiredProps.map((p) => p.definition).join(',\\n ');\n const optionalPart = optionalProps.map((p) => p.definition).join(',\\n ');\n const allParams = [requiredPart, 'accept?: string', optionalPart]\n .filter(Boolean)\n .join(',\\n ');\n contentTypeOverloads += `\\n ${operationName}(${allParams}, options?: HttpClientOptions): ${multiImplementationReturnType};`;\n }\n\n const observeOverloads =\n isRequestOptions && !hasMultipleContentTypes\n ? `${functionName}(${propsDefinition} options?: HttpClientOptions & { observe?: 'body' }): Observable<${isModelType ? 'TData' : dataType}>;\n ${functionName}(${propsDefinition} options?: HttpClientOptions & { observe: 'events' }): Observable<HttpEvent<${isModelType ? 'TData' : dataType}>>;\n ${functionName}(${propsDefinition} options?: HttpClientOptions & { observe: 'response' }): Observable<AngularHttpResponse<${isModelType ? 'TData' : dataType}>>;`\n : '';\n\n const overloads = contentTypeOverloads || observeOverloads;\n\n const observableDataType = isModelType ? 'TData' : dataType;\n const singleImplementationReturnType = isRequestOptions\n ? `Observable<${observableDataType} | HttpEvent<${observableDataType}> | AngularHttpResponse<${observableDataType}>>`\n : `Observable<${observableDataType}>`;\n\n if (hasMultipleContentTypes) {\n const requiredProps = props.filter((p) => p.required && !p.default);\n const optionalProps = props.filter((p) => !p.required || p.default);\n\n const requiredPart = requiredProps\n .map((p) => p.implementation)\n .join(',\\n ');\n const optionalPart = optionalProps\n .map((p) => p.implementation)\n .join(',\\n ');\n const allParams = [\n requiredPart,\n `accept: string = '${defaultContentType}'`,\n optionalPart,\n ]\n .filter(Boolean)\n .join(',\\n ');\n\n return ` ${overloads}\n ${operationName}(\n ${allParams},\n ${isRequestOptions ? 'options?: HttpClientOptions' : ''}\n ): ${multiImplementationReturnType} {${bodyForm}\n const headers = options?.headers instanceof HttpHeaders\n ? options.headers.set('Accept', accept)\n : { ...(options?.headers ?? {}), Accept: accept };\n\n if (accept.includes('json') || accept.includes('+json')) {\n return this.http.${verb}<${jsonReturnType}>(\\`${route}\\`, {\n ...options,\n responseType: 'json',\n headers,\n });\n } else if (accept.startsWith('text/') || accept.includes('xml')) {\n return this.http.${verb}(\\`${route}\\`, {\n ...options,\n responseType: 'text',\n headers,\n }) as Observable<string>;\n } else {\n return this.http.${verb}(\\`${route}\\`, {\n ...options,\n responseType: 'blob',\n headers,\n }) as Observable<Blob>;\n }\n }\n`;\n }\n\n const observeImplementation = isRequestOptions\n ? `${paramsDeclaration}if (options?.observe === 'events') {\n return this.http.${verb}${isModelType ? '<TData>' : ''}(${\n observeOptions?.events ?? options\n });\n }\n\n if (options?.observe === 'response') {\n return this.http.${verb}${isModelType ? '<TData>' : ''}(${\n observeOptions?.response ?? options\n });\n }\n\n return this.http.${verb}${isModelType ? '<TData>' : ''}(${\n observeOptions?.body ?? options\n });`\n : `return this.http.${verb}${isModelType ? '<TData>' : ''}(${options});`;\n\n return ` ${overloads}\n ${functionName}(\n ${toObjectString(props, 'implementation')} ${\n isRequestOptions\n ? `options?: HttpClientOptions & { observe?: 'body' | 'events' | 'response' }`\n : ''\n }): ${singleImplementationReturnType} {${bodyForm}\n ${observeImplementation}\n }\n`;\n};\n\nconst createAngularClient =\n (returnTypesToWrite: ReturnTypesToWrite): ClientBuilder =>\n (verbOptions, options, _outputClient, _output) => {\n // Keep signature aligned with ClientBuilder without tripping TS noUnusedParameters\n void _outputClient;\n void _output;\n const imports = generateVerbImports(verbOptions);\n const implementation = generateImplementation(\n returnTypesToWrite,\n verbOptions,\n options,\n );\n\n return { implementation, imports };\n };\n\nconst standaloneReturnTypesToWrite = new Map<string, string>();\n\nexport const generateAngular: ClientBuilder = (\n verbOptions,\n options,\n outputClient,\n output,\n) =>\n createAngularClient(standaloneReturnTypesToWrite)(\n verbOptions,\n options,\n outputClient,\n output,\n );\n\nconst createAngularClientBuilder = (): ClientGeneratorsBuilder => {\n const returnTypesToWrite = new Map<string, string>();\n\n return {\n client: createAngularClient(returnTypesToWrite),\n header: createAngularHeader(),\n dependencies: getAngularDependencies,\n footer: createAngularFooter(returnTypesToWrite),\n title: generateAngularTitle,\n };\n};\n\nexport const builder: () => () => ClientGeneratorsBuilder = () => {\n return () => createAngularClientBuilder();\n};\n\nexport default builder;\n"],"mappings":";;;AAwBA,MAAM,uBAAuB;CAC3B;EACE,SAAS;GACP;IAAE,MAAM;IAAc,QAAQ;IAAM;GACpC;IAAE,MAAM;IAAe,QAAQ;IAAM;GACrC,EAAE,MAAM,cAAc;GACtB,EAAE,MAAM,eAAe;GACvB;IAAE,MAAM;IAAgB,OAAO;IAAuB;GACtD,EAAE,MAAM,aAAa;GACtB;EACD,YAAY;EACb;CACD;EACE,SAAS,CACP;GAAE,MAAM;GAAc,QAAQ;GAAM,EACpC;GAAE,MAAM;GAAU,QAAQ;GAAM,CACjC;EACD,YAAY;EACb;CACD;EACE,SAAS,CAAC;GAAE,MAAM;GAAc,QAAQ;GAAM,CAAC;EAC/C,YAAY;EACb;CACF;AAID,MAAaA,+BAA0D,CACrE,GAAG,qBACJ;AAED,MAAaC,wBAA4C,UAAU;AAEjE,QAAO,GAAG,OADO,SAAS,MAAM,CACN,CAAC;;AAG7B,MAAM,6BAEH,EACC,OACA,kBACA,WACA,iBACA,WACA,aACA,UACI;CAIJ,MAAM,kBAHgB,MAClB,OAAO,OAAO,YAAY,CAAC,QAAQ,MAAM,EAAE,KAAK,SAAS,IAAc,CAAC,GACxE,OAAO,OAAO,YAAY,EACO,MAAM,MAAM,EAAE,YAAY;AAC/D,QAAO;EAET,oBAAoB,CAAC,kBACjB;;;;;;;;;;;;;;;;;;;;EAoBJ,iBAAiB,oCAAoC,GAAG,OACpD,GACL;;EAGC,oBAAoB,YAChB;;;;;;;cAQA,GACL;;cAEa,YAAY,kBAAkB,UAAU,UAAU,GAAG,SAAS,UAAU,OAAO,GAAG;eACjF,MAAM;;;;AAKrB,MAAaC,yBAA8C,WACzD,qBAAqB,CAAC,OAAO;AAE/B,MAAM,qDAAqC,IAAI,KAAqB;AAEpE,MAAM,uBACH,wBACA,EAAE,qBAAqB;CACtB,IAAI,SAAS;AAEb,MAAK,MAAM,iBAAiB,eAC1B,KAAI,mBAAmB,IAAI,cAAc,CAIvC,WAAU,mBAAmB,IAAI,cAAc,GAAG;AAItD,QAAO;;AAGX,MAAaC,yBAA8C,WACzD,oBAAoB,mCAAmC,CAAC,OAAO;AAEjE,MAAM,0BACJ,oBACA,EACE,SACA,aACA,eACA,UACA,SACA,MACA,OACA,MACA,UACA,UACA,gBACA,oBAEF,EAAE,OAAO,cACN;CACH,MAAM,mBAAmB,SAAS,mBAAmB;CACrD,MAAM,aAAa,CAAC,SAAS,SAAS;CACtC,MAAM,mBAAmB,SAAS,mBAAmB;CACrD,MAAM,+BACJ,CAAC,CAAC,QAAQ,OAAO,UAAU,iBAAiB;CAC9C,MAAM,WAAW,sCAAsC;EACrD;EACA;EACA;EACA;EACA;EACD,CAAC;CAEF,MAAM,WAAW,SAAS,WAAW,WAAW;AAEhD,oBAAmB,IACjB,eACA,eAAe,OACb,cACD,CAAC,6BAA6B,SAAS,GACzC;AAED,KAAI,SAAS;EACX,MAAM,gBAAgB,sBAAsB;GAC1C;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA,WAAW;GACX;GACA,WAAW;GACZ,CAAC;EAEF,MAAM,iBAAiB,mBACnB,8BACE,SAAS,gBACT,QAAQ,YACT,GACD;AAUJ,SAAO,IAAI,cAAc,WAAW,SAAS,UAP3C,QAAQ,gBAAgB,KAAK,aACzB,eAAe,OAAO,iBAAiB,CAAC,QACtC,IAAI,OAAO,OAAO,GAAG,YAAY,KAAK,aAAa,EACnD,OAAO,QAAQ,aAAa,GAAG,KAAK,WAAW,GAChD,GACD,eAAe,OAAO,iBAAiB,CAE8B,KACzE,oBAAoB,QAAQ,cACxB,mCAAmC,QAAQ,KAAK,KAChD,GACL,KAAK,SAAS;eACJ,QAAQ,KAAK;QACpB,cAAc;;QAEd,eAAe;;;;CAKrB,MAAM,cAAc;EAClB;EACA;EACA;EACA;EACA;EACA;EACA,gBAAgB,SAAS;EACzB;EACA;EACA;EACA,yBAAyB,SAAS;EAClC,WAAW;EACX;EACA,WAAW;EACZ;CAED,MAAM,kBAAkB,eAAe,OAAO,aAAa;CAG3D,MAAM,eAAe,SAAS,MAAM;CACpC,MAAM,qBAAqB,CACzB,GAAG,IAAI,IAAI,aAAa,KAAK,MAAM,EAAE,YAAY,CAAC,OAAO,QAAQ,CAAC,CACnE;CACD,MAAM,0BAA0B,mBAAmB,SAAS;CAK5D,MAAM,wBAAwB,oBAAoB,CAAC;CACnD,MAAM,mBACJ,yBAAyB,cAAc,mBAAmB;CAE5D,IAAI,oBAAoB;AACxB,KAAI,oBAAoB,aAAa;EACnC,MAAM,WAAW,uCACf,mCACA,YAAY,wBAAwB,EAAE,CACvC;AACD,sBAAoB,mBAChB,SAAS,iBAAiB,KAAK,iBAAiB,KAAK,GAAG,SAAS,cACjE,SAAS,iBAAiB,KAAK,SAAS;;CAG9C,MAAM,UAAU,gBAAgB;EAC9B,GAAG;EACH,GAAI,mBAAmB,EAAE,kBAAkB,GAAG,EAAE;EACjD,CAAC;CAGF,MAAM,qBAAqB,0BACvB,mBAAmB,SAAS,aAAa,GACvC,eACA,sBAAsB,mBAAmB,GAC1C,mBAAmB,MAAM;CAC9B,MAAM,4BACJ,aACA,UACW;AACX,MAAI,CAAC,YACH,QAAO;AAGT,MAAI,YAAY,SAAS,OAAO,IAAI,YAAY,SAAS,QAAQ,CAC/D,QAAO;AAGT,MAAI,YAAY,WAAW,QAAQ,IAAI,YAAY,SAAS,MAAM,CAChE,QAAO;AAGT,SAAO;;CAGT,MAAM,oBAAoB,CACxB,GAAG,IAAI,IACL,aACG,QACE,EAAE,kBACD,CAAC,CAAC,gBACD,YAAY,SAAS,OAAO,IAAI,YAAY,SAAS,QAAQ,EACjE,CACA,KAAK,EAAE,YAAY,MAAM,CAC7B,CACF;CAED,MAAM,iBACJ,kBAAkB,SAAS,IAAI,kBAAkB,KAAK,MAAM,GAAG;CACjE,MAAM,gCAAgC,cAAc,eAAe;CAEnE,MAAM,mBACJ,kBACA,gBACW;EACX,MAAM,gBACJ;AAEF,MAAI,iBAAiB,SAAS,cAAc,CAC1C,QAAO,iBAAiB,QACtB,eACA,GAAG,cAAc,sBAAsB,YAAY,IACpD;AAGH,SAAO,iBAAiB,QACtB,6DACA,6EAA6E,YAAY,KAC1F;;CAGH,MAAM,iBAAiB,wBACnB;EACE,MAAM,gBAAgB,SAAS,OAAO;EACtC,QAAQ,gBAAgB,SAAS,SAAS;EAC1C,UAAU,gBAAgB,SAAS,WAAW;EAC/C,GACD;CAEJ,MAAM,cAAc,aAAa,UAAU,aAAa;CACxD,IAAI,eAAe;AACnB,KAAI,eAAe,CAAC,wBAClB,iBAAgB,YAAY,SAAS;CAGvC,IAAI,uBAAuB;AAC3B,KAAI,2BAA2B,kBAAkB;EAC/C,MAAM,gBAAgB,MAAM,QAAQ,MAAM,EAAE,YAAY,CAAC,EAAE,QAAQ;EACnE,MAAM,gBAAgB,MAAM,QAAQ,MAAM,CAAC,EAAE,YAAY,EAAE,QAAQ;AAEnE,yBAAuB,aACpB,QAAQ,MAAM,EAAE,YAAY,CAC5B,KAAK,EAAE,aAAa,YAAY;GAC/B,MAAM,aAAa,yBAAyB,aAAa,MAAM;AAY/D,UAAO,GAAG,cAAc,GAHN;IARG,cAClB,KAAK,MAAM,EAAE,WAAW,CACxB,KAAK,UAAU;IACC,YAAY,YAAY;IACtB,cAClB,KAAK,MAAM,EAAE,WAAW,CACxB,KAAK,UAAU;IAEwC,CACvD,OAAO,QAAQ,CACf,KAAK,UAAU,CACmB,6CAA6C,WAAW;IAC7F,CACD,KAAK,OAAO;EAIf,MAAM,YAAY;GAFG,cAAc,KAAK,MAAM,EAAE,WAAW,CAAC,KAAK,UAAU;GAE1C;GADZ,cAAc,KAAK,MAAM,EAAE,WAAW,CAAC,KAAK,UAAU;GACV,CAC9D,OAAO,QAAQ,CACf,KAAK,UAAU;AAClB,0BAAwB,OAAO,cAAc,GAAG,UAAU,kCAAkC,8BAA8B;;CAG5H,MAAM,mBACJ,oBAAoB,CAAC,0BACjB,GAAG,aAAa,GAAG,gBAAgB,mEAAmE,cAAc,UAAU,SAAS;GAC5I,aAAa,GAAG,gBAAgB,8EAA8E,cAAc,UAAU,SAAS;GAC/I,aAAa,GAAG,gBAAgB,0FAA0F,cAAc,UAAU,SAAS,OACtJ;CAEN,MAAM,YAAY,wBAAwB;CAE1C,MAAM,qBAAqB,cAAc,UAAU;CACnD,MAAM,iCAAiC,mBACnC,cAAc,mBAAmB,eAAe,mBAAmB,0BAA0B,mBAAmB,MAChH,cAAc,mBAAmB;AAErC,KAAI,yBAAyB;EAC3B,MAAM,gBAAgB,MAAM,QAAQ,MAAM,EAAE,YAAY,CAAC,EAAE,QAAQ;EACnE,MAAM,gBAAgB,MAAM,QAAQ,MAAM,CAAC,EAAE,YAAY,EAAE,QAAQ;EAEnE,MAAM,eAAe,cAClB,KAAK,MAAM,EAAE,eAAe,CAC5B,KAAK,UAAU;EAClB,MAAM,eAAe,cAClB,KAAK,MAAM,EAAE,eAAe,CAC5B,KAAK,UAAU;AASlB,SAAO,IAAI,UAAU;IACrB,cAAc;MATI;GAChB;GACA,qBAAqB,mBAAmB;GACxC;GACD,CACE,OAAO,QAAQ,CACf,KAAK,UAAU,CAIN;MACV,mBAAmB,gCAAgC,GAAG;OACrD,8BAA8B,IAAI,SAAS;;;;;;yBAMzB,KAAK,GAAG,eAAe,MAAM,MAAM;;;;;;yBAMnC,KAAK,KAAK,MAAM;;;;;;yBAMhB,KAAK,KAAK,MAAM;;;;;;;;;CAUvC,MAAM,wBAAwB,mBAC1B,GAAG,kBAAkB;yBACF,OAAO,cAAc,YAAY,GAAG,GACrD,gBAAgB,UAAU,QAC3B;;;;yBAIkB,OAAO,cAAc,YAAY,GAAG,GACrD,gBAAgB,YAAY,QAC7B;;;uBAGgB,OAAO,cAAc,YAAY,GAAG,GACrD,gBAAgB,QAAQ,QACzB,MACC,oBAAoB,OAAO,cAAc,YAAY,GAAG,GAAG,QAAQ;AAEvE,QAAO,IAAI,UAAU;IACnB,aAAa;MACX,eAAe,OAAO,iBAAiB,CAAC,GACxC,mBACI,+EACA,GACL,KAAK,+BAA+B,IAAI,SAAS;MAChD,sBAAsB;;;;AAK5B,MAAM,uBACH,wBACA,aAAa,SAAS,eAAe,YAAY;CAIhD,MAAM,UAAU,oBAAoB,YAAY;AAOhD,QAAO;EAAE,gBANc,uBACrB,oBACA,aACA,QACD;EAEwB;EAAS;;AAGtC,MAAM,+CAA+B,IAAI,KAAqB;AAE9D,MAAaC,mBACX,aACA,SACA,cACA,WAEA,oBAAoB,6BAA6B,CAC/C,aACA,SACA,cACA,OACD;AAEH,MAAM,mCAA4D;CAChE,MAAM,qCAAqB,IAAI,KAAqB;AAEpD,QAAO;EACL,QAAQ,oBAAoB,mBAAmB;EAC/C,QAAQ,qBAAqB;EAC7B,cAAc;EACd,QAAQ,oBAAoB,mBAAmB;EAC/C,OAAO;EACR;;AAGH,MAAaC,gBAAqD;AAChE,cAAa,4BAA4B;;AAG3C,kBAAe"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@orval/angular",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.4.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -16,17 +16,19 @@
|
|
|
16
16
|
"build": "tsdown --config-loader unrun",
|
|
17
17
|
"dev": "tsdown --config-loader unrun --watch src",
|
|
18
18
|
"lint": "eslint .",
|
|
19
|
+
"test": "vitest",
|
|
19
20
|
"clean": "rimraf .turbo dist",
|
|
20
21
|
"nuke": "rimraf .turbo dist node_modules"
|
|
21
22
|
},
|
|
22
23
|
"dependencies": {
|
|
23
|
-
"@orval/core": "8.
|
|
24
|
+
"@orval/core": "8.4.0"
|
|
24
25
|
},
|
|
25
26
|
"devDependencies": {
|
|
26
27
|
"eslint": "9.39.2",
|
|
27
28
|
"rimraf": "6.1.2",
|
|
28
29
|
"tsdown": "0.18.2",
|
|
29
|
-
"typescript": "5.9.3"
|
|
30
|
+
"typescript": "5.9.3",
|
|
31
|
+
"vitest": "4.0.16"
|
|
30
32
|
},
|
|
31
33
|
"main": "./dist/index.mjs",
|
|
32
34
|
"module": "./dist/index.mjs",
|