diff --git a/docs/generators/typescript-angular.md b/docs/generators/typescript-angular.md index e3a8ba54e386..fb71f6034b54 100644 --- a/docs/generators/typescript-angular.md +++ b/docs/generators/typescript-angular.md @@ -107,6 +107,8 @@ These options may be applied as additional-properties (cli) or configOptions (pl
  • ReturnType
  • Set
  • String
  • +
  • Temporal.Instant
  • +
  • Temporal.PlainDate
  • ThisParameterType
  • ThisType
  • Uncapitalize
  • diff --git a/docs/generators/typescript-aurelia.md b/docs/generators/typescript-aurelia.md index 5a75ef803916..8b7a924ed6e0 100644 --- a/docs/generators/typescript-aurelia.md +++ b/docs/generators/typescript-aurelia.md @@ -86,6 +86,8 @@ These options may be applied as additional-properties (cli) or configOptions (pl
  • ReturnType
  • Set
  • String
  • +
  • Temporal.Instant
  • +
  • Temporal.PlainDate
  • ThisParameterType
  • ThisType
  • Uncapitalize
  • diff --git a/docs/generators/typescript-axios.md b/docs/generators/typescript-axios.md index 09cb16e27759..f54f4377d76a 100644 --- a/docs/generators/typescript-axios.md +++ b/docs/generators/typescript-axios.md @@ -98,6 +98,8 @@ These options may be applied as additional-properties (cli) or configOptions (pl
  • ReturnType
  • Set
  • String
  • +
  • Temporal.Instant
  • +
  • Temporal.PlainDate
  • ThisParameterType
  • ThisType
  • Uncapitalize
  • diff --git a/docs/generators/typescript-fetch.md b/docs/generators/typescript-fetch.md index 37762fabc0d9..b9a8b0f67693 100644 --- a/docs/generators/typescript-fetch.md +++ b/docs/generators/typescript-fetch.md @@ -43,6 +43,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl |sortParamsByRequiredFlag|Sort method arguments to place required parameters before optional parameters.| |true| |stringEnums|Generate string enums instead of objects for enum values.| |false| |supportsES6|Generate code that conforms to ES6.| |false| +|temporal|Setting this property to true will use Temporal data types instead of Date.| |false| |useSingleRequestParameter|Setting this property to true will generate functions with a single argument containing all API endpoint parameters instead of one argument per parameter.| |true| |useSquareBracketsInArrayNames|Setting this property to true will add brackets to array attribute names, e.g. my_values[].| |false| |validationAttributes|Setting this property to true will generate the validation attributes of model properties.| |false| @@ -98,6 +99,8 @@ These options may be applied as additional-properties (cli) or configOptions (pl
  • ReturnType
  • Set
  • String
  • +
  • Temporal.Instant
  • +
  • Temporal.PlainDate
  • ThisParameterType
  • ThisType
  • Uncapitalize
  • diff --git a/docs/generators/typescript-inversify.md b/docs/generators/typescript-inversify.md index 0060e8f01eb6..99561f00c1f8 100644 --- a/docs/generators/typescript-inversify.md +++ b/docs/generators/typescript-inversify.md @@ -92,6 +92,8 @@ These options may be applied as additional-properties (cli) or configOptions (pl
  • ReturnType
  • Set
  • String
  • +
  • Temporal.Instant
  • +
  • Temporal.PlainDate
  • ThisParameterType
  • ThisType
  • Uncapitalize
  • diff --git a/docs/generators/typescript-jquery.md b/docs/generators/typescript-jquery.md index c7c9851e3dd0..52b6852a5d60 100644 --- a/docs/generators/typescript-jquery.md +++ b/docs/generators/typescript-jquery.md @@ -88,6 +88,8 @@ These options may be applied as additional-properties (cli) or configOptions (pl
  • ReturnType
  • Set
  • String
  • +
  • Temporal.Instant
  • +
  • Temporal.PlainDate
  • ThisParameterType
  • ThisType
  • Uncapitalize
  • diff --git a/docs/generators/typescript-nestjs-server.md b/docs/generators/typescript-nestjs-server.md index 8017770b291d..da7a57a71239 100644 --- a/docs/generators/typescript-nestjs-server.md +++ b/docs/generators/typescript-nestjs-server.md @@ -99,6 +99,8 @@ These options may be applied as additional-properties (cli) or configOptions (pl
  • ReturnType
  • Set
  • String
  • +
  • Temporal.Instant
  • +
  • Temporal.PlainDate
  • ThisParameterType
  • ThisType
  • Uncapitalize
  • diff --git a/docs/generators/typescript-nestjs.md b/docs/generators/typescript-nestjs.md index 5c2b8d3cd002..9f967aef1a4f 100644 --- a/docs/generators/typescript-nestjs.md +++ b/docs/generators/typescript-nestjs.md @@ -98,6 +98,8 @@ These options may be applied as additional-properties (cli) or configOptions (pl
  • ReturnType
  • Set
  • String
  • +
  • Temporal.Instant
  • +
  • Temporal.PlainDate
  • ThisParameterType
  • ThisType
  • Uncapitalize
  • diff --git a/docs/generators/typescript-node.md b/docs/generators/typescript-node.md index f7521e158abd..65db791f5874 100644 --- a/docs/generators/typescript-node.md +++ b/docs/generators/typescript-node.md @@ -91,6 +91,8 @@ These options may be applied as additional-properties (cli) or configOptions (pl
  • ReturnType
  • Set
  • String
  • +
  • Temporal.Instant
  • +
  • Temporal.PlainDate
  • ThisParameterType
  • ThisType
  • Uncapitalize
  • diff --git a/docs/generators/typescript-redux-query.md b/docs/generators/typescript-redux-query.md index 55e71f159430..c2436fe66ac1 100644 --- a/docs/generators/typescript-redux-query.md +++ b/docs/generators/typescript-redux-query.md @@ -89,6 +89,8 @@ These options may be applied as additional-properties (cli) or configOptions (pl
  • ReturnType
  • Set
  • String
  • +
  • Temporal.Instant
  • +
  • Temporal.PlainDate
  • ThisParameterType
  • ThisType
  • Uncapitalize
  • diff --git a/docs/generators/typescript-rxjs.md b/docs/generators/typescript-rxjs.md index 9a7bdcf465fa..91a371def9c6 100644 --- a/docs/generators/typescript-rxjs.md +++ b/docs/generators/typescript-rxjs.md @@ -89,6 +89,8 @@ These options may be applied as additional-properties (cli) or configOptions (pl
  • ReturnType
  • Set
  • String
  • +
  • Temporal.Instant
  • +
  • Temporal.PlainDate
  • ThisParameterType
  • ThisType
  • Uncapitalize
  • diff --git a/docs/generators/typescript.md b/docs/generators/typescript.md index 57474571765c..325c1f183426 100644 --- a/docs/generators/typescript.md +++ b/docs/generators/typescript.md @@ -97,6 +97,8 @@ These options may be applied as additional-properties (cli) or configOptions (pl
  • ReturnType
  • Set
  • String
  • +
  • Temporal.Instant
  • +
  • Temporal.PlainDate
  • ThisParameterType
  • ThisType
  • Uncapitalize
  • diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptFetchClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptFetchClientCodegen.java index bc7473f9f861..7635b3f4459e 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptFetchClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/TypeScriptFetchClientCodegen.java @@ -74,6 +74,7 @@ public class TypeScriptFetchClientCodegen extends AbstractTypeScriptClientCodege public static final String USE_SQUARE_BRACKETS_IN_ARRAY_NAMES = "useSquareBracketsInArrayNames"; public static final String VALIDATION_ATTRIBUTES = "validationAttributes"; public static final String WITH_REQUEST_OPTS_IN_INTERFACE = "withRequestOptsInInterface"; + public static final String TEMPORAL = "temporal"; @Getter @Setter protected String npmRepository = null; @@ -134,6 +135,11 @@ public TypeScriptFetchClientCodegen() { this.addExtraReservedWords(); + languageSpecificPrimitives.addAll(Arrays.asList( + "Temporal.Instant", + "Temporal.PlainDate" + )); + supportModelPropertyNaming(CodegenConstants.MODEL_PROPERTY_NAMING_TYPE.camelCase); this.cliOptions.add(new CliOption(NPM_REPOSITORY, "Use this property to set an url your private npmRepo in the package.json")); this.cliOptions.add(new CliOption(WITH_INTERFACES, "Setting this property to true will generate interfaces next to the default class implementations.", SchemaTypeUtil.BOOLEAN_TYPE).defaultValue(Boolean.FALSE.toString())); @@ -147,6 +153,7 @@ public TypeScriptFetchClientCodegen() { this.cliOptions.add(new CliOption(USE_SQUARE_BRACKETS_IN_ARRAY_NAMES, "Setting this property to true will add brackets to array attribute names, e.g. my_values[].", SchemaTypeUtil.BOOLEAN_TYPE).defaultValue(Boolean.FALSE.toString())); this.cliOptions.add(new CliOption(VALIDATION_ATTRIBUTES, "Setting this property to true will generate the validation attributes of model properties.", SchemaTypeUtil.BOOLEAN_TYPE).defaultValue(Boolean.FALSE.toString())); this.cliOptions.add(new CliOption(WITH_REQUEST_OPTS_IN_INTERFACE, "Setting this property to true will include *RequestOpts methods in the API interface declarations. Set to false to keep them only on the class.", SchemaTypeUtil.BOOLEAN_TYPE).defaultValue(Boolean.TRUE.toString())); + this.cliOptions.add(new CliOption(TEMPORAL, "Setting this property to true will use Temporal data types instead of Date.", SchemaTypeUtil.BOOLEAN_TYPE).defaultValue(Boolean.FALSE.toString())); } @Override @@ -315,10 +322,19 @@ public void processOpts() { this.setFileNaming(additionalProperties.get(FILE_NAMING).toString()); } + if (additionalProperties.containsKey(TEMPORAL)) { + convertPropertyToBooleanAndWriteBack(TEMPORAL); + } + if (!withoutRuntimeChecks) { this.modelTemplateFiles.put("models.mustache", ".ts"); - typeMapping.put("date", "Date"); - typeMapping.put("DateTime", "Date"); + if (additionalProperties.containsKey(TEMPORAL) && Boolean.TRUE.equals(additionalProperties.get(TEMPORAL))) { + typeMapping.put("date", "Temporal.PlainDate"); + typeMapping.put("DateTime", "Temporal.Instant"); + } else { + typeMapping.put("date", "Date"); + typeMapping.put("DateTime", "Date"); + } } if (additionalProperties.containsKey(SAGAS_AND_RECORDS)) { @@ -1484,11 +1500,11 @@ public String getItemsDataType() { } public boolean isDateType() { - return isDate && "Date".equals(dataType); + return isDate && ("Date".equals(dataType) || "Temporal.PlainDate".equals(dataType)); } public boolean isDateTimeType() { - return isDateTime && "Date".equals(dataType); + return isDateTime && ("Date".equals(dataType) || "Temporal.Instant".equals(dataType)); } public ExtendedCodegenParameter(CodegenParameter cp) { @@ -1635,11 +1651,11 @@ public String getItemsDataType() { } public boolean isDateType() { - return isDate && "Date".equals(dataType); + return isDate && ("Date".equals(dataType) || "Temporal.PlainDate".equals(dataType)); } public boolean isDateTimeType() { - return isDateTime && "Date".equals(dataType); + return isDateTime && ("Date".equals(dataType) || "Temporal.Instant".equals(dataType)); } public ExtendedCodegenProperty(CodegenProperty cp) { @@ -1924,11 +1940,11 @@ public boolean hasSelfReferencingDiscriminatorMapping(){ return selfReferencingDiscriminatorMapping != null; } public boolean isDateType() { - return isDate && "Date".equals(dataType); + return isDate && ("Date".equals(dataType) || "Temporal.PlainDate".equals(dataType)); } public boolean isDateTimeType() { - return isDateTime && "Date".equals(dataType); + return isDateTime && ("Date".equals(dataType) || "Temporal.Instant".equals(dataType)); } public ExtendedCodegenModel(CodegenModel cm) { diff --git a/modules/openapi-generator/src/main/resources/typescript-fetch/apis.mustache b/modules/openapi-generator/src/main/resources/typescript-fetch/apis.mustache index 9958fe4a7b06..3cdac8199bf8 100644 --- a/modules/openapi-generator/src/main/resources/typescript-fetch/apis.mustache +++ b/modules/openapi-generator/src/main/resources/typescript-fetch/apis.mustache @@ -307,16 +307,28 @@ export class {{classname}} extends runtime.BaseAPI { let urlPath = `{{{path}}}`; {{#pathParams}} {{#isDateTimeType}} + {{#temporal}} + if (requestParameters['{{paramName}}'] instanceof Temporal.Instant) { + urlPath = urlPath.replace({{=<< >>=}}'{<>}'<<={{ }}=>>, encodeURIComponent(requestParameters['{{paramName}}'].toString())); + {{/temporal}} + {{^temporal}} if (requestParameters['{{paramName}}'] instanceof Date) { urlPath = urlPath.replace({{=<< >>=}}'{<>}'<<={{ }}=>>, encodeURIComponent(requestParameters['{{paramName}}'].toISOString())); + {{/temporal}} } else { urlPath = urlPath.replace({{=<< >>=}}'{<>}'<<={{ }}=>>, encodeURIComponent(String(requestParameters['{{paramName}}']))); } {{/isDateTimeType}} {{^isDateTimeType}} {{#isDateType}} + {{#temporal}} + if (requestParameters['{{paramName}}'] instanceof Temporal.PlainDate) { + urlPath = urlPath.replace({{=<< >>=}}'{<>}'<<={{ }}=>>, encodeURIComponent(requestParameters['{{paramName}}'].toString())); + {{/temporal}} + {{^temporal}} if (requestParameters['{{paramName}}'] instanceof Date) { urlPath = urlPath.replace({{=<< >>=}}'{<>}'<<={{ }}=>>, encodeURIComponent(requestParameters['{{paramName}}'].toISOString().substring(0,10))); + {{/temporal}} } else { urlPath = urlPath.replace({{=<< >>=}}'{<>}'<<={{ }}=>>, encodeURIComponent(String(requestParameters['{{paramName}}']))); } diff --git a/modules/openapi-generator/src/main/resources/typescript-fetch/apisAssignQueryParam.mustache b/modules/openapi-generator/src/main/resources/typescript-fetch/apisAssignQueryParam.mustache index 8da37374eea1..6eab346a788e 100644 --- a/modules/openapi-generator/src/main/resources/typescript-fetch/apisAssignQueryParam.mustache +++ b/modules/openapi-generator/src/main/resources/typescript-fetch/apisAssignQueryParam.mustache @@ -1,10 +1,10 @@ {{! Assign query parameters based on their type }} {{#isDateTimeType}} - queryParameters['{{baseName}}'] = (requestParameters['{{paramName}}'] as any).toISOString(); + queryParameters['{{baseName}}'] = {{#temporal}}(requestParameters['{{paramName}}'] as any).toString(){{/temporal}}{{^temporal}}(requestParameters['{{paramName}}'] as any).toISOString(){{/temporal}}; {{/isDateTimeType}} {{^isDateTimeType}} {{#isDateType}} - queryParameters['{{baseName}}'] = (requestParameters['{{paramName}}'] as any).toISOString().substring(0,10); + queryParameters['{{baseName}}'] = {{#temporal}}(requestParameters['{{paramName}}'] as any).toString(){{/temporal}}{{^temporal}}(requestParameters['{{paramName}}'] as any).toISOString().substring(0,10){{/temporal}}; {{/isDateType}} {{^isDateType}} queryParameters['{{baseName}}'] = requestParameters['{{paramName}}']; diff --git a/modules/openapi-generator/src/main/resources/typescript-fetch/apisFormParams.mustache b/modules/openapi-generator/src/main/resources/typescript-fetch/apisFormParams.mustache index 0b442d351275..de85cd59c7bb 100644 --- a/modules/openapi-generator/src/main/resources/typescript-fetch/apisFormParams.mustache +++ b/modules/openapi-generator/src/main/resources/typescript-fetch/apisFormParams.mustache @@ -37,7 +37,12 @@ {{^isArray}} if (requestParameters['{{paramName}}'] != null) { {{#isDateTimeType}} + {{#temporal}} + formParams.append('{{baseName}}', (requestParameters['{{paramName}}'] as any).toString()); + {{/temporal}} + {{^temporal}} formParams.append('{{baseName}}', (requestParameters['{{paramName}}'] as any).toISOString()); + {{/temporal}} {{/isDateTimeType}} {{^isDateTimeType}} {{#isPrimitiveType}} diff --git a/modules/openapi-generator/src/main/resources/typescript-fetch/modelGeneric.mustache b/modules/openapi-generator/src/main/resources/typescript-fetch/modelGeneric.mustache index e2a1fcf328bb..6232c211a0a0 100644 --- a/modules/openapi-generator/src/main/resources/typescript-fetch/modelGeneric.mustache +++ b/modules/openapi-generator/src/main/resources/typescript-fetch/modelGeneric.mustache @@ -98,10 +98,10 @@ export function {{classname}}FromJSONTyped(json: any, ignoreDiscriminator: boole {{/isArray}} {{^isArray}} {{#isDateType}} - '{{name}}': {{^required}}{{#isNullable}}json['{{baseName}}'] === undefined ? undefined : json['{{baseName}}'] === null ? null : {{/isNullable}}{{^isNullable}}json['{{baseName}}'] == null ? undefined : {{/isNullable}}{{/required}}({{#required}}{{#isNullable}}json['{{baseName}}'] == null ? null : {{/isNullable}}{{^isNullable}}json['{{baseName}}'] == null ? json['{{baseName}}'] : {{/isNullable}}{{/required}}new Date(json['{{baseName}}'])), + '{{name}}': {{^required}}{{#isNullable}}json['{{baseName}}'] === undefined ? undefined : json['{{baseName}}'] === null ? null : {{/isNullable}}{{^isNullable}}json['{{baseName}}'] == null ? undefined : {{/isNullable}}{{/required}}({{#required}}{{#isNullable}}json['{{baseName}}'] == null ? null : {{/isNullable}}{{^isNullable}}json['{{baseName}}'] == null ? json['{{baseName}}'] : {{/isNullable}}{{/required}}{{#temporal}}Temporal.PlainDate.from(json['{{baseName}}']){{/temporal}}{{^temporal}}new Date(json['{{baseName}}']){{/temporal}}), {{/isDateType}} {{#isDateTimeType}} - '{{name}}': {{^required}}{{#isNullable}}json['{{baseName}}'] === undefined ? undefined : json['{{baseName}}'] === null ? null : {{/isNullable}}{{^isNullable}}json['{{baseName}}'] == null ? undefined : {{/isNullable}}{{/required}}({{#required}}{{#isNullable}}json['{{baseName}}'] == null ? null : {{/isNullable}}{{^isNullable}}json['{{baseName}}'] == null ? json['{{baseName}}'] : {{/isNullable}}{{/required}}new Date(json['{{baseName}}'])), + '{{name}}': {{^required}}{{#isNullable}}json['{{baseName}}'] === undefined ? undefined : json['{{baseName}}'] === null ? null : {{/isNullable}}{{^isNullable}}json['{{baseName}}'] == null ? undefined : {{/isNullable}}{{/required}}({{#required}}{{#isNullable}}json['{{baseName}}'] == null ? null : {{/isNullable}}{{^isNullable}}json['{{baseName}}'] == null ? json['{{baseName}}'] : {{/isNullable}}{{/required}}{{#temporal}}Temporal.Instant.from(json['{{baseName}}']){{/temporal}}{{^temporal}}new Date(json['{{baseName}}']){{/temporal}}), {{/isDateTimeType}} {{^isDateType}} {{^isDateTimeType}} @@ -173,10 +173,10 @@ export function {{classname}}ToJSONTyped(value?: {{#hasReadOnly}}Omit<{{classnam {{^isReadOnly}} {{#isPrimitiveType}} {{#isDateType}} - '{{baseName}}': value['{{name}}'] == null ? value['{{name}}'] : value['{{name}}'].toISOString().substring(0,10), + '{{baseName}}': value['{{name}}'] == null ? value['{{name}}'] : {{#temporal}}value['{{name}}'].toString(){{/temporal}}{{^temporal}}value['{{name}}'].toISOString().substring(0,10){{/temporal}}, {{/isDateType}} {{#isDateTimeType}} - '{{baseName}}': value['{{name}}'] == null ? value['{{name}}'] : value['{{name}}'].toISOString(), + '{{baseName}}': value['{{name}}'] == null ? value['{{name}}'] : {{#temporal}}value['{{name}}'].toString(){{/temporal}}{{^temporal}}value['{{name}}'].toISOString(){{/temporal}}, {{/isDateTimeType}} {{#isArray}} '{{baseName}}': {{#uniqueItems}}{{^required}}value['{{name}}'] == null ? undefined : {{/required}}{{#required}}{{#isNullable}}value['{{name}}'] == null ? null : {{/isNullable}}{{/required}}Array.from(value['{{name}}'] as Set){{/uniqueItems}}{{^uniqueItems}}value['{{name}}']{{/uniqueItems}}, diff --git a/modules/openapi-generator/src/main/resources/typescript-fetch/modelOneOf.mustache b/modules/openapi-generator/src/main/resources/typescript-fetch/modelOneOf.mustache index 7017451090f8..b34a89fb878d 100644 --- a/modules/openapi-generator/src/main/resources/typescript-fetch/modelOneOf.mustache +++ b/modules/openapi-generator/src/main/resources/typescript-fetch/modelOneOf.mustache @@ -69,16 +69,30 @@ export function {{classname}}FromJSONTyped(json: any, ignoreDiscriminator: boole {{#items}} {{#isDateType}} if (Array.isArray(json)) { + {{#temporal}} + try { + return json.map(value => Temporal.PlainDate.from(value)); + } catch {} + {{/temporal}} + {{^temporal}} if (json.every(item => !(isNaN(new Date(item).getTime())))) { return json.map(value => new Date(value)); } + {{/temporal}} } {{/isDateType}} {{#isDateTimeType}} if (Array.isArray(json)) { + {{#temporal}} + try { + return json.map(value => Temporal.Instant.from(value)); + } catch {} + {{/temporal}} + {{^temporal}} if (json.every(item => !(isNaN(new Date(item).getTime())))) { return json.map(value => new Date(value)); } + {{/temporal}} } {{/isDateTimeType}} {{#isNumeric}} @@ -115,15 +129,29 @@ export function {{classname}}FromJSONTyped(json: any, ignoreDiscriminator: boole {{#oneOfPrimitives}} {{^isArray}} {{#isDateType}} + {{#temporal}} + try { + return {{^required}}json == null ? undefined : {{/required}}({{#required}}{{#isNullable}}json == null ? null : {{/isNullable}}{{/required}}Temporal.PlainDate.from(json)); + } catch {} + {{/temporal}} + {{^temporal}} if (!(isNaN(new Date(json).getTime()))) { return {{^required}}json == null ? undefined : {{/required}}({{#required}}{{#isNullable}}json == null ? null : {{/isNullable}}{{/required}}new Date(json)); } + {{/temporal}} {{/isDateType}} {{^isDateType}} {{#isDateTimeType}} + {{#temporal}} + try { + return {{^required}}json == null ? undefined : {{/required}}({{#required}}{{#isNullable}}json == null ? null : {{/isNullable}}{{/required}}Temporal.Instant.from(json)); + } catch {} + {{/temporal}} + {{^temporal}} if (!(isNaN(new Date(json).getTime()))) { return {{^required}}json == null ? undefined : {{/required}}({{#required}}{{#isNullable}}json == null ? null : {{/isNullable}}{{/required}}new Date(json)); } + {{/temporal}} {{/isDateTimeType}} {{/isDateType}} {{#isNumeric}} @@ -194,16 +222,30 @@ export function {{classname}}ToJSONTyped(value?: {{classname}} | null, ignoreDis {{#items}} {{#isDateType}} if (Array.isArray(value)) { + {{#temporal}} + if (value.every(item => item instanceof Temporal.PlainDate)) { + return value.map(value => value.toString()); + } + {{/temporal}} + {{^temporal}} if (value.every(item => item instanceof Date)) { return value.map(value => value.toISOString().substring(0,10)); } + {{/temporal}} } {{/isDateType}} {{#isDateTimeType}} if (Array.isArray(value)) { + {{#temporal}} + if (value.every(item => item instanceof Temporal.Instant)) { + return value.map(item => item.toString()); + } + {{/temporal}} + {{^temporal}} if (value.every(item => item instanceof Date)) { return value.map(item => item.toISOString()); } + {{/temporal}} } {{/isDateTimeType}} {{#isNumeric}} @@ -240,14 +282,28 @@ export function {{classname}}ToJSONTyped(value?: {{classname}} | null, ignoreDis {{#oneOfPrimitives}} {{^isArray}} {{#isDateType}} + {{#temporal}} + if (value instanceof Temporal.PlainDate) { + return ((value{{#isNullable}} as any{{/isNullable}}){{^required}}{{#isNullable}}?{{/isNullable}}{{/required}}.toString()); + } + {{/temporal}} + {{^temporal}} if (value instanceof Date) { return ((value{{#isNullable}} as any{{/isNullable}}){{^required}}{{#isNullable}}?{{/isNullable}}{{/required}}.toISOString().substring(0,10)); } + {{/temporal}} {{/isDateType}} {{#isDateTimeType}} + {{#temporal}} + if (value instanceof Temporal.Instant) { + return {{^required}}{{#isNullable}}value === null ? null : {{/isNullable}}{{^isNullable}}value == null ? undefined : {{/isNullable}}{{/required}}((value{{#isNullable}} as any{{/isNullable}}){{^required}}{{#isNullable}}?{{/isNullable}}{{/required}}.toString()); + } + {{/temporal}} + {{^temporal}} if (value instanceof Date) { return {{^required}}{{#isNullable}}value === null ? null : {{/isNullable}}{{^isNullable}}value == null ? undefined : {{/isNullable}}{{/required}}((value{{#isNullable}} as any{{/isNullable}}){{^required}}{{#isNullable}}?{{/isNullable}}{{/required}}.toISOString()); } + {{/temporal}} {{/isDateTimeType}} {{#isNumeric}} if (typeof value === 'number'{{#isEnum}} && ({{#allowableValues}}{{#values}}value === {{.}}{{^-last}} || {{/-last}}{{/values}}{{/allowableValues}}){{/isEnum}}) { diff --git a/modules/openapi-generator/src/main/resources/typescript-fetch/runtime.mustache b/modules/openapi-generator/src/main/resources/typescript-fetch/runtime.mustache index b1598aacca4a..4e37670b8684 100644 --- a/modules/openapi-generator/src/main/resources/typescript-fetch/runtime.mustache +++ b/modules/openapi-generator/src/main/resources/typescript-fetch/runtime.mustache @@ -350,9 +350,19 @@ function querystringSingleKey(key: string, value: string | number | null | undef const valueAsArray = Array.from(value); return querystringSingleKey(key, valueAsArray, keyPrefix); } +{{#temporal}} + if (value instanceof Temporal.Instant) { + return `${encodeURIComponent(fullKey)}=${encodeURIComponent(value.toString())}`; + } + if (value instanceof Temporal.PlainDate) { + return `${encodeURIComponent(fullKey)}=${encodeURIComponent(value.toString())}`; + } +{{/temporal}} +{{^temporal}} if (value instanceof Date) { return `${encodeURIComponent(fullKey)}=${encodeURIComponent(value.toISOString())}`; } +{{/temporal}} if (value instanceof Object) { return querystring(value as HTTPQuery, fullKey); } diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/options/TypeScriptFetchClientOptionsProvider.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/options/TypeScriptFetchClientOptionsProvider.java index a6bccce568cb..8ae39a88f029 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/options/TypeScriptFetchClientOptionsProvider.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/options/TypeScriptFetchClientOptionsProvider.java @@ -54,6 +54,7 @@ public Map createOptions() { .put(TypeScriptFetchClientCodegen.USE_SQUARE_BRACKETS_IN_ARRAY_NAMES, Boolean.FALSE.toString()) .put(TypeScriptFetchClientCodegen.VALIDATION_ATTRIBUTES, Boolean.FALSE.toString()) .put(TypeScriptFetchClientCodegen.WITH_REQUEST_OPTS_IN_INTERFACE, Boolean.TRUE.toString()) + .put(TypeScriptFetchClientCodegen.TEMPORAL, Boolean.FALSE.toString()) .build(); } } diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/typescript/fetch/TypeScriptFetchClientCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/typescript/fetch/TypeScriptFetchClientCodegenTest.java index 3aa6ce5656ba..8e94d3902810 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/typescript/fetch/TypeScriptFetchClientCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/typescript/fetch/TypeScriptFetchClientCodegenTest.java @@ -1074,6 +1074,41 @@ public void testRequiredDatesAreNullGuarded() throws Exception { "'optionalDateTime': value['optionalDateTime'] == null ? value['optionalDateTime'] : value['optionalDateTime'].toISOString(),"); } + @Test(description = "Verify required Temporal date and date-time properties are null-guarded on serialization and deserialization") + public void testRequiredTemporalInstancesAreNullGuarded() throws Exception { + Map properties = new HashMap<>(); + properties.put("temporal", Boolean.TRUE); + File output = generate( + properties, + "src/test/resources/3_0/typescript-fetch/required-date.yaml" + ); + + Path modelPath = Paths.get(output + "/models/Event.ts"); + TestUtils.assertFileExists(modelPath); + + TestUtils.assertFileContains(modelPath, + "'requiredDate': (json['requiredDate'] == null ? json['requiredDate'] : Temporal.PlainDate.from(json['requiredDate'])),"); + TestUtils.assertFileContains(modelPath, + "'requiredDateTime': (json['requiredDateTime'] == null ? json['requiredDateTime'] : Temporal.Instant.from(json['requiredDateTime'])),"); + TestUtils.assertFileContains(modelPath, + "'requiredNullableDate': (json['requiredNullableDate'] == null ? null : Temporal.PlainDate.from(json['requiredNullableDate'])),"); + TestUtils.assertFileContains(modelPath, + "'requiredNullableDateTime': (json['requiredNullableDateTime'] == null ? null : Temporal.Instant.from(json['requiredNullableDateTime'])),"); + TestUtils.assertFileContains(modelPath, + "'optionalDate': json['optionalDate'] == null ? undefined : (Temporal.PlainDate.from(json['optionalDate'])),"); + TestUtils.assertFileContains(modelPath, + "'optionalDateTime': json['optionalDateTime'] == null ? undefined : (Temporal.Instant.from(json['optionalDateTime'])),"); + + TestUtils.assertFileContains(modelPath, + "'requiredDate': value['requiredDate'] == null ? value['requiredDate'] : value['requiredDate'].toString(),"); + TestUtils.assertFileContains(modelPath, + "'requiredDateTime': value['requiredDateTime'] == null ? value['requiredDateTime'] : value['requiredDateTime'].toString(),"); + TestUtils.assertFileContains(modelPath, + "'requiredNullableDate': value['requiredNullableDate'] == null ? value['requiredNullableDate'] : value['requiredNullableDate'].toString(),"); + TestUtils.assertFileContains(modelPath, + "'optionalDateTime': value['optionalDateTime'] == null ? value['optionalDateTime'] : value['optionalDateTime'].toString(),"); + } + private static File generate( Map properties ) throws IOException {