ng-openapi 0.2.2 → 0.2.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.
Files changed (4) hide show
  1. package/cli.cjs +117 -30
  2. package/index.d.ts +9 -1
  3. package/index.js +125 -32
  4. package/package.json +1 -1
package/cli.cjs CHANGED
@@ -44,7 +44,7 @@ var fs4 = __toESM(require("fs"));
44
44
  var path12 = __toESM(require("path"));
45
45
 
46
46
  // package.json
47
- var version = "0.2.1";
47
+ var version = "0.2.2";
48
48
 
49
49
  // src/lib/core/generator.ts
50
50
  var import_ts_morph7 = require("ts-morph");
@@ -111,6 +111,10 @@ function getTypeScriptType(schemaOrType, config, formatOrNullable, isNullable, c
111
111
  case "null":
112
112
  return "null";
113
113
  default:
114
+ if (Array.isArray(schema.type)) {
115
+ const types = schema.type.map((t) => getTypeScriptType(t, config, void 0, void 0, context));
116
+ return nullableType(types.join(" | "), nullable);
117
+ }
114
118
  return nullableType("any", nullable);
115
119
  }
116
120
  }
@@ -292,7 +296,7 @@ function inferResponseTypeFromContentType(contentType) {
292
296
  }
293
297
  return "text";
294
298
  }
295
- if (normalizedType === "application/x-www-form-urlencoded" || normalizedType === "multipart/form-data") {
299
+ if (normalizedType === "CONTENT_TYPES.FORM_URLENCODED" || normalizedType === "multipart/form-data") {
296
300
  return "text";
297
301
  }
298
302
  if (normalizedType === "application/javascript" || normalizedType === "application/typescript" || normalizedType === "application/css" || normalizedType === "application/yaml" || normalizedType === "application/x-yaml" || normalizedType === "application/toml") {
@@ -325,10 +329,17 @@ function getResponseType(response, config) {
325
329
  }
326
330
  __name(getResponseType, "getResponseType");
327
331
 
332
+ // ../shared/src/utils/content-types.constants.ts
333
+ var CONTENT_TYPES = {
334
+ MULTIPART: "multipart/form-data",
335
+ FORM_URLENCODED: "application/x-www-form-urlencoded",
336
+ JSON: "application/json"
337
+ };
338
+
328
339
  // ../shared/src/utils/functions/get-request-body-type.ts
329
340
  function getRequestBodyType(requestBody, config) {
330
341
  const content = requestBody.content || {};
331
- const jsonContent = content["application/json"];
342
+ const jsonContent = content[CONTENT_TYPES.JSON];
332
343
  if (jsonContent?.schema) {
333
344
  return getTypeScriptType(jsonContent.schema, config, jsonContent.schema.nullable);
334
345
  }
@@ -943,6 +954,10 @@ var TypeGenerator = class {
943
954
  case "null":
944
955
  return this.nullableType("null", isNullable);
945
956
  default:
957
+ if (Array.isArray(type)) {
958
+ const types = type.map((t) => this.mapSwaggerTypeToTypeScript(t, void 0, isNullable));
959
+ return this.nullableType(types.join(" | "), isNullable);
960
+ }
946
961
  return this.nullableType("any", isNullable);
947
962
  }
948
963
  }
@@ -1941,19 +1956,35 @@ var ServiceMethodBodyGenerator = class {
1941
1956
  this.generateQueryParams(context),
1942
1957
  this.generateHeaders(context),
1943
1958
  this.generateMultipartFormData(operation, context),
1959
+ this.generateUrlEncodedFormData(operation, context),
1944
1960
  this.generateRequestOptions(context),
1945
1961
  this.generateHttpRequest(operation, context)
1946
1962
  ];
1947
1963
  return bodyParts.filter(Boolean).join("\n");
1948
1964
  }
1949
1965
  isMultipartFormData(operation) {
1950
- return !!operation.requestBody?.content?.["multipart/form-data"];
1966
+ return !!operation.requestBody?.content?.[CONTENT_TYPES.MULTIPART];
1967
+ }
1968
+ isUrlEncodedFormData(operation) {
1969
+ return !!operation.requestBody?.content?.[CONTENT_TYPES.FORM_URLENCODED] && !operation.requestBody?.content?.[CONTENT_TYPES.JSON];
1951
1970
  }
1952
1971
  getFormDataFields(operation) {
1953
1972
  if (!this.isMultipartFormData(operation)) {
1954
1973
  return [];
1955
1974
  }
1956
- const schema = operation.requestBody?.content?.["multipart/form-data"].schema;
1975
+ const schema = operation.requestBody?.content?.[CONTENT_TYPES.MULTIPART].schema;
1976
+ let resolvedSchema = schema;
1977
+ if (schema?.$ref) {
1978
+ resolvedSchema = this.parser.resolveReference(schema.$ref);
1979
+ }
1980
+ const properties = resolvedSchema?.properties || {};
1981
+ return Object.keys(properties);
1982
+ }
1983
+ getUrlEncodedFields(operation) {
1984
+ if (!this.isUrlEncodedFormData(operation)) {
1985
+ return [];
1986
+ }
1987
+ const schema = operation.requestBody?.content?.[CONTENT_TYPES.FORM_URLENCODED].schema;
1957
1988
  let resolvedSchema = schema;
1958
1989
  if (schema?.$ref) {
1959
1990
  resolvedSchema = this.parser.resolveReference(schema.$ref);
@@ -1967,7 +1998,9 @@ var ServiceMethodBodyGenerator = class {
1967
1998
  queryParams: operation.parameters?.filter((p) => p.in === "query") || [],
1968
1999
  hasBody: !!operation.requestBody,
1969
2000
  isMultipart: this.isMultipartFormData(operation),
2001
+ isUrlEncoded: this.isUrlEncodedFormData(operation),
1970
2002
  formDataFields: this.getFormDataFields(operation),
2003
+ urlEncodedFields: this.getUrlEncodedFields(operation),
1971
2004
  responseType: this.determineResponseType(operation)
1972
2005
  };
1973
2006
  }
@@ -1993,7 +2026,7 @@ ${paramMappings}`;
1993
2026
  }
1994
2027
  generateHeaders(context) {
1995
2028
  const hasCustomHeaders = this.config.options.customHeaders;
1996
- if (!hasCustomHeaders && !context.isMultipart) {
2029
+ if (!hasCustomHeaders && !context.isMultipart && !context.isUrlEncoded) {
1997
2030
  return "";
1998
2031
  }
1999
2032
  let headerCode = `
@@ -2014,7 +2047,13 @@ ${Object.entries(this.config.options.customHeaders || {}).map(([key, value]) =>
2014
2047
  headerCode += `
2015
2048
  // Remove Content-Type for multipart (browser will set it with boundary)
2016
2049
  headers = headers.delete('Content-Type');`;
2017
- } else if (!context.isMultipart) {
2050
+ } else if (context.isUrlEncoded) {
2051
+ headerCode += `
2052
+ // Set Content-Type for URL-encoded form data
2053
+ if (!headers.has('Content-Type')) {
2054
+ headers = headers.set('Content-Type', 'application/x-www-form-urlencoded');
2055
+ }`;
2056
+ } else {
2018
2057
  headerCode += `
2019
2058
  // Set Content-Type for JSON requests if not already set
2020
2059
  if (!headers.has('Content-Type')) {
@@ -2027,7 +2066,7 @@ if (!headers.has('Content-Type')) {
2027
2066
  if (!context.isMultipart || context.formDataFields.length === 0) {
2028
2067
  return "";
2029
2068
  }
2030
- const schema = operation.requestBody?.content?.["multipart/form-data"].schema;
2069
+ const schema = operation.requestBody?.content?.[CONTENT_TYPES.MULTIPART].schema;
2031
2070
  let resolvedSchema = schema;
2032
2071
  if (schema?.$ref) {
2033
2072
  resolvedSchema = this.parser.resolveReference(schema.$ref);
@@ -2058,11 +2097,42 @@ if (!headers.has('Content-Type')) {
2058
2097
  return `
2059
2098
  const formData = new FormData();
2060
2099
  ${formDataAppends}`;
2100
+ }
2101
+ generateUrlEncodedFormData(operation, context) {
2102
+ if (!context.isUrlEncoded || context.urlEncodedFields.length === 0) {
2103
+ return "";
2104
+ }
2105
+ const schema = operation.requestBody?.content?.[CONTENT_TYPES.FORM_URLENCODED].schema;
2106
+ let resolvedSchema = schema;
2107
+ if (schema?.$ref) {
2108
+ resolvedSchema = this.parser.resolveReference(schema.$ref);
2109
+ }
2110
+ const properties = resolvedSchema?.properties || {};
2111
+ const formBodyAppends = context.urlEncodedFields.map((field) => {
2112
+ const fieldSchema = properties[field];
2113
+ const isArray = fieldSchema?.type === "array";
2114
+ if (isArray) {
2115
+ return `if (${field} !== undefined && Array.isArray(${field})) {
2116
+ ${field}.forEach((item) => {
2117
+ if (item !== undefined && item !== null) {
2118
+ formBody.append('${field}', String(item));
2119
+ }
2120
+ });
2121
+ }`;
2122
+ } else {
2123
+ return `if (${field} !== undefined && ${field} !== null) {
2124
+ formBody.append('${field}', String(${field}));
2125
+ }`;
2126
+ }
2127
+ }).join("\n");
2128
+ return `
2129
+ const formBody = new URLSearchParams();
2130
+ ${formBodyAppends}`;
2061
2131
  }
2062
2132
  generateRequestOptions(context) {
2063
2133
  const options = [];
2064
2134
  options.push("observe: observe as any");
2065
- const hasHeaders = this.config.options.customHeaders || context.isMultipart;
2135
+ const hasHeaders = this.config.options.customHeaders || context.isMultipart || context.isUrlEncoded;
2066
2136
  if (hasHeaders) {
2067
2137
  options.push("headers");
2068
2138
  }
@@ -2087,7 +2157,9 @@ const requestOptions: any = {
2087
2157
  if (context.hasBody) {
2088
2158
  if (context.isMultipart) {
2089
2159
  bodyParam = "formData";
2090
- } else if (operation.requestBody?.content?.["application/json"]) {
2160
+ } else if (context.isUrlEncoded) {
2161
+ bodyParam = "formBody.toString()";
2162
+ } else if (operation.requestBody?.content?.[CONTENT_TYPES.JSON]) {
2091
2163
  const bodyType = getRequestBodyType(operation.requestBody, this.config);
2092
2164
  const isInterface = isDataTypeInterface(bodyType);
2093
2165
  bodyParam = isInterface ? camelCase(bodyType) : "requestBody";
@@ -2162,28 +2234,28 @@ var ServiceMethodParamsGenerator = class {
2162
2234
  hasQuestionToken: !param.required
2163
2235
  });
2164
2236
  });
2165
- if (operation.requestBody && operation.requestBody?.content?.["multipart/form-data"]) {
2166
- const schema = operation.requestBody.content["multipart/form-data"].schema;
2167
- let resolvedSchema = schema;
2168
- if (schema?.$ref) {
2169
- resolvedSchema = this.parser.resolveReference(schema.$ref);
2237
+ const requestBody = operation.requestBody;
2238
+ if (requestBody) {
2239
+ const formDataContent = requestBody.content?.[CONTENT_TYPES.MULTIPART];
2240
+ const urlEncodedContent = requestBody.content?.[CONTENT_TYPES.FORM_URLENCODED];
2241
+ const jsonContent = requestBody.content?.[CONTENT_TYPES.JSON];
2242
+ if (formDataContent) {
2243
+ const formParams = this.convertObjectToSingleParams(formDataContent.schema);
2244
+ params.push(...formParams);
2245
+ }
2246
+ if (!jsonContent && urlEncodedContent) {
2247
+ const formParams = this.convertObjectToSingleParams(urlEncodedContent.schema);
2248
+ params.push(...formParams);
2170
2249
  }
2171
- Object.entries(resolvedSchema?.properties ?? {}).forEach(([key, value]) => {
2250
+ if (jsonContent && !formDataContent) {
2251
+ const bodyType = this.getRequestBodyType(requestBody);
2252
+ const isInterface = isDataTypeInterface(bodyType);
2172
2253
  params.push({
2173
- name: key,
2174
- type: getTypeScriptType(value, this.config, value.nullable),
2175
- hasQuestionToken: !resolvedSchema?.required?.includes(key)
2254
+ name: isInterface ? camelCase(bodyType) : "requestBody",
2255
+ type: bodyType,
2256
+ hasQuestionToken: !requestBody.required
2176
2257
  });
2177
- });
2178
- }
2179
- if (operation.requestBody && operation.requestBody?.content?.["application/json"]) {
2180
- const bodyType = this.getRequestBodyType(operation.requestBody);
2181
- const isInterface = isDataTypeInterface(bodyType);
2182
- params.push({
2183
- name: isInterface ? camelCase(bodyType) : "requestBody",
2184
- type: bodyType,
2185
- hasQuestionToken: !operation.requestBody.required
2186
- });
2258
+ }
2187
2259
  }
2188
2260
  const queryParams = operation.parameters?.filter((p) => p.in === "query") || [];
2189
2261
  queryParams.forEach((param) => {
@@ -2222,12 +2294,27 @@ var ServiceMethodParamsGenerator = class {
2222
2294
  }
2223
2295
  getRequestBodyType(requestBody) {
2224
2296
  const content = requestBody.content || {};
2225
- const jsonContent = content["application/json"];
2297
+ const jsonContent = content[CONTENT_TYPES.JSON];
2226
2298
  if (jsonContent?.schema) {
2227
2299
  return getTypeScriptType(jsonContent.schema, this.config, jsonContent.schema.nullable);
2228
2300
  }
2229
2301
  return "any";
2230
2302
  }
2303
+ convertObjectToSingleParams(schema) {
2304
+ const params = [];
2305
+ let resolvedSchema = schema;
2306
+ if (schema?.$ref) {
2307
+ resolvedSchema = this.parser.resolveReference(schema.$ref);
2308
+ }
2309
+ Object.entries(resolvedSchema?.properties ?? {}).forEach(([key, value]) => {
2310
+ params.push({
2311
+ name: key,
2312
+ type: getTypeScriptType(value, this.config, value.nullable),
2313
+ hasQuestionToken: !resolvedSchema?.required?.includes(key)
2314
+ });
2315
+ });
2316
+ return params;
2317
+ }
2231
2318
  };
2232
2319
 
2233
2320
  // src/lib/generators/service/service-method/service-method-overloads.generator.ts
package/index.d.ts CHANGED
@@ -13,7 +13,9 @@ interface MethodGenerationContext {
13
13
  }>;
14
14
  hasBody: boolean;
15
15
  isMultipart: boolean;
16
+ isUrlEncoded: boolean;
16
17
  formDataFields: string[];
18
+ urlEncodedFields: string[];
17
19
  responseType: "json" | "blob" | "arraybuffer" | "text";
18
20
  }
19
21
  interface TypeSchema {
@@ -259,6 +261,12 @@ declare function isDataTypeInterface(type: string): boolean;
259
261
 
260
262
  declare function generateParseRequestTypeParams(params: OptionalKind<ParameterDeclarationStructure>[]): string;
261
263
 
264
+ declare const CONTENT_TYPES: {
265
+ MULTIPART: string;
266
+ FORM_URLENCODED: string;
267
+ JSON: string;
268
+ };
269
+
262
270
  declare const TYPE_GENERATOR_HEADER_COMMENT: string;
263
271
  declare const SERVICE_INDEX_GENERATOR_HEADER_COMMENT: string;
264
272
  declare const SERVICE_GENERATOR_HEADER_COMMENT: (controllerName: string) => string;
@@ -278,4 +286,4 @@ declare function validateInput(inputPath: string): void;
278
286
  */
279
287
  declare function generateFromConfig(config: GeneratorConfig): Promise<void>;
280
288
 
281
- export { BASE_INTERCEPTOR_HEADER_COMMENT, type EnumValueObject, type GeneratorConfig, type GetMethodGenerationContext, HTTP_RESOURCE_GENERATOR_HEADER_COMMENT, type IPluginGenerator, type IPluginGeneratorClass, MAIN_INDEX_GENERATOR_HEADER_COMMENT, type MethodGenerationContext, type NgOpenapiClientConfig, PROVIDER_GENERATOR_HEADER_COMMENT, type Parameter, type PathInfo, type RequestBody, SERVICE_GENERATOR_HEADER_COMMENT, SERVICE_INDEX_GENERATOR_HEADER_COMMENT, type SwaggerDefinition, SwaggerParser, type SwaggerResponse, type SwaggerSpec, TYPE_GENERATOR_HEADER_COMMENT, type TypeSchema, ZOD_PLUGIN_GENERATOR_HEADER_COMMENT, ZOD_PLUGIN_INDEX_GENERATOR_HEADER_COMMENT, camelCase, escapeString, extractPaths, generateFromConfig, generateParseRequestTypeParams, getBasePathTokenName, getClientContextTokenName, getRequestBodyType, getResponseType, getResponseTypeFromResponse, getTypeScriptType, hasDuplicateFunctionNames, inferResponseTypeFromContentType, isDataTypeInterface, isPrimitiveType, kebabCase, nullableType, pascalCase, type placeHolder, screamingSnakeCase, validateInput };
289
+ export { BASE_INTERCEPTOR_HEADER_COMMENT, CONTENT_TYPES, type EnumValueObject, type GeneratorConfig, type GetMethodGenerationContext, HTTP_RESOURCE_GENERATOR_HEADER_COMMENT, type IPluginGenerator, type IPluginGeneratorClass, MAIN_INDEX_GENERATOR_HEADER_COMMENT, type MethodGenerationContext, type NgOpenapiClientConfig, PROVIDER_GENERATOR_HEADER_COMMENT, type Parameter, type PathInfo, type RequestBody, SERVICE_GENERATOR_HEADER_COMMENT, SERVICE_INDEX_GENERATOR_HEADER_COMMENT, type SwaggerDefinition, SwaggerParser, type SwaggerResponse, type SwaggerSpec, TYPE_GENERATOR_HEADER_COMMENT, type TypeSchema, ZOD_PLUGIN_GENERATOR_HEADER_COMMENT, ZOD_PLUGIN_INDEX_GENERATOR_HEADER_COMMENT, camelCase, escapeString, extractPaths, generateFromConfig, generateParseRequestTypeParams, getBasePathTokenName, getClientContextTokenName, getRequestBodyType, getResponseType, getResponseTypeFromResponse, getTypeScriptType, hasDuplicateFunctionNames, inferResponseTypeFromContentType, isDataTypeInterface, isPrimitiveType, kebabCase, nullableType, pascalCase, type placeHolder, screamingSnakeCase, validateInput };
package/index.js CHANGED
@@ -74,6 +74,7 @@ var __async = (__this, __arguments, generator) => {
74
74
  var index_exports = {};
75
75
  __export(index_exports, {
76
76
  BASE_INTERCEPTOR_HEADER_COMMENT: () => BASE_INTERCEPTOR_HEADER_COMMENT,
77
+ CONTENT_TYPES: () => CONTENT_TYPES,
77
78
  HTTP_RESOURCE_GENERATOR_HEADER_COMMENT: () => HTTP_RESOURCE_GENERATOR_HEADER_COMMENT,
78
79
  MAIN_INDEX_GENERATOR_HEADER_COMMENT: () => MAIN_INDEX_GENERATOR_HEADER_COMMENT,
79
80
  PROVIDER_GENERATOR_HEADER_COMMENT: () => PROVIDER_GENERATOR_HEADER_COMMENT,
@@ -179,6 +180,10 @@ function getTypeScriptType(schemaOrType, config, formatOrNullable, isNullable, c
179
180
  case "null":
180
181
  return "null";
181
182
  default:
183
+ if (Array.isArray(schema.type)) {
184
+ const types = schema.type.map((t) => getTypeScriptType(t, config, void 0, void 0, context));
185
+ return nullableType(types.join(" | "), nullable);
186
+ }
182
187
  return nullableType("any", nullable);
183
188
  }
184
189
  }
@@ -361,7 +366,7 @@ function inferResponseTypeFromContentType(contentType) {
361
366
  }
362
367
  return "text";
363
368
  }
364
- if (normalizedType === "application/x-www-form-urlencoded" || normalizedType === "multipart/form-data") {
369
+ if (normalizedType === "CONTENT_TYPES.FORM_URLENCODED" || normalizedType === "multipart/form-data") {
365
370
  return "text";
366
371
  }
367
372
  if (normalizedType === "application/javascript" || normalizedType === "application/typescript" || normalizedType === "application/css" || normalizedType === "application/yaml" || normalizedType === "application/x-yaml" || normalizedType === "application/toml") {
@@ -394,10 +399,17 @@ function getResponseType(response, config) {
394
399
  }
395
400
  __name(getResponseType, "getResponseType");
396
401
 
402
+ // ../shared/src/utils/content-types.constants.ts
403
+ var CONTENT_TYPES = {
404
+ MULTIPART: "multipart/form-data",
405
+ FORM_URLENCODED: "application/x-www-form-urlencoded",
406
+ JSON: "application/json"
407
+ };
408
+
397
409
  // ../shared/src/utils/functions/get-request-body-type.ts
398
410
  function getRequestBodyType(requestBody, config) {
399
411
  const content = requestBody.content || {};
400
- const jsonContent = content["application/json"];
412
+ const jsonContent = content[CONTENT_TYPES.JSON];
401
413
  if (jsonContent == null ? void 0 : jsonContent.schema) {
402
414
  return getTypeScriptType(jsonContent.schema, config, jsonContent.schema.nullable);
403
415
  }
@@ -1066,6 +1078,10 @@ var _TypeGenerator = class _TypeGenerator {
1066
1078
  case "null":
1067
1079
  return this.nullableType("null", isNullable);
1068
1080
  default:
1081
+ if (Array.isArray(type)) {
1082
+ const types = type.map((t) => this.mapSwaggerTypeToTypeScript(t, void 0, isNullable));
1083
+ return this.nullableType(types.join(" | "), isNullable);
1084
+ }
1069
1085
  return this.nullableType("any", isNullable);
1070
1086
  }
1071
1087
  }
@@ -2059,6 +2075,7 @@ var _ServiceMethodBodyGenerator = class _ServiceMethodBodyGenerator {
2059
2075
  this.generateQueryParams(context),
2060
2076
  this.generateHeaders(context),
2061
2077
  this.generateMultipartFormData(operation, context),
2078
+ this.generateUrlEncodedFormData(operation, context),
2062
2079
  this.generateRequestOptions(context),
2063
2080
  this.generateHttpRequest(operation, context)
2064
2081
  ];
@@ -2066,14 +2083,31 @@ var _ServiceMethodBodyGenerator = class _ServiceMethodBodyGenerator {
2066
2083
  }
2067
2084
  isMultipartFormData(operation) {
2068
2085
  var _a, _b;
2069
- return !!((_b = (_a = operation.requestBody) == null ? void 0 : _a.content) == null ? void 0 : _b["multipart/form-data"]);
2086
+ return !!((_b = (_a = operation.requestBody) == null ? void 0 : _a.content) == null ? void 0 : _b[CONTENT_TYPES.MULTIPART]);
2087
+ }
2088
+ isUrlEncodedFormData(operation) {
2089
+ var _a, _b, _c, _d;
2090
+ return !!((_b = (_a = operation.requestBody) == null ? void 0 : _a.content) == null ? void 0 : _b[CONTENT_TYPES.FORM_URLENCODED]) && !((_d = (_c = operation.requestBody) == null ? void 0 : _c.content) == null ? void 0 : _d[CONTENT_TYPES.JSON]);
2070
2091
  }
2071
2092
  getFormDataFields(operation) {
2072
2093
  var _a, _b;
2073
2094
  if (!this.isMultipartFormData(operation)) {
2074
2095
  return [];
2075
2096
  }
2076
- const schema = (_b = (_a = operation.requestBody) == null ? void 0 : _a.content) == null ? void 0 : _b["multipart/form-data"].schema;
2097
+ const schema = (_b = (_a = operation.requestBody) == null ? void 0 : _a.content) == null ? void 0 : _b[CONTENT_TYPES.MULTIPART].schema;
2098
+ let resolvedSchema = schema;
2099
+ if (schema == null ? void 0 : schema.$ref) {
2100
+ resolvedSchema = this.parser.resolveReference(schema.$ref);
2101
+ }
2102
+ const properties = (resolvedSchema == null ? void 0 : resolvedSchema.properties) || {};
2103
+ return Object.keys(properties);
2104
+ }
2105
+ getUrlEncodedFields(operation) {
2106
+ var _a, _b;
2107
+ if (!this.isUrlEncodedFormData(operation)) {
2108
+ return [];
2109
+ }
2110
+ const schema = (_b = (_a = operation.requestBody) == null ? void 0 : _a.content) == null ? void 0 : _b[CONTENT_TYPES.FORM_URLENCODED].schema;
2077
2111
  let resolvedSchema = schema;
2078
2112
  if (schema == null ? void 0 : schema.$ref) {
2079
2113
  resolvedSchema = this.parser.resolveReference(schema.$ref);
@@ -2088,7 +2122,9 @@ var _ServiceMethodBodyGenerator = class _ServiceMethodBodyGenerator {
2088
2122
  queryParams: ((_b = operation.parameters) == null ? void 0 : _b.filter((p) => p.in === "query")) || [],
2089
2123
  hasBody: !!operation.requestBody,
2090
2124
  isMultipart: this.isMultipartFormData(operation),
2125
+ isUrlEncoded: this.isUrlEncodedFormData(operation),
2091
2126
  formDataFields: this.getFormDataFields(operation),
2127
+ urlEncodedFields: this.getUrlEncodedFields(operation),
2092
2128
  responseType: this.determineResponseType(operation)
2093
2129
  };
2094
2130
  }
@@ -2114,7 +2150,7 @@ ${paramMappings}`;
2114
2150
  }
2115
2151
  generateHeaders(context) {
2116
2152
  const hasCustomHeaders = this.config.options.customHeaders;
2117
- if (!hasCustomHeaders && !context.isMultipart) {
2153
+ if (!hasCustomHeaders && !context.isMultipart && !context.isUrlEncoded) {
2118
2154
  return "";
2119
2155
  }
2120
2156
  let headerCode = `
@@ -2135,7 +2171,13 @@ ${Object.entries(this.config.options.customHeaders || {}).map(([key, value]) =>
2135
2171
  headerCode += `
2136
2172
  // Remove Content-Type for multipart (browser will set it with boundary)
2137
2173
  headers = headers.delete('Content-Type');`;
2138
- } else if (!context.isMultipart) {
2174
+ } else if (context.isUrlEncoded) {
2175
+ headerCode += `
2176
+ // Set Content-Type for URL-encoded form data
2177
+ if (!headers.has('Content-Type')) {
2178
+ headers = headers.set('Content-Type', 'application/x-www-form-urlencoded');
2179
+ }`;
2180
+ } else {
2139
2181
  headerCode += `
2140
2182
  // Set Content-Type for JSON requests if not already set
2141
2183
  if (!headers.has('Content-Type')) {
@@ -2149,7 +2191,7 @@ if (!headers.has('Content-Type')) {
2149
2191
  if (!context.isMultipart || context.formDataFields.length === 0) {
2150
2192
  return "";
2151
2193
  }
2152
- const schema = (_b = (_a = operation.requestBody) == null ? void 0 : _a.content) == null ? void 0 : _b["multipart/form-data"].schema;
2194
+ const schema = (_b = (_a = operation.requestBody) == null ? void 0 : _a.content) == null ? void 0 : _b[CONTENT_TYPES.MULTIPART].schema;
2153
2195
  let resolvedSchema = schema;
2154
2196
  if (schema == null ? void 0 : schema.$ref) {
2155
2197
  resolvedSchema = this.parser.resolveReference(schema.$ref);
@@ -2180,11 +2222,43 @@ if (!headers.has('Content-Type')) {
2180
2222
  return `
2181
2223
  const formData = new FormData();
2182
2224
  ${formDataAppends}`;
2225
+ }
2226
+ generateUrlEncodedFormData(operation, context) {
2227
+ var _a, _b;
2228
+ if (!context.isUrlEncoded || context.urlEncodedFields.length === 0) {
2229
+ return "";
2230
+ }
2231
+ const schema = (_b = (_a = operation.requestBody) == null ? void 0 : _a.content) == null ? void 0 : _b[CONTENT_TYPES.FORM_URLENCODED].schema;
2232
+ let resolvedSchema = schema;
2233
+ if (schema == null ? void 0 : schema.$ref) {
2234
+ resolvedSchema = this.parser.resolveReference(schema.$ref);
2235
+ }
2236
+ const properties = (resolvedSchema == null ? void 0 : resolvedSchema.properties) || {};
2237
+ const formBodyAppends = context.urlEncodedFields.map((field) => {
2238
+ const fieldSchema = properties[field];
2239
+ const isArray = (fieldSchema == null ? void 0 : fieldSchema.type) === "array";
2240
+ if (isArray) {
2241
+ return `if (${field} !== undefined && Array.isArray(${field})) {
2242
+ ${field}.forEach((item) => {
2243
+ if (item !== undefined && item !== null) {
2244
+ formBody.append('${field}', String(item));
2245
+ }
2246
+ });
2247
+ }`;
2248
+ } else {
2249
+ return `if (${field} !== undefined && ${field} !== null) {
2250
+ formBody.append('${field}', String(${field}));
2251
+ }`;
2252
+ }
2253
+ }).join("\n");
2254
+ return `
2255
+ const formBody = new URLSearchParams();
2256
+ ${formBodyAppends}`;
2183
2257
  }
2184
2258
  generateRequestOptions(context) {
2185
2259
  const options = [];
2186
2260
  options.push("observe: observe as any");
2187
- const hasHeaders = this.config.options.customHeaders || context.isMultipart;
2261
+ const hasHeaders = this.config.options.customHeaders || context.isMultipart || context.isUrlEncoded;
2188
2262
  if (hasHeaders) {
2189
2263
  options.push("headers");
2190
2264
  }
@@ -2210,7 +2284,9 @@ const requestOptions: any = {
2210
2284
  if (context.hasBody) {
2211
2285
  if (context.isMultipart) {
2212
2286
  bodyParam = "formData";
2213
- } else if ((_b = (_a = operation.requestBody) == null ? void 0 : _a.content) == null ? void 0 : _b["application/json"]) {
2287
+ } else if (context.isUrlEncoded) {
2288
+ bodyParam = "formBody.toString()";
2289
+ } else if ((_b = (_a = operation.requestBody) == null ? void 0 : _a.content) == null ? void 0 : _b[CONTENT_TYPES.JSON]) {
2214
2290
  const bodyType = getRequestBodyType(operation.requestBody, this.config);
2215
2291
  const isInterface = isDataTypeInterface(bodyType);
2216
2292
  bodyParam = isInterface ? camelCase(bodyType) : "requestBody";
@@ -2276,7 +2352,7 @@ var _ServiceMethodParamsGenerator = class _ServiceMethodParamsGenerator {
2276
2352
  return uniqueParams;
2277
2353
  }
2278
2354
  generateApiParameters(operation) {
2279
- var _a, _b, _c, _d, _e, _f, _g;
2355
+ var _a, _b, _c, _d, _e;
2280
2356
  const params = [];
2281
2357
  const pathParams = ((_a = operation.parameters) == null ? void 0 : _a.filter((p) => p.in === "path")) || [];
2282
2358
  pathParams.forEach((param) => {
@@ -2286,31 +2362,30 @@ var _ServiceMethodParamsGenerator = class _ServiceMethodParamsGenerator {
2286
2362
  hasQuestionToken: !param.required
2287
2363
  });
2288
2364
  });
2289
- if (operation.requestBody && ((_c = (_b = operation.requestBody) == null ? void 0 : _b.content) == null ? void 0 : _c["multipart/form-data"])) {
2290
- const schema = operation.requestBody.content["multipart/form-data"].schema;
2291
- let resolvedSchema = schema;
2292
- if (schema == null ? void 0 : schema.$ref) {
2293
- resolvedSchema = this.parser.resolveReference(schema.$ref);
2365
+ const requestBody = operation.requestBody;
2366
+ if (requestBody) {
2367
+ const formDataContent = (_b = requestBody.content) == null ? void 0 : _b[CONTENT_TYPES.MULTIPART];
2368
+ const urlEncodedContent = (_c = requestBody.content) == null ? void 0 : _c[CONTENT_TYPES.FORM_URLENCODED];
2369
+ const jsonContent = (_d = requestBody.content) == null ? void 0 : _d[CONTENT_TYPES.JSON];
2370
+ if (formDataContent) {
2371
+ const formParams = this.convertObjectToSingleParams(formDataContent.schema);
2372
+ params.push(...formParams);
2294
2373
  }
2295
- Object.entries((_d = resolvedSchema == null ? void 0 : resolvedSchema.properties) != null ? _d : {}).forEach(([key, value]) => {
2296
- var _a2;
2374
+ if (!jsonContent && urlEncodedContent) {
2375
+ const formParams = this.convertObjectToSingleParams(urlEncodedContent.schema);
2376
+ params.push(...formParams);
2377
+ }
2378
+ if (jsonContent && !formDataContent) {
2379
+ const bodyType = this.getRequestBodyType(requestBody);
2380
+ const isInterface = isDataTypeInterface(bodyType);
2297
2381
  params.push({
2298
- name: key,
2299
- type: getTypeScriptType(value, this.config, value.nullable),
2300
- hasQuestionToken: !((_a2 = resolvedSchema == null ? void 0 : resolvedSchema.required) == null ? void 0 : _a2.includes(key))
2382
+ name: isInterface ? camelCase(bodyType) : "requestBody",
2383
+ type: bodyType,
2384
+ hasQuestionToken: !requestBody.required
2301
2385
  });
2302
- });
2303
- }
2304
- if (operation.requestBody && ((_f = (_e = operation.requestBody) == null ? void 0 : _e.content) == null ? void 0 : _f["application/json"])) {
2305
- const bodyType = this.getRequestBodyType(operation.requestBody);
2306
- const isInterface = isDataTypeInterface(bodyType);
2307
- params.push({
2308
- name: isInterface ? camelCase(bodyType) : "requestBody",
2309
- type: bodyType,
2310
- hasQuestionToken: !operation.requestBody.required
2311
- });
2386
+ }
2312
2387
  }
2313
- const queryParams = ((_g = operation.parameters) == null ? void 0 : _g.filter((p) => p.in === "query")) || [];
2388
+ const queryParams = ((_e = operation.parameters) == null ? void 0 : _e.filter((p) => p.in === "query")) || [];
2314
2389
  queryParams.forEach((param) => {
2315
2390
  params.push({
2316
2391
  name: param.name,
@@ -2348,12 +2423,29 @@ var _ServiceMethodParamsGenerator = class _ServiceMethodParamsGenerator {
2348
2423
  }
2349
2424
  getRequestBodyType(requestBody) {
2350
2425
  const content = requestBody.content || {};
2351
- const jsonContent = content["application/json"];
2426
+ const jsonContent = content[CONTENT_TYPES.JSON];
2352
2427
  if (jsonContent == null ? void 0 : jsonContent.schema) {
2353
2428
  return getTypeScriptType(jsonContent.schema, this.config, jsonContent.schema.nullable);
2354
2429
  }
2355
2430
  return "any";
2356
2431
  }
2432
+ convertObjectToSingleParams(schema) {
2433
+ var _a;
2434
+ const params = [];
2435
+ let resolvedSchema = schema;
2436
+ if (schema == null ? void 0 : schema.$ref) {
2437
+ resolvedSchema = this.parser.resolveReference(schema.$ref);
2438
+ }
2439
+ Object.entries((_a = resolvedSchema == null ? void 0 : resolvedSchema.properties) != null ? _a : {}).forEach(([key, value]) => {
2440
+ var _a2;
2441
+ params.push({
2442
+ name: key,
2443
+ type: getTypeScriptType(value, this.config, value.nullable),
2444
+ hasQuestionToken: !((_a2 = resolvedSchema == null ? void 0 : resolvedSchema.required) == null ? void 0 : _a2.includes(key))
2445
+ });
2446
+ });
2447
+ return params;
2448
+ }
2357
2449
  };
2358
2450
  __name(_ServiceMethodParamsGenerator, "ServiceMethodParamsGenerator");
2359
2451
  var ServiceMethodParamsGenerator = _ServiceMethodParamsGenerator;
@@ -2801,6 +2893,7 @@ __name(generateFromConfig, "generateFromConfig");
2801
2893
  // Annotate the CommonJS export names for ESM import in node:
2802
2894
  0 && (module.exports = {
2803
2895
  BASE_INTERCEPTOR_HEADER_COMMENT,
2896
+ CONTENT_TYPES,
2804
2897
  HTTP_RESOURCE_GENERATOR_HEADER_COMMENT,
2805
2898
  MAIN_INDEX_GENERATOR_HEADER_COMMENT,
2806
2899
  PROVIDER_GENERATOR_HEADER_COMMENT,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ng-openapi",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "description": "Generate Angular services and TypeScript types from OpenAPI/Swagger specifications",
5
5
  "keywords": [
6
6
  "ng-openapi",