Skip to content

Commit

Permalink
[OpenAPI3 Emitter] Add option to map safeint to double-int (micro…
Browse files Browse the repository at this point in the history
…soft#2933)

fix  microsoft#2367 
Format was added to the schema registry so we are safe to use that now
https://spec.openapis.org/registry/format/double-int.html

---------

Co-authored-by: Brian Terlson <brian.terlson@microsoft.com>
  • Loading branch information
2 people authored and markcowl committed Mar 8, 2024
1 parent 87e2559 commit 30bd421
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 2 deletions.
8 changes: 8 additions & 0 deletions .chronus/changes/safe-int-openapi3-2024-1-17-0-53-2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
changeKind: feature
packages:
- "@typespec/openapi3"
---

Add a new option `safeint-strategy` that can be set to `double-int` to emit `type: integer, format: double-int` instead of `type: integer, format: int64` when using the `safeint` scalar.
11 changes: 11 additions & 0 deletions docs/libraries/openapi3/reference/emitter.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,14 @@ By default all types declared under the service namespace will be included. With

If the generated openapi types should have the `x-typespec-name` extension set with the name of the TypeSpec type that created it.
This extension is meant for debugging and should not be depended on.

### `safeint-strategy`

**Type:** `"double-int" | "int64"`

How to handle safeint type. Options are:

- `double-int`: Will produce `type: integer, format: double-int`
- `int64`: Will produce `type: integer, format: int64`

Default: `int64`
11 changes: 11 additions & 0 deletions packages/openapi3/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,17 @@ By default all types declared under the service namespace will be included. With
If the generated openapi types should have the `x-typespec-name` extension set with the name of the TypeSpec type that created it.
This extension is meant for debugging and should not be depended on.

#### `safeint-strategy`

**Type:** `"double-int" | "int64"`

How to handle safeint type. Options are:

- `double-int`: Will produce `type: integer, format: double-int`
- `int64`: Will produce `type: integer, format: int64`

Default: `int64`

## Decorators

### TypeSpec.OpenAPI
Expand Down
21 changes: 21 additions & 0 deletions packages/openapi3/src/lib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,14 @@ export interface OpenAPI3EmitterOptions {
* @default "never"
*/
"include-x-typespec-name"?: "inline-only" | "never";

/**
* How to handle safeint type. Options are:
* - `double-int`: Will produce `type: integer, format: double-int`
* - `int64`: Will produce `type: integer, format: int64`
* @default "int64"
*/
"safeint-strategy"?: "double-int" | "int64";
}

const EmitterOptionsSchema: JSONSchemaType<OpenAPI3EmitterOptions> = {
Expand Down Expand Up @@ -117,6 +125,19 @@ const EmitterOptionsSchema: JSONSchemaType<OpenAPI3EmitterOptions> = {
description:
"If the generated openapi types should have the `x-typespec-name` extension set with the name of the TypeSpec type that created it.\nThis extension is meant for debugging and should not be depended on.",
},
"safeint-strategy": {
type: "string",
enum: ["double-int", "int64"],
nullable: true,
default: "int64",
description: [
"How to handle safeint type. Options are:",
" - `double-int`: Will produce `type: integer, format: double-int`",
" - `int64`: Will produce `type: integer, format: int64`",
"",
"Default: `int64`",
].join("\n"),
},
},
required: [],
};
Expand Down
3 changes: 3 additions & 0 deletions packages/openapi3/src/openapi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ const defaultOptions = {
"new-line": "lf",
"omit-unreachable-types": false,
"include-x-typespec-name": "never",
"safeint-strategy": "int64",
} as const;

export async function $onEmit(context: EmitContext<OpenAPI3EmitterOptions>) {
Expand Down Expand Up @@ -186,6 +187,7 @@ export function resolveOptions(
newLine: resolvedOptions["new-line"],
omitUnreachableTypes: resolvedOptions["omit-unreachable-types"],
includeXTypeSpecName: resolvedOptions["include-x-typespec-name"],
safeintStrategy: resolvedOptions["safeint-strategy"],
outputFile: resolvePath(context.emitterOutputDir, outputFile),
};
}
Expand All @@ -196,6 +198,7 @@ export interface ResolvedOpenAPI3EmitterOptions {
newLine: NewLine;
omitUnreachableTypes: boolean;
includeXTypeSpecName: "inline-only" | "never";
safeintStrategy: "double-int" | "int64";
}

function createOAPIEmitter(
Expand Down
8 changes: 7 additions & 1 deletion packages/openapi3/src/schema-emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -699,7 +699,13 @@ export class OpenAPI3SchemaEmitter extends TypeEmitter<
case "int64":
return { type: "integer", format: "int64" };
case "safeint":
return { type: "integer", format: "int64" };
switch (this.#options.safeintStrategy) {
case "double-int":
return { type: "integer", format: "double-int" };
case "int64":
default:
return { type: "integer", format: "int64" };
}
case "uint8":
return { type: "integer", format: "uint8" };
case "uint16":
Expand Down
30 changes: 29 additions & 1 deletion packages/openapi3/test/primitive-types.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { deepStrictEqual, ok, strictEqual } from "assert";
import { describe, it } from "vitest";
import { OpenAPI3Schema } from "../src/types.js";
import { oapiForModel } from "./test-host.js";
import { oapiForModel, openApiFor } from "./test-host.js";

describe("openapi3: primitives", () => {
describe("handle TypeSpec intrinsic types", () => {
Expand Down Expand Up @@ -48,6 +48,34 @@ describe("openapi3: primitives", () => {
}
});

describe("safeint-strategy", () => {
it("produce type: integer, format: double-int for safeint when safeint-strategy is double-int", async () => {
const res = await openApiFor(
`
model Pet { name: safeint };
`,
undefined,
{ "safeint-strategy": "double-int" }
);

const schema = res.components.schemas.Pet.properties.name;
deepStrictEqual(schema, { type: "integer", format: "double-int" });
});

it("produce type: integer, format: int64 for safeint when safeint-strategy is int64", async () => {
const res = await openApiFor(
`
model Pet { name: safeint };
`,
undefined,
{ "safeint-strategy": "int64" }
);

const schema = res.components.schemas.Pet.properties.name;
deepStrictEqual(schema, { type: "integer", format: "int64" });
});
});

it("defines models extended from primitives", async () => {
const res = await oapiForModel(
"Pet",
Expand Down

0 comments on commit 30bd421

Please sign in to comment.