ng-openapi 0.1.8 → 0.1.9-pr-18-feature-schema-validation-18c9be1.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.
Files changed (4) hide show
  1. package/cli.cjs +178 -53
  2. package/index.d.ts +12 -2
  3. package/index.js +188 -53
  4. package/package.json +1 -1
package/cli.cjs CHANGED
@@ -115,6 +115,7 @@ __name(escapeString, "escapeString");
115
115
  // ../shared/src/utils/functions/collect-used-types.ts
116
116
  function collectUsedTypes(operations) {
117
117
  const usedTypes = /* @__PURE__ */ new Set();
118
+ usedTypes.add("RequestOptions");
118
119
  operations.forEach((operation) => {
119
120
  operation.parameters?.forEach((param) => {
120
121
  collectTypesFromSchema(param.schema || param, usedTypes);
@@ -387,6 +388,47 @@ function getResponseType(response, config) {
387
388
  }
388
389
  __name(getResponseType, "getResponseType");
389
390
 
391
+ // ../shared/src/utils/functions/get-request-body-type.ts
392
+ function getRequestBodyType(requestBody, config) {
393
+ const content = requestBody.content || {};
394
+ const jsonContent = content["application/json"];
395
+ if (jsonContent?.schema) {
396
+ return getTypeScriptType(jsonContent.schema, config, jsonContent.schema.nullable);
397
+ }
398
+ return "any";
399
+ }
400
+ __name(getRequestBodyType, "getRequestBodyType");
401
+
402
+ // ../shared/src/utils/functions/is-data-type-interface.ts
403
+ function isDataTypeInterface(type) {
404
+ const invalidTypes = [
405
+ "any",
406
+ "File",
407
+ "string",
408
+ "number",
409
+ "boolean",
410
+ "object",
411
+ "unknown",
412
+ "[]",
413
+ "Array"
414
+ ];
415
+ return !invalidTypes.some((invalidType) => type.includes(invalidType));
416
+ }
417
+ __name(isDataTypeInterface, "isDataTypeInterface");
418
+
419
+ // ../shared/src/utils/functions/generate-parse-request-type-params.ts
420
+ function generateParseRequestTypeParams(params) {
421
+ const bodyParam = params.find((param) => {
422
+ return typeof param.type === "string" && isDataTypeInterface(param.type);
423
+ });
424
+ if (bodyParam) {
425
+ const optional = bodyParam.hasQuestionToken ? " | undefined" : "";
426
+ return `${bodyParam.type}${optional}`;
427
+ }
428
+ return "";
429
+ }
430
+ __name(generateParseRequestTypeParams, "generateParseRequestTypeParams");
431
+
390
432
  // ../shared/src/config/constants.ts
391
433
  var disableLinting = `/* @ts-nocheck */
392
434
  /* eslint-disable */
@@ -629,6 +671,7 @@ var TypeGenerator = class _TypeGenerator {
629
671
  Object.entries(definitions).forEach(([name, definition]) => {
630
672
  this.generateInterface(name, definition);
631
673
  });
674
+ this.generateSdkTypes();
632
675
  this.sourceFile.formatText();
633
676
  this.sourceFile.saveSync();
634
677
  } catch (error) {
@@ -885,6 +928,86 @@ var TypeGenerator = class _TypeGenerator {
885
928
  escapeString(str) {
886
929
  return str.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
887
930
  }
931
+ generateSdkTypes() {
932
+ this.sourceFile.addImportDeclarations([
933
+ {
934
+ namedImports: [
935
+ "HttpContext",
936
+ "HttpHeaders"
937
+ ],
938
+ moduleSpecifier: "@angular/common/http"
939
+ }
940
+ ]);
941
+ const { response, request } = this.config.options.validation ?? {};
942
+ const typeParameters = [
943
+ "TResponseType extends 'arraybuffer' | 'blob' | 'json' | 'text'"
944
+ ];
945
+ const properties = [
946
+ {
947
+ name: "headers",
948
+ type: "HttpHeaders",
949
+ hasQuestionToken: true
950
+ },
951
+ {
952
+ name: "reportProgress",
953
+ type: "boolean",
954
+ hasQuestionToken: true
955
+ },
956
+ {
957
+ name: "responseType",
958
+ type: "TResponseType",
959
+ hasQuestionToken: true
960
+ },
961
+ {
962
+ name: "withCredentials",
963
+ type: "boolean",
964
+ hasQuestionToken: true
965
+ },
966
+ {
967
+ name: "context",
968
+ type: "HttpContext",
969
+ hasQuestionToken: true
970
+ }
971
+ ];
972
+ if (response) {
973
+ properties.push({
974
+ name: "parse",
975
+ type: "(response: unknown) => TReturnType",
976
+ hasQuestionToken: true
977
+ });
978
+ typeParameters.push("TReturnType");
979
+ const _typeParameters = [
980
+ ...typeParameters,
981
+ "TParamsObject = never"
982
+ ];
983
+ this.sourceFile.addInterface({
984
+ name: "RequestOptions",
985
+ isExported: true,
986
+ typeParameters: _typeParameters,
987
+ properties,
988
+ docs: [
989
+ "Request Options for Angular HttpClient requests without request parsing"
990
+ ]
991
+ });
992
+ }
993
+ if (request) {
994
+ properties.push({
995
+ name: "parseRequest",
996
+ type: "(params: TParamsObject) => void",
997
+ hasQuestionToken: true
998
+ });
999
+ typeParameters.push("TParamsObject");
1000
+ }
1001
+ this.sourceFile.addInterface({
1002
+ name: "RequestOptions",
1003
+ isExported: true,
1004
+ typeParameters,
1005
+ properties,
1006
+ docs: [
1007
+ "Request Options for Angular HttpClient requests"
1008
+ ]
1009
+ });
1010
+ }
888
1011
  };
889
1012
 
890
1013
  // src/lib/generators/utility/token.generator.ts
@@ -1705,14 +1828,6 @@ var ServiceMethodBodyGenerator = class {
1705
1828
  ];
1706
1829
  return bodyParts.filter(Boolean).join("\n");
1707
1830
  }
1708
- getRequestBodyType(requestBody) {
1709
- const content = requestBody.content || {};
1710
- const jsonContent = content["application/json"];
1711
- if (jsonContent?.schema) {
1712
- return getTypeScriptType(jsonContent.schema, this.config, jsonContent.schema.nullable);
1713
- }
1714
- return "any";
1715
- }
1716
1831
  isMultipartFormData(operation) {
1717
1832
  return !!operation.requestBody?.content?.["multipart/form-data"];
1718
1833
  }
@@ -1830,8 +1945,8 @@ const requestOptions: any = {
1830
1945
  if (context.isMultipart) {
1831
1946
  bodyParam = "formData";
1832
1947
  } else if (operation.requestBody?.content?.["application/json"]) {
1833
- const bodyType = this.getRequestBodyType(operation.requestBody);
1834
- const isInterface = this.isDataTypeInterface(bodyType);
1948
+ const bodyType = getRequestBodyType(operation.requestBody, this.config);
1949
+ const isInterface = isDataTypeInterface(bodyType);
1835
1950
  bodyParam = isInterface ? camelCase(bodyType) : "requestBody";
1836
1951
  }
1837
1952
  }
@@ -1840,12 +1955,13 @@ const requestOptions: any = {
1840
1955
  "put",
1841
1956
  "patch"
1842
1957
  ];
1958
+ const parseResponse = this.config.options.validation?.response ? `.pipe(map(response => options?.parse?.(response) ?? response))` : "";
1843
1959
  if (methodsWithBody.includes(httpMethod)) {
1844
1960
  return `
1845
- return this.httpClient.${httpMethod}(url, ${bodyParam || "null"}, requestOptions);`;
1961
+ return this.httpClient.${httpMethod}(url, ${bodyParam || "null"}, requestOptions)${parseResponse};`;
1846
1962
  } else {
1847
1963
  return `
1848
- return this.httpClient.${httpMethod}(url, requestOptions);`;
1964
+ return this.httpClient.${httpMethod}(url, requestOptions)${parseResponse};`;
1849
1965
  }
1850
1966
  }
1851
1967
  determineResponseType(operation) {
@@ -1863,19 +1979,10 @@ return this.httpClient.${httpMethod}(url, requestOptions);`;
1863
1979
  }
1864
1980
  return "json";
1865
1981
  }
1866
- isDataTypeInterface(type) {
1867
- const invalidTypes = [
1868
- "any",
1869
- "File",
1870
- "string",
1871
- "number",
1872
- "boolean",
1873
- "object",
1874
- "unknown",
1875
- "[]",
1876
- "Array"
1877
- ];
1878
- return !invalidTypes.some((invalidType) => type.includes(invalidType));
1982
+ generateParseRequestBody(operation) {
1983
+ if (this.config.options.validation?.request) {
1984
+ }
1985
+ return "";
1879
1986
  }
1880
1987
  };
1881
1988
 
@@ -1890,7 +1997,7 @@ var ServiceMethodParamsGenerator = class {
1890
1997
  }
1891
1998
  generateMethodParameters(operation) {
1892
1999
  const params = this.generateApiParameters(operation);
1893
- const optionsParam = this.addOptionsParameter();
2000
+ const optionsParam = this.addOptionsParameter(params);
1894
2001
  const combined = [
1895
2002
  ...params,
1896
2003
  ...optionsParam
@@ -1926,7 +2033,7 @@ var ServiceMethodParamsGenerator = class {
1926
2033
  }
1927
2034
  if (operation.requestBody && operation.requestBody?.content?.["application/json"]) {
1928
2035
  const bodyType = this.getRequestBodyType(operation.requestBody);
1929
- const isInterface = this.isDataTypeInterface(bodyType);
2036
+ const isInterface = isDataTypeInterface(bodyType);
1930
2037
  params.push({
1931
2038
  name: isInterface ? camelCase(bodyType) : "requestBody",
1932
2039
  type: bodyType,
@@ -1943,7 +2050,7 @@ var ServiceMethodParamsGenerator = class {
1943
2050
  });
1944
2051
  return params.sort((a, b) => Number(a.hasQuestionToken) - Number(b.hasQuestionToken));
1945
2052
  }
1946
- addOptionsParameter() {
2053
+ addOptionsParameter(params) {
1947
2054
  return [
1948
2055
  {
1949
2056
  name: "observe",
@@ -1952,24 +2059,25 @@ var ServiceMethodParamsGenerator = class {
1952
2059
  },
1953
2060
  {
1954
2061
  name: "options",
1955
- type: `{ headers?: HttpHeaders; params?: HttpParams; reportProgress?: boolean; responseType?: 'arraybuffer' | 'blob' | 'json' | 'text'; withCredentials?: boolean; context?: HttpContext; }`,
2062
+ type: this.getHttpRequestOptionsParameter(params),
1956
2063
  hasQuestionToken: true
1957
2064
  }
1958
2065
  ];
1959
2066
  }
1960
- isDataTypeInterface(type) {
1961
- const invalidTypes = [
1962
- "any",
1963
- "File",
1964
- "string",
1965
- "number",
1966
- "boolean",
1967
- "object",
1968
- "unknown",
1969
- "[]",
1970
- "Array"
1971
- ];
1972
- return !invalidTypes.some((invalidType) => type.includes(invalidType));
2067
+ getHttpRequestOptionsParameter(params) {
2068
+ const { response, request } = this.config.options.validation ?? {};
2069
+ const parseRequest = request ? generateParseRequestTypeParams(params) : "";
2070
+ const additionalTypeParameters = [];
2071
+ if (response) {
2072
+ additionalTypeParameters.push("any");
2073
+ }
2074
+ if (request && parseRequest) {
2075
+ additionalTypeParameters.push(parseRequest);
2076
+ }
2077
+ if (additionalTypeParameters.length === 0) {
2078
+ return `RequestOptions<'arraybuffer' | 'blob' | 'json' | 'text'>`;
2079
+ }
2080
+ return `RequestOptions<'arraybuffer' | 'blob' | 'json' | 'text', ${additionalTypeParameters.join(", ")}>`;
1973
2081
  }
1974
2082
  getRequestBodyType(requestBody) {
1975
2083
  const content = requestBody.content || {};
@@ -1988,6 +2096,7 @@ var ServiceMethodOverloadsGenerator = class {
1988
2096
  }
1989
2097
  config;
1990
2098
  paramsGenerator;
2099
+ responseDataType = "any";
1991
2100
  constructor(config) {
1992
2101
  this.config = config;
1993
2102
  this.paramsGenerator = new ServiceMethodParamsGenerator(config);
@@ -2009,9 +2118,9 @@ var ServiceMethodOverloadsGenerator = class {
2009
2118
  return overloads;
2010
2119
  }
2011
2120
  generateMethodOverload(operation, observe, responseType) {
2012
- const responseDataType = this.generateOverloadResponseType(operation);
2121
+ this.responseDataType = this.generateOverloadResponseType(operation);
2013
2122
  const params = this.generateOverloadParameters(operation, observe, responseType);
2014
- const returnType = this.generateOverloadReturnType(responseDataType, observe);
2123
+ const returnType = this.generateOverloadReturnType(observe);
2015
2124
  return {
2016
2125
  parameters: params,
2017
2126
  returnType
@@ -2019,7 +2128,7 @@ var ServiceMethodOverloadsGenerator = class {
2019
2128
  }
2020
2129
  generateOverloadParameters(operation, observe, responseType) {
2021
2130
  const params = this.paramsGenerator.generateApiParameters(operation);
2022
- const optionsParam = this.addOverloadOptionsParameter(observe, responseType);
2131
+ const optionsParam = this.addOverloadOptionsParameter(params, observe, responseType);
2023
2132
  const combined = [
2024
2133
  ...params,
2025
2134
  ...optionsParam
@@ -2034,7 +2143,7 @@ var ServiceMethodOverloadsGenerator = class {
2034
2143
  }
2035
2144
  return uniqueParams;
2036
2145
  }
2037
- addOverloadOptionsParameter(observe, responseType) {
2146
+ addOverloadOptionsParameter(params, observe, responseType) {
2038
2147
  return [
2039
2148
  {
2040
2149
  name: "observe",
@@ -2043,11 +2152,26 @@ var ServiceMethodOverloadsGenerator = class {
2043
2152
  },
2044
2153
  {
2045
2154
  name: "options",
2046
- type: `{ headers?: HttpHeaders; reportProgress?: boolean; responseType?: '${responseType}'; withCredentials?: boolean; context?: HttpContext; }`,
2155
+ type: this.getHttpRequestOptionsParameter(params, responseType),
2047
2156
  hasQuestionToken: true
2048
2157
  }
2049
2158
  ];
2050
2159
  }
2160
+ getHttpRequestOptionsParameter(params, responseType) {
2161
+ const { response, request } = this.config.options.validation ?? {};
2162
+ const parseRequest = request ? generateParseRequestTypeParams(params) : "";
2163
+ const additionalTypeParameters = [];
2164
+ if (response) {
2165
+ additionalTypeParameters.push(this.responseDataType);
2166
+ }
2167
+ if (request && parseRequest) {
2168
+ additionalTypeParameters.push(parseRequest);
2169
+ }
2170
+ if (additionalTypeParameters.length === 0) {
2171
+ return `RequestOptions<'${responseType}'>`;
2172
+ }
2173
+ return `RequestOptions<'${responseType}', ${additionalTypeParameters.join(", ")}>`;
2174
+ }
2051
2175
  generateOverloadResponseType(operation) {
2052
2176
  const response = operation.responses?.["200"] || operation.responses?.["201"] || operation.responses?.["204"];
2053
2177
  if (!response) {
@@ -2055,14 +2179,14 @@ var ServiceMethodOverloadsGenerator = class {
2055
2179
  }
2056
2180
  return getResponseType(response, this.config);
2057
2181
  }
2058
- generateOverloadReturnType(responseType, observe) {
2182
+ generateOverloadReturnType(observe) {
2059
2183
  switch (observe) {
2060
2184
  case "body":
2061
- return `Observable<${responseType}>`;
2185
+ return `Observable<${this.responseDataType}>`;
2062
2186
  case "response":
2063
- return `Observable<HttpResponse<${responseType}>>`;
2187
+ return `Observable<HttpResponse<${this.responseDataType}>>`;
2064
2188
  case "events":
2065
- return `Observable<HttpEvent<${responseType}>>`;
2189
+ return `Observable<HttpEvent<${this.responseDataType}>>`;
2066
2190
  default:
2067
2191
  throw new Error(`Unsupported observe type: ${observe}`);
2068
2192
  }
@@ -2231,7 +2355,8 @@ var ServiceGenerator = class _ServiceGenerator {
2231
2355
  },
2232
2356
  {
2233
2357
  namedImports: [
2234
- "Observable"
2358
+ "Observable",
2359
+ "map"
2235
2360
  ],
2236
2361
  moduleSpecifier: "rxjs"
2237
2362
  },
@@ -2439,7 +2564,7 @@ async function generateFromConfig(config) {
2439
2564
  __name(generateFromConfig, "generateFromConfig");
2440
2565
 
2441
2566
  // package.json
2442
- var version = "0.1.7";
2567
+ var version = "0.1.8";
2443
2568
 
2444
2569
  // src/lib/cli.ts
2445
2570
  var program = new import_commander.Command();
package/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Project, ScriptTarget, ModuleKind, MethodDeclaration, FunctionDeclaration } from 'ts-morph';
1
+ import { Project, ScriptTarget, ModuleKind, MethodDeclaration, FunctionDeclaration, OptionalKind, ParameterDeclarationStructure } from 'ts-morph';
2
2
  import { HttpInterceptor } from '@angular/common/http';
3
3
  import { Info, ExternalDocs, Path, ParameterType, XML, BodyParameter, QueryParameter, Security, Tag } from 'swagger-schema-official';
4
4
 
@@ -202,6 +202,10 @@ interface GeneratorConfig {
202
202
  options: {
203
203
  dateType: "string" | "Date";
204
204
  enumStyle: "enum" | "union";
205
+ validation?: {
206
+ response?: boolean;
207
+ request?: boolean;
208
+ };
205
209
  generateServices?: boolean;
206
210
  generateEnumBasedOnDescription?: boolean;
207
211
  customHeaders?: Record<string, string>;
@@ -261,6 +265,12 @@ declare function isPrimitiveType(schema: any): boolean;
261
265
  declare function inferResponseTypeFromContentType(contentType: string): "json" | "blob" | "arraybuffer" | "text";
262
266
  declare function getResponseType(response: SwaggerResponse, config: GeneratorConfig): string;
263
267
 
268
+ declare function getRequestBodyType(requestBody: RequestBody, config: GeneratorConfig): string;
269
+
270
+ declare function isDataTypeInterface(type: string): boolean;
271
+
272
+ declare function generateParseRequestTypeParams(params: OptionalKind<ParameterDeclarationStructure>[]): string;
273
+
264
274
  declare const TYPE_GENERATOR_HEADER_COMMENT: string;
265
275
  declare const SERVICE_INDEX_GENERATOR_HEADER_COMMENT: string;
266
276
  declare const SERVICE_GENERATOR_HEADER_COMMENT: (controllerName: string) => string;
@@ -278,4 +288,4 @@ declare function validateInput(inputPath: string): void;
278
288
  */
279
289
  declare function generateFromConfig(config: GeneratorConfig): Promise<void>;
280
290
 
281
- export { BASE_INTERCEPTOR_HEADER_COMMENT, type EnumValueObject, type GeneratorConfig, type GetMethodGenerationContext, HTTP_RESOURCE_GENERATOR_HEADER_COMMENT, type IPluginGenerator, type IPluginGeneratorClass, type IPluginGeneratorConstructor, 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, camelCase, collectUsedTypes, escapeString, extractPaths, generateFromConfig, getBasePathTokenName, getClientContextTokenName, getResponseType, getResponseTypeFromResponse, getTypeScriptType, hasDuplicateFunctionNames, inferResponseTypeFromContentType, isPrimitiveType, kebabCase, nullableType, pascalCase, type placeHolder, validateInput };
291
+ export { BASE_INTERCEPTOR_HEADER_COMMENT, type EnumValueObject, type GeneratorConfig, type GetMethodGenerationContext, HTTP_RESOURCE_GENERATOR_HEADER_COMMENT, type IPluginGenerator, type IPluginGeneratorClass, type IPluginGeneratorConstructor, 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, camelCase, collectUsedTypes, escapeString, extractPaths, generateFromConfig, generateParseRequestTypeParams, getBasePathTokenName, getClientContextTokenName, getRequestBodyType, getResponseType, getResponseTypeFromResponse, getTypeScriptType, hasDuplicateFunctionNames, inferResponseTypeFromContentType, isDataTypeInterface, isPrimitiveType, kebabCase, nullableType, pascalCase, type placeHolder, validateInput };
package/index.js CHANGED
@@ -86,13 +86,16 @@ __export(index_exports, {
86
86
  escapeString: () => escapeString,
87
87
  extractPaths: () => extractPaths,
88
88
  generateFromConfig: () => generateFromConfig,
89
+ generateParseRequestTypeParams: () => generateParseRequestTypeParams,
89
90
  getBasePathTokenName: () => getBasePathTokenName,
90
91
  getClientContextTokenName: () => getClientContextTokenName,
92
+ getRequestBodyType: () => getRequestBodyType,
91
93
  getResponseType: () => getResponseType,
92
94
  getResponseTypeFromResponse: () => getResponseTypeFromResponse,
93
95
  getTypeScriptType: () => getTypeScriptType,
94
96
  hasDuplicateFunctionNames: () => hasDuplicateFunctionNames,
95
97
  inferResponseTypeFromContentType: () => inferResponseTypeFromContentType,
98
+ isDataTypeInterface: () => isDataTypeInterface,
96
99
  isPrimitiveType: () => isPrimitiveType,
97
100
  kebabCase: () => kebabCase,
98
101
  nullableType: () => nullableType,
@@ -191,6 +194,7 @@ __name(escapeString, "escapeString");
191
194
  // ../shared/src/utils/functions/collect-used-types.ts
192
195
  function collectUsedTypes(operations) {
193
196
  const usedTypes = /* @__PURE__ */ new Set();
197
+ usedTypes.add("RequestOptions");
194
198
  operations.forEach((operation) => {
195
199
  var _a;
196
200
  (_a = operation.parameters) == null ? void 0 : _a.forEach((param) => {
@@ -465,6 +469,47 @@ function getResponseType(response, config) {
465
469
  }
466
470
  __name(getResponseType, "getResponseType");
467
471
 
472
+ // ../shared/src/utils/functions/get-request-body-type.ts
473
+ function getRequestBodyType(requestBody, config) {
474
+ const content = requestBody.content || {};
475
+ const jsonContent = content["application/json"];
476
+ if (jsonContent == null ? void 0 : jsonContent.schema) {
477
+ return getTypeScriptType(jsonContent.schema, config, jsonContent.schema.nullable);
478
+ }
479
+ return "any";
480
+ }
481
+ __name(getRequestBodyType, "getRequestBodyType");
482
+
483
+ // ../shared/src/utils/functions/is-data-type-interface.ts
484
+ function isDataTypeInterface(type) {
485
+ const invalidTypes = [
486
+ "any",
487
+ "File",
488
+ "string",
489
+ "number",
490
+ "boolean",
491
+ "object",
492
+ "unknown",
493
+ "[]",
494
+ "Array"
495
+ ];
496
+ return !invalidTypes.some((invalidType) => type.includes(invalidType));
497
+ }
498
+ __name(isDataTypeInterface, "isDataTypeInterface");
499
+
500
+ // ../shared/src/utils/functions/generate-parse-request-type-params.ts
501
+ function generateParseRequestTypeParams(params) {
502
+ const bodyParam = params.find((param) => {
503
+ return typeof param.type === "string" && isDataTypeInterface(param.type);
504
+ });
505
+ if (bodyParam) {
506
+ const optional = bodyParam.hasQuestionToken ? " | undefined" : "";
507
+ return `${bodyParam.type}${optional}`;
508
+ }
509
+ return "";
510
+ }
511
+ __name(generateParseRequestTypeParams, "generateParseRequestTypeParams");
512
+
468
513
  // ../shared/src/config/constants.ts
469
514
  var disableLinting = `/* @ts-nocheck */
470
515
  /* eslint-disable */
@@ -717,6 +762,7 @@ var _TypeGenerator = class _TypeGenerator {
717
762
  Object.entries(definitions).forEach(([name, definition]) => {
718
763
  this.generateInterface(name, definition);
719
764
  });
765
+ this.generateSdkTypes();
720
766
  this.sourceFile.formatText();
721
767
  this.sourceFile.saveSync();
722
768
  } catch (error) {
@@ -976,6 +1022,87 @@ var _TypeGenerator = class _TypeGenerator {
976
1022
  escapeString(str) {
977
1023
  return str.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
978
1024
  }
1025
+ generateSdkTypes() {
1026
+ var _a;
1027
+ this.sourceFile.addImportDeclarations([
1028
+ {
1029
+ namedImports: [
1030
+ "HttpContext",
1031
+ "HttpHeaders"
1032
+ ],
1033
+ moduleSpecifier: "@angular/common/http"
1034
+ }
1035
+ ]);
1036
+ const { response, request } = (_a = this.config.options.validation) != null ? _a : {};
1037
+ const typeParameters = [
1038
+ "TResponseType extends 'arraybuffer' | 'blob' | 'json' | 'text'"
1039
+ ];
1040
+ const properties = [
1041
+ {
1042
+ name: "headers",
1043
+ type: "HttpHeaders",
1044
+ hasQuestionToken: true
1045
+ },
1046
+ {
1047
+ name: "reportProgress",
1048
+ type: "boolean",
1049
+ hasQuestionToken: true
1050
+ },
1051
+ {
1052
+ name: "responseType",
1053
+ type: "TResponseType",
1054
+ hasQuestionToken: true
1055
+ },
1056
+ {
1057
+ name: "withCredentials",
1058
+ type: "boolean",
1059
+ hasQuestionToken: true
1060
+ },
1061
+ {
1062
+ name: "context",
1063
+ type: "HttpContext",
1064
+ hasQuestionToken: true
1065
+ }
1066
+ ];
1067
+ if (response) {
1068
+ properties.push({
1069
+ name: "parse",
1070
+ type: "(response: unknown) => TReturnType",
1071
+ hasQuestionToken: true
1072
+ });
1073
+ typeParameters.push("TReturnType");
1074
+ const _typeParameters = [
1075
+ ...typeParameters,
1076
+ "TParamsObject = never"
1077
+ ];
1078
+ this.sourceFile.addInterface({
1079
+ name: "RequestOptions",
1080
+ isExported: true,
1081
+ typeParameters: _typeParameters,
1082
+ properties,
1083
+ docs: [
1084
+ "Request Options for Angular HttpClient requests without request parsing"
1085
+ ]
1086
+ });
1087
+ }
1088
+ if (request) {
1089
+ properties.push({
1090
+ name: "parseRequest",
1091
+ type: "(params: TParamsObject) => void",
1092
+ hasQuestionToken: true
1093
+ });
1094
+ typeParameters.push("TParamsObject");
1095
+ }
1096
+ this.sourceFile.addInterface({
1097
+ name: "RequestOptions",
1098
+ isExported: true,
1099
+ typeParameters,
1100
+ properties,
1101
+ docs: [
1102
+ "Request Options for Angular HttpClient requests"
1103
+ ]
1104
+ });
1105
+ }
979
1106
  };
980
1107
  __name(_TypeGenerator, "TypeGenerator");
981
1108
  var TypeGenerator = _TypeGenerator;
@@ -1792,14 +1919,6 @@ var _ServiceMethodBodyGenerator = class _ServiceMethodBodyGenerator {
1792
1919
  ];
1793
1920
  return bodyParts.filter(Boolean).join("\n");
1794
1921
  }
1795
- getRequestBodyType(requestBody) {
1796
- const content = requestBody.content || {};
1797
- const jsonContent = content["application/json"];
1798
- if (jsonContent == null ? void 0 : jsonContent.schema) {
1799
- return getTypeScriptType(jsonContent.schema, this.config, jsonContent.schema.nullable);
1800
- }
1801
- return "any";
1802
- }
1803
1922
  isMultipartFormData(operation) {
1804
1923
  var _a, _b;
1805
1924
  return !!((_b = (_a = operation.requestBody) == null ? void 0 : _a.content) == null ? void 0 : _b["multipart/form-data"]);
@@ -1915,15 +2034,15 @@ const requestOptions: any = {
1915
2034
  };`;
1916
2035
  }
1917
2036
  generateHttpRequest(operation, context) {
1918
- var _a, _b;
2037
+ var _a, _b, _c;
1919
2038
  const httpMethod = operation.method.toLowerCase();
1920
2039
  let bodyParam = "";
1921
2040
  if (context.hasBody) {
1922
2041
  if (context.isMultipart) {
1923
2042
  bodyParam = "formData";
1924
2043
  } else if ((_b = (_a = operation.requestBody) == null ? void 0 : _a.content) == null ? void 0 : _b["application/json"]) {
1925
- const bodyType = this.getRequestBodyType(operation.requestBody);
1926
- const isInterface = this.isDataTypeInterface(bodyType);
2044
+ const bodyType = getRequestBodyType(operation.requestBody, this.config);
2045
+ const isInterface = isDataTypeInterface(bodyType);
1927
2046
  bodyParam = isInterface ? camelCase(bodyType) : "requestBody";
1928
2047
  }
1929
2048
  }
@@ -1932,12 +2051,13 @@ const requestOptions: any = {
1932
2051
  "put",
1933
2052
  "patch"
1934
2053
  ];
2054
+ const parseResponse = ((_c = this.config.options.validation) == null ? void 0 : _c.response) ? `.pipe(map(response => options?.parse?.(response) ?? response))` : "";
1935
2055
  if (methodsWithBody.includes(httpMethod)) {
1936
2056
  return `
1937
- return this.httpClient.${httpMethod}(url, ${bodyParam || "null"}, requestOptions);`;
2057
+ return this.httpClient.${httpMethod}(url, ${bodyParam || "null"}, requestOptions)${parseResponse};`;
1938
2058
  } else {
1939
2059
  return `
1940
- return this.httpClient.${httpMethod}(url, requestOptions);`;
2060
+ return this.httpClient.${httpMethod}(url, requestOptions)${parseResponse};`;
1941
2061
  }
1942
2062
  }
1943
2063
  determineResponseType(operation) {
@@ -1956,19 +2076,11 @@ return this.httpClient.${httpMethod}(url, requestOptions);`;
1956
2076
  }
1957
2077
  return "json";
1958
2078
  }
1959
- isDataTypeInterface(type) {
1960
- const invalidTypes = [
1961
- "any",
1962
- "File",
1963
- "string",
1964
- "number",
1965
- "boolean",
1966
- "object",
1967
- "unknown",
1968
- "[]",
1969
- "Array"
1970
- ];
1971
- return !invalidTypes.some((invalidType) => type.includes(invalidType));
2079
+ generateParseRequestBody(operation) {
2080
+ var _a;
2081
+ if ((_a = this.config.options.validation) == null ? void 0 : _a.request) {
2082
+ }
2083
+ return "";
1972
2084
  }
1973
2085
  };
1974
2086
  __name(_ServiceMethodBodyGenerator, "ServiceMethodBodyGenerator");
@@ -1982,7 +2094,7 @@ var _ServiceMethodParamsGenerator = class _ServiceMethodParamsGenerator {
1982
2094
  }
1983
2095
  generateMethodParameters(operation) {
1984
2096
  const params = this.generateApiParameters(operation);
1985
- const optionsParam = this.addOptionsParameter();
2097
+ const optionsParam = this.addOptionsParameter(params);
1986
2098
  const combined = [
1987
2099
  ...params,
1988
2100
  ...optionsParam
@@ -2019,7 +2131,7 @@ var _ServiceMethodParamsGenerator = class _ServiceMethodParamsGenerator {
2019
2131
  }
2020
2132
  if (operation.requestBody && ((_i = (_h = operation.requestBody) == null ? void 0 : _h.content) == null ? void 0 : _i["application/json"])) {
2021
2133
  const bodyType = this.getRequestBodyType(operation.requestBody);
2022
- const isInterface = this.isDataTypeInterface(bodyType);
2134
+ const isInterface = isDataTypeInterface(bodyType);
2023
2135
  params.push({
2024
2136
  name: isInterface ? camelCase(bodyType) : "requestBody",
2025
2137
  type: bodyType,
@@ -2036,7 +2148,7 @@ var _ServiceMethodParamsGenerator = class _ServiceMethodParamsGenerator {
2036
2148
  });
2037
2149
  return params.sort((a, b) => Number(a.hasQuestionToken) - Number(b.hasQuestionToken));
2038
2150
  }
2039
- addOptionsParameter() {
2151
+ addOptionsParameter(params) {
2040
2152
  return [
2041
2153
  {
2042
2154
  name: "observe",
@@ -2045,24 +2157,26 @@ var _ServiceMethodParamsGenerator = class _ServiceMethodParamsGenerator {
2045
2157
  },
2046
2158
  {
2047
2159
  name: "options",
2048
- type: `{ headers?: HttpHeaders; params?: HttpParams; reportProgress?: boolean; responseType?: 'arraybuffer' | 'blob' | 'json' | 'text'; withCredentials?: boolean; context?: HttpContext; }`,
2160
+ type: this.getHttpRequestOptionsParameter(params),
2049
2161
  hasQuestionToken: true
2050
2162
  }
2051
2163
  ];
2052
2164
  }
2053
- isDataTypeInterface(type) {
2054
- const invalidTypes = [
2055
- "any",
2056
- "File",
2057
- "string",
2058
- "number",
2059
- "boolean",
2060
- "object",
2061
- "unknown",
2062
- "[]",
2063
- "Array"
2064
- ];
2065
- return !invalidTypes.some((invalidType) => type.includes(invalidType));
2165
+ getHttpRequestOptionsParameter(params) {
2166
+ var _a;
2167
+ const { response, request } = (_a = this.config.options.validation) != null ? _a : {};
2168
+ const parseRequest = request ? generateParseRequestTypeParams(params) : "";
2169
+ const additionalTypeParameters = [];
2170
+ if (response) {
2171
+ additionalTypeParameters.push("any");
2172
+ }
2173
+ if (request && parseRequest) {
2174
+ additionalTypeParameters.push(parseRequest);
2175
+ }
2176
+ if (additionalTypeParameters.length === 0) {
2177
+ return `RequestOptions<'arraybuffer' | 'blob' | 'json' | 'text'>`;
2178
+ }
2179
+ return `RequestOptions<'arraybuffer' | 'blob' | 'json' | 'text', ${additionalTypeParameters.join(", ")}>`;
2066
2180
  }
2067
2181
  getRequestBodyType(requestBody) {
2068
2182
  const content = requestBody.content || {};
@@ -2081,6 +2195,7 @@ var _ServiceMethodOverloadsGenerator = class _ServiceMethodOverloadsGenerator {
2081
2195
  constructor(config) {
2082
2196
  __publicField(this, "config");
2083
2197
  __publicField(this, "paramsGenerator");
2198
+ __publicField(this, "responseDataType", "any");
2084
2199
  this.config = config;
2085
2200
  this.paramsGenerator = new ServiceMethodParamsGenerator(config);
2086
2201
  }
@@ -2101,9 +2216,9 @@ var _ServiceMethodOverloadsGenerator = class _ServiceMethodOverloadsGenerator {
2101
2216
  return overloads;
2102
2217
  }
2103
2218
  generateMethodOverload(operation, observe, responseType) {
2104
- const responseDataType = this.generateOverloadResponseType(operation);
2219
+ this.responseDataType = this.generateOverloadResponseType(operation);
2105
2220
  const params = this.generateOverloadParameters(operation, observe, responseType);
2106
- const returnType = this.generateOverloadReturnType(responseDataType, observe);
2221
+ const returnType = this.generateOverloadReturnType(observe);
2107
2222
  return {
2108
2223
  parameters: params,
2109
2224
  returnType
@@ -2111,7 +2226,7 @@ var _ServiceMethodOverloadsGenerator = class _ServiceMethodOverloadsGenerator {
2111
2226
  }
2112
2227
  generateOverloadParameters(operation, observe, responseType) {
2113
2228
  const params = this.paramsGenerator.generateApiParameters(operation);
2114
- const optionsParam = this.addOverloadOptionsParameter(observe, responseType);
2229
+ const optionsParam = this.addOverloadOptionsParameter(params, observe, responseType);
2115
2230
  const combined = [
2116
2231
  ...params,
2117
2232
  ...optionsParam
@@ -2126,7 +2241,7 @@ var _ServiceMethodOverloadsGenerator = class _ServiceMethodOverloadsGenerator {
2126
2241
  }
2127
2242
  return uniqueParams;
2128
2243
  }
2129
- addOverloadOptionsParameter(observe, responseType) {
2244
+ addOverloadOptionsParameter(params, observe, responseType) {
2130
2245
  return [
2131
2246
  {
2132
2247
  name: "observe",
@@ -2135,11 +2250,27 @@ var _ServiceMethodOverloadsGenerator = class _ServiceMethodOverloadsGenerator {
2135
2250
  },
2136
2251
  {
2137
2252
  name: "options",
2138
- type: `{ headers?: HttpHeaders; reportProgress?: boolean; responseType?: '${responseType}'; withCredentials?: boolean; context?: HttpContext; }`,
2253
+ type: this.getHttpRequestOptionsParameter(params, responseType),
2139
2254
  hasQuestionToken: true
2140
2255
  }
2141
2256
  ];
2142
2257
  }
2258
+ getHttpRequestOptionsParameter(params, responseType) {
2259
+ var _a;
2260
+ const { response, request } = (_a = this.config.options.validation) != null ? _a : {};
2261
+ const parseRequest = request ? generateParseRequestTypeParams(params) : "";
2262
+ const additionalTypeParameters = [];
2263
+ if (response) {
2264
+ additionalTypeParameters.push(this.responseDataType);
2265
+ }
2266
+ if (request && parseRequest) {
2267
+ additionalTypeParameters.push(parseRequest);
2268
+ }
2269
+ if (additionalTypeParameters.length === 0) {
2270
+ return `RequestOptions<'${responseType}'>`;
2271
+ }
2272
+ return `RequestOptions<'${responseType}', ${additionalTypeParameters.join(", ")}>`;
2273
+ }
2143
2274
  generateOverloadResponseType(operation) {
2144
2275
  var _a, _b, _c;
2145
2276
  const response = ((_a = operation.responses) == null ? void 0 : _a["200"]) || ((_b = operation.responses) == null ? void 0 : _b["201"]) || ((_c = operation.responses) == null ? void 0 : _c["204"]);
@@ -2148,14 +2279,14 @@ var _ServiceMethodOverloadsGenerator = class _ServiceMethodOverloadsGenerator {
2148
2279
  }
2149
2280
  return getResponseType(response, this.config);
2150
2281
  }
2151
- generateOverloadReturnType(responseType, observe) {
2282
+ generateOverloadReturnType(observe) {
2152
2283
  switch (observe) {
2153
2284
  case "body":
2154
- return `Observable<${responseType}>`;
2285
+ return `Observable<${this.responseDataType}>`;
2155
2286
  case "response":
2156
- return `Observable<HttpResponse<${responseType}>>`;
2287
+ return `Observable<HttpResponse<${this.responseDataType}>>`;
2157
2288
  case "events":
2158
- return `Observable<HttpEvent<${responseType}>>`;
2289
+ return `Observable<HttpEvent<${this.responseDataType}>>`;
2159
2290
  default:
2160
2291
  throw new Error(`Unsupported observe type: ${observe}`);
2161
2292
  }
@@ -2325,7 +2456,8 @@ var _ServiceGenerator = class _ServiceGenerator {
2325
2456
  },
2326
2457
  {
2327
2458
  namedImports: [
2328
- "Observable"
2459
+ "Observable",
2460
+ "map"
2329
2461
  ],
2330
2462
  moduleSpecifier: "rxjs"
2331
2463
  },
@@ -2549,13 +2681,16 @@ __name(generateFromConfig, "generateFromConfig");
2549
2681
  escapeString,
2550
2682
  extractPaths,
2551
2683
  generateFromConfig,
2684
+ generateParseRequestTypeParams,
2552
2685
  getBasePathTokenName,
2553
2686
  getClientContextTokenName,
2687
+ getRequestBodyType,
2554
2688
  getResponseType,
2555
2689
  getResponseTypeFromResponse,
2556
2690
  getTypeScriptType,
2557
2691
  hasDuplicateFunctionNames,
2558
2692
  inferResponseTypeFromContentType,
2693
+ isDataTypeInterface,
2559
2694
  isPrimitiveType,
2560
2695
  kebabCase,
2561
2696
  nullableType,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ng-openapi",
3
- "version": "0.1.8",
3
+ "version": "0.1.9-pr-18-feature-schema-validation-18c9be1.0",
4
4
  "description": "Generate Angular services and TypeScript types from OpenAPI/Swagger specifications",
5
5
  "keywords": [
6
6
  "ng-openapi",