Skip to content

Commit

Permalink
feat(sdk-generator): turn x-local-timezone mandatory for utils.Date
Browse files Browse the repository at this point in the history
Use `x-local-timezone` as an opt-in mechanism to use utils.Date and
utils.DateTime (#1808).

Set sdk `isStringified` option for dates as true by default
  • Loading branch information
cpaulve-1A committed Jul 1, 2024
1 parent 1c1a104 commit d01ec1e
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 73 deletions.
38 changes: 38 additions & 0 deletions migration-guides/11.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,41 @@
## @o3r/schematics

- `NodePackageNgAddTask` has been removed. `setupDependencies` should be used instead

- The [`stringifyDate` cli option](https://www.npmjs.com/package/@ama-sdk/schematics#dates) is now enabled by default. If
you want to use the `Date` format, you will need to set it to `false` via the command line:

```shell
# with yarn package manager
yarn run schematics @ama-sdk/schematics:typescript-core --global-property stringifyDate=false
# with npm package manager
npm run schematics @ama-sdk/schematics:typescript-core --global-property stringifyDate=false
```

or by disabling it for your generator in your `openapitools.json` file:
```json5
{
"$schema": "https://raw.githubusercontent.com/OpenAPITools/openapi-generator-cli/master/apps/generator-cli/src/config.schema.json",
"generator-cli": {
"version": "7.4.0", // Version of the Codegen downloaded by the cli - updated via the
"storageDir": ".openapi-generator",
"generators": {
"my-generator": {
"generatorName": "typescriptFetch",
"output": ".",
"inputSpec": "spec-path.(yaml|json)",
"globalProperty": {
"stringifyDate": false
}
}
}
}
}
```

- Prior version 11, the default type for dates was the `utils.Date` and `utils.DateTime` which take the date
from the API response and remove the timezone to use the local one from the user's machine.
If a date needed to be expressed in its original timezone, the date specification needed an extra `x-date-timezone` vendor.
From version 11, the default behaviour is now to keep the timezone of the API response and to use `string` or `Date`
depending on the `stringifyDate` value. The removal the timezone is now an 'opt-in' mechanism and dates with a timezone
that should be ignored needs to add the `x-local-timezone` vendor.
10 changes: 8 additions & 2 deletions packages/@ama-sdk/create/src/index.it.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,12 @@ describe('Create new sdk command', () => {
expect(() =>
packageManagerCreate({
script: '@ama-sdk',
args: ['typescript', sdkPackageName, '--package-manager', packageManager, '--spec-path', path.join(sdkFolderPath, 'swagger-spec-with-date.yml')]
args: [
'typescript',
sdkPackageName,
'--package-manager', packageManager,
'--spec-path', path.join(sdkFolderPath, 'swagger-spec-with-date.yml'),
'--global-property', 'stringifyDate=false']
}, execAppOptions)
).not.toThrow();
expect(() => packageManagerRun({script: 'build'}, { ...execAppOptions, cwd: sdkPackagePath })).not.toThrow();
Expand All @@ -88,7 +93,8 @@ describe('Create new sdk command', () => {
'--spec-package-name', '@ama-sdk/showcase-sdk',
'--spec-package-path', 'openapi.yml',
'--spec-package-version', o3rEnvironment.testEnvironment.o3rVersion,
'--spec-package-registry', o3rEnvironment.testEnvironment.packageManagerConfig.registry
'--spec-package-registry', o3rEnvironment.testEnvironment.packageManagerConfig.registry,
'--global-property', 'stringifyDate=false'
]
}, execAppOptions)
).not.toThrow();
Expand Down
13 changes: 6 additions & 7 deletions packages/@ama-sdk/schematics/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,16 +127,15 @@ Please note that revivers are generated for SDKs that use:

If your specification file includes dates, there are multiple options for the generation of your SDK involving the global property option `stringifyDate`:

- By default, the option `stringifyDate` is false so dates will be generated as either `utils.Date`, `utils.DateTime`, or `Date`.
- By default, the option `stringifyDate` is set to `true`. Set it to `false` if you want dates will be generated as `Date`.
For more information related to these types, check out this [documentation](https://github.com/AmadeusITGroup/otter/tree/main/packages/%40ama-sdk/schematics/schematics/typescript/shell/templates/base#manage-dates).
- To leave the handling of the timezone to the application and generate the dates as `string` types, the option `stringifyDate` can be set to true. <br>
This can be done by adding `--global-property stringifyDate` to the generator command.
- If an existing SDK contains stringified dates that need to be reverted to their expected formats, you can regenerate the SDK by removing the `stringifyDate` option from the global properties (since it is false by default).
This can be done by adding `--global-property stringifyDate=false` to the generator command or by adding the global property
to the `openapitools.json`

Example to stringify dates:
Example to use `Date`:

```shell
yarn schematics @ama-sdk/schematics:typescript-core --spec-path ./swagger-spec.yaml --global-property stringifyDate
yarn schematics @ama-sdk/schematics:typescript-core --spec-path ./swagger-spec.yaml --global-property stringifyDate=false
```

##### Extensible models
Expand Down Expand Up @@ -214,7 +213,7 @@ described global properties `stringifyDate` and `allowModelExtension`:
"output": ".",
"inputSpec": "./openapi-spec.yaml", // or "./openapi-spec.json" according to the specification format
"globalProperty": {
"stringifyDate": true,
"stringifyDate": false,
"allowModelExtension": true
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ public AbstractTypeScriptClientCodegen() {
String allowModelExtensionString = GlobalSettings.getProperty("allowModelExtension");
allowModelExtension = allowModelExtensionString != null ? !"false".equalsIgnoreCase(allowModelExtensionString) : false;
String stringifyDateString = GlobalSettings.getProperty("stringifyDate");
stringifyDate = stringifyDateString != null ? !"false".equalsIgnoreCase(stringifyDateString) : false;
stringifyDate = stringifyDateString != null ? !"false".equalsIgnoreCase(stringifyDateString) : true;
typeMapping.put("DateTime", stringifyDate ? "string" : "utils.DateTime");
typeMapping.put("Date", stringifyDate ? "string" : "utils.Date");
//TODO binary should be mapped to byte array
Expand Down Expand Up @@ -444,12 +444,6 @@ public void postProcessModelProperty(CodegenModel model, CodegenProperty propert
}
}

if (property != null && !stringifyDate) {
if (Boolean.TRUE.equals(property.isDate) || Boolean.TRUE.equals(property.isDateTime)) {
property.isPrimitiveType = false;
}
}

if (property.isEnum) {
List<String> allowableValues = (List) property.allowableValues.get("values");
List<String> sanitizedAllowableValues = allowableValues;
Expand Down Expand Up @@ -512,11 +506,20 @@ public void postProcessModelProperty(CodegenModel model, CodegenProperty propert
+ "list container.");
}

// If the x-date-timezone is present in the specification, replace utils.Date with Date
if (("utils.Date".equals(property.dataType) || "utils.DateTime".equals(property.dataType)) && property.vendorExtensions.containsKey("x-date-timezone")) {
property.dataType = "Date";
property.datatypeWithEnum = "Date";
property.baseType = "Date";
if (property.vendorExtensions.containsKey("x-date-timezone")) {
throw new IllegalArgumentException("'x-date-timezone' is deprecated and conflicts with the 'x-local-timezone' vendor." +
" Please check out the documentation and migrate to the 'x-local-timezone' model.");
}
// If the x-local-timezone is present in the specification, use utils.Date
if (property.vendorExtensions.containsKey("x-local-timezone")) {
String dataType = "date-time".equals(property.getFormat()) ? "utils.DateTime" : "utils.Date";
property.isPrimitiveType = false;
property.dataType = dataType;
property.datatypeWithEnum = dataType;
property.baseType = dataType;
}
if (property != null && property.dataType != null && property.dataType.matches("^(Date|utils.Date|utils.DateTime)$")) {
property.isPrimitiveType = false;
}
property.vendorExtensions.put("x-exposed-classname", model.classname);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,12 +124,11 @@ For example, you want to be able to display that the flight is in X hours.
You will need to compute this information with the two timezones -- the airport's and the user's.

### Solution proposed to remove the timezone: utils.DateTime
We have introduced the utils.Date object to replace the Date implementation and ignore the timezone.
As we need to get rid of the timezones more often than not, this will be our default behavior.
By default, the Date models are replaced with utils.Date.
The Otter framework has introduced the `utils.Date` object to replace the `Date` implementation and ignore the timezone.
This can be enabled at property level thanks to the `x-local-timezone` vendor.

When we need to keep the timezone information, we create a new field directly in the SDK.
As this field does not exist in the specification, it will not be part of the base model but of the core model instead.
If you need to keep the timezone information, extend the model and create a new field directly in the SDK.
As this field does not exist in the specification, it will not be part of the base model but of the core model instead (the first one being completely generated from the API specifications).

Simple example:
```yaml
Expand All @@ -140,6 +139,8 @@ Simple example:
properties:
departureDateTime:
type: string
x-local-timezone:
description: If this vendor extension is present send dates without their timezone
format: date-time
```
Base model generated
Expand Down Expand Up @@ -197,23 +198,3 @@ export * from './flight/index';

You can now use departureDateTimeConsideringTimezone to access the timezone information.
See [utils.Date](https://github.com/AmadeusITGroup/otter/blob/main/packages/%40ama-sdk/core/src/fwk/date.ts) for more information.

### How to keep the timezone (prevent Date replacement with utils.Date)

In order to add the timezone to your timestamp property you can add the x-date-timezone extension in your yaml, for example:

```yaml
properties:
timestamp:
title: timestamp
description: >-
Timestamp when event is triggered. UTC time (server time), with a
format similar to yyyy-MM-ddThh:mm:ss.sTZD. Refer to the pattern
type: string
format: date-time
x-date-timezone:
description: If this vendor extension is present send dates with the timezone
pattern: >-
^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{1,3}([Z]|([+][0-9]{2}:?[0-9]{2}$))
example: '2013-12-31T19:20:30.45+01:00'
```
33 changes: 6 additions & 27 deletions packages/@ama-sdk/showcase-sdk/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,12 +130,11 @@ You will need to compute this information with the two timezones -- the airport'

### Solution proposed to remove the timezone: utils.DateTime

We have introduced the utils.Date object to replace the Date implementation and ignore the timezone.
As we need to get rid of the timezones more often than not, this will be our default behavior.
By default, the Date models are replaced with utils.Date.
The Otter framework has introduced the `utils.Date` object to replace the `Date` implementation and ignore the timezone.
This can be enabled at property level thanks to the `x-local-timezone` vendor.

When we need to keep the timezone information, we create a new field directly in the SDK.
As this field does not exist in the specification, it will not be part of the base model but of the core model instead.
If you need to keep the timezone information, extend the model and create a new field directly in the SDK.
As this field does not exist in the specification, it will not be part of the base model but of the core model instead (the first one being completely generated from the API specifications).

Simple example:

Expand All @@ -147,11 +146,11 @@ Simple example:
properties:
departureDateTime:
type: string
x-local-timezone: true
description: If this vendor extension is present send dates without their timezone
format: date-time
```
Base model generated
```typescript
// flight.ts generated in base models
export interface Flight {
Expand Down Expand Up @@ -211,23 +210,3 @@ export * from './flight/index';

You can now use departureDateTimeConsideringTimezone to access the timezone information.
See [utils.Date](https://github.com/AmadeusITGroup/otter/blob/main/packages/%40ama-sdk/core/src/fwk/date.ts) for more information.

### How to keep the timezone (prevent Date replacement with utils.Date)

In order to add the timezone to your timestamp property you can add the x-date-timezone extension in your yaml, for example:

```yaml
properties:
timestamp:
title: timestamp
description: >-
Timestamp when event is triggered. UTC time (server time), with a
format similar to yyyy-MM-ddThh:mm:ss.sTZD. Refer to the pattern
type: string
format: date-time
x-date-timezone:
description: If this vendor extension is present send dates with the timezone
pattern: >-
^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{1,3}([Z]|([+][0-9]{2}:?[0-9]{2}$))
example: '2013-12-31T19:20:30.45+01:00'
```

0 comments on commit d01ec1e

Please sign in to comment.