Skip to content

Commit

Permalink
chore: add coerce-enums-to-literals-option (#4807)
Browse files Browse the repository at this point in the history
  • Loading branch information
dsinghvi authored Oct 5, 2024
1 parent 1c15dde commit 75da6e9
Show file tree
Hide file tree
Showing 14 changed files with 76 additions and 21 deletions.
19 changes: 19 additions & 0 deletions packages/cli/cli/versions.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
- changelogEntry:
- summary: |
The OpenAPI importer used to try and coerce all enums into a literals.
In some cases this is not desirable, so we now expose an option called
`coerce-enums-to-literals` in your generators.yml.
```yml generators.yml
api:
specs:
- openapi: ../openapi.json
overrides: ../openapi-overrides.yml
settings:
title-as-schema-name: false
coerce-enums-to-literals: false
```
type: feat
irVersion: 53
version: 0.44.1

- changelogEntry:
- summary: |
The Fern CLI now supports parsing [Conjure](https://github.com/palantir/conjure), Palantir's
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export interface APIDefinitionSettings {
shouldUseUndiscriminatedUnionsWithLiterals: boolean | undefined;
asyncApiMessageNaming: "v1" | "v2" | undefined;
shouldUseOptionalAdditionalProperties: boolean | undefined;
coerceEnumsToLiterals: boolean | undefined;
}

export interface APIDefinitionLocation {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@ async function parseAPIConfigurationToApiLocations(
shouldUseTitleAsName: undefined,
shouldUseUndiscriminatedUnionsWithLiterals: undefined,
asyncApiMessageNaming: undefined,
shouldUseOptionalAdditionalProperties: undefined
shouldUseOptionalAdditionalProperties: undefined,
coerceEnumsToLiterals: undefined,
}
});
} else if (isRawProtobufAPIDefinitionSchema(apiConfiguration)) {
Expand All @@ -113,7 +114,8 @@ async function parseAPIConfigurationToApiLocations(
shouldUseTitleAsName: undefined,
shouldUseUndiscriminatedUnionsWithLiterals: undefined,
asyncApiMessageNaming: undefined,
shouldUseOptionalAdditionalProperties: undefined
shouldUseOptionalAdditionalProperties: undefined,
coerceEnumsToLiterals: undefined,
}
});
} else if (Array.isArray(apiConfiguration)) {
Expand All @@ -131,7 +133,8 @@ async function parseAPIConfigurationToApiLocations(
shouldUseTitleAsName: undefined,
shouldUseUndiscriminatedUnionsWithLiterals: undefined,
asyncApiMessageNaming: undefined,
shouldUseOptionalAdditionalProperties: undefined
shouldUseOptionalAdditionalProperties: undefined,
coerceEnumsToLiterals: undefined,
}
});
} else if (isRawProtobufAPIDefinitionSchema(definition)) {
Expand All @@ -149,7 +152,8 @@ async function parseAPIConfigurationToApiLocations(
shouldUseTitleAsName: undefined,
shouldUseUndiscriminatedUnionsWithLiterals: undefined,
asyncApiMessageNaming: undefined,
shouldUseOptionalAdditionalProperties: undefined
shouldUseOptionalAdditionalProperties: undefined,
coerceEnumsToLiterals: undefined,
}
});
} else {
Expand All @@ -165,7 +169,8 @@ async function parseAPIConfigurationToApiLocations(
shouldUseTitleAsName: definition.settings?.["use-title"],
shouldUseUndiscriminatedUnionsWithLiterals: definition.settings?.unions === "v1",
asyncApiMessageNaming: definition.settings?.["message-naming"],
shouldUseOptionalAdditionalProperties: undefined
shouldUseOptionalAdditionalProperties: undefined,
coerceEnumsToLiterals: undefined,
}
});
}
Expand All @@ -183,7 +188,8 @@ async function parseAPIConfigurationToApiLocations(
shouldUseTitleAsName: apiConfiguration.settings?.["use-title"],
shouldUseUndiscriminatedUnionsWithLiterals: apiConfiguration.settings?.unions === "v1",
asyncApiMessageNaming: apiConfiguration.settings?.["message-naming"],
shouldUseOptionalAdditionalProperties: undefined
shouldUseOptionalAdditionalProperties: undefined,
coerceEnumsToLiterals: undefined,
}
});
}
Expand All @@ -206,7 +212,8 @@ async function parseAPIConfigurationToApiLocations(
shouldUseTitleAsName: settings?.["use-title"],
shouldUseUndiscriminatedUnionsWithLiterals: settings?.unions === "v1",
asyncApiMessageNaming: undefined,
shouldUseOptionalAdditionalProperties: undefined
shouldUseOptionalAdditionalProperties: undefined,
coerceEnumsToLiterals: undefined,
}
});
} else if (openapi != null) {
Expand All @@ -222,7 +229,8 @@ async function parseAPIConfigurationToApiLocations(
shouldUseTitleAsName: openapi.settings?.["use-title"],
shouldUseUndiscriminatedUnionsWithLiterals: openapi.settings?.unions === "v1",
asyncApiMessageNaming: undefined,
shouldUseOptionalAdditionalProperties: undefined
shouldUseOptionalAdditionalProperties: undefined,
coerceEnumsToLiterals: undefined,
}
});
}
Expand All @@ -240,7 +248,8 @@ async function parseAPIConfigurationToApiLocations(
shouldUseTitleAsName: settings?.["use-title"],
shouldUseUndiscriminatedUnionsWithLiterals: settings?.unions === "v1",
asyncApiMessageNaming: settings?.["message-naming"],
shouldUseOptionalAdditionalProperties: undefined
shouldUseOptionalAdditionalProperties: undefined,
coerceEnumsToLiterals: undefined,
}
});
}
Expand Down Expand Up @@ -280,7 +289,8 @@ async function parseApiConfigurationV2Schema({
shouldUseTitleAsName: spec.settings?.["title-as-schema-name"],
shouldUseUndiscriminatedUnionsWithLiterals: undefined,
asyncApiMessageNaming: undefined,
shouldUseOptionalAdditionalProperties: spec.settings?.["optional-additional-properties"] ?? true
shouldUseOptionalAdditionalProperties: spec.settings?.["optional-additional-properties"] ?? true,
coerceEnumsToLiterals: spec.settings?.["coerce-enums-to-literals"],
}
};
if (spec.namespace == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import { RawSchemas } from "@fern-api/fern-definition-schema";

export const OpenAPISettingsSchema = z.strictObject({
"title-as-schema-name": z.optional(z.boolean()),
"optional-additional-properties": z.optional(z.boolean())
"optional-additional-properties": z.optional(z.boolean()),
"coerce-enums-to-literals": z.optional(z.boolean())
});

export type OpenAPISettingsSchema = z.infer<typeof OpenAPISettingsSchema>;
Expand All @@ -23,7 +24,8 @@ export type OpenAPISpecSchema = z.infer<typeof OpenAPISpecSchema>;

export const AsyncAPISettingsSchema = z.strictObject({
"title-as-schema-name": z.optional(z.boolean()),
"optional-additional-properties": z.optional(z.boolean())
"optional-additional-properties": z.optional(z.boolean()),
"coerce-enums-to-literals": z.optional(z.boolean())
});

export type AsyncAPISettingsSchema = z.infer<typeof AsyncAPISettingsSchema>;
Expand Down
8 changes: 8 additions & 0 deletions packages/cli/lazy-fern-workspace/src/OSSWorkspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ export interface SpecImportSettings {
shouldUseUndiscriminatedUnionsWithLiterals: boolean;
optionalAdditionalProperties: boolean;
asyncApiNaming?: "v1" | "v2";
cooerceEnumsToLiterals: boolean;
}

export declare namespace OSSWorkspace {
Expand Down Expand Up @@ -93,6 +94,10 @@ export declare namespace OSSWorkspace {
* optional.
*/
optionalAdditionalProperties?: boolean;
/*
* Whether or not to cooerce enums to undiscriminated union literals.
*/
cooerceEnumsToLiterals?: boolean;
}
}

Expand Down Expand Up @@ -253,5 +258,8 @@ function getOptionsOverridesFromSettings(settings?: OSSWorkspace.Settings): Part
if (settings.optionalAdditionalProperties) {
result.optionalAdditionalProperties = true;
}
if (settings.cooerceEnumsToLiterals) {
result.cooerceEnumsToLiterals = true;
}
return result;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ describe("anyOf", () => {
audiences: [],
shouldUseTitleAsName: true,
shouldUseUndiscriminatedUnionsWithLiterals: true,
optionalAdditionalProperties: false
optionalAdditionalProperties: false,
cooerceEnumsToLiterals: true
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ describe("open api parser", () => {
audiences: [],
shouldUseTitleAsName: true,
shouldUseUndiscriminatedUnionsWithLiterals: true,
optionalAdditionalProperties: true
optionalAdditionalProperties: true,
cooerceEnumsToLiterals: true
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ describe("open api parser", () => {
audiences: [],
shouldUseTitleAsName: true,
shouldUseUndiscriminatedUnionsWithLiterals: false,
optionalAdditionalProperties: true
optionalAdditionalProperties: true,
cooerceEnumsToLiterals: true
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ describe("open api parser", () => {
audiences: [],
shouldUseTitleAsName: false,
shouldUseUndiscriminatedUnionsWithLiterals: false,
optionalAdditionalProperties: true
optionalAdditionalProperties: true,
cooerceEnumsToLiterals: true
});
});
5 changes: 4 additions & 1 deletion packages/cli/openapi-parser/src/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,15 @@ export interface ParseOpenAPIOptions {
audiences: string[] | undefined;
/* Whether or not to make additional property values optional */
optionalAdditionalProperties: boolean;
/* Whether or not to cooerce enums as literals */
cooerceEnumsToLiterals: boolean;
}

export const DEFAULT_PARSE_OPENAPI_SETTINGS: ParseOpenAPIOptions = {
disableExamples: false,
discriminatedUnionV2: false,
useTitlesAsName: true,
audiences: undefined,
optionalAdditionalProperties: true
optionalAdditionalProperties: true,
cooerceEnumsToLiterals: true
};
7 changes: 6 additions & 1 deletion packages/cli/openapi-parser/src/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export interface SpecImportSettings {
shouldUseUndiscriminatedUnionsWithLiterals: boolean;
asyncApiNaming?: "v1" | "v2";
optionalAdditionalProperties: boolean;
cooerceEnumsToLiterals: boolean;
}

export type Source = AsyncAPISource | OpenAPISource | ProtobufSource;
Expand Down Expand Up @@ -190,7 +191,11 @@ function getParseOptions({
optionalAdditionalProperties:
overrides?.optionalAdditionalProperties ??
specSettings?.optionalAdditionalProperties ??
DEFAULT_PARSE_OPENAPI_SETTINGS.optionalAdditionalProperties
DEFAULT_PARSE_OPENAPI_SETTINGS.optionalAdditionalProperties,
cooerceEnumsToLiterals:
overrides?.cooerceEnumsToLiterals ??
specSettings?.cooerceEnumsToLiterals ??
DEFAULT_PARSE_OPENAPI_SETTINGS.cooerceEnumsToLiterals
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export function convertUndiscriminatedOneOf({
const derivedSubtypePrefixes = getUniqueSubTypeNames({ schemas: subtypes });

const convertedSubtypes = subtypes.flatMap((schema, index) => {
if (!isReferenceObject(schema) && schema.enum != null) {
if (!isReferenceObject(schema) && schema.enum != null && context.options.cooerceEnumsToLiterals) {
return schema.enum.map((enumValue) => {
return SchemaWithExample.literal({
nameOverride: undefined,
Expand Down
6 changes: 4 additions & 2 deletions packages/cli/workspace-loader/src/loadAPIWorkspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ export async function loadSingleNamespaceAPIWorkspace({
shouldUseTitleAsName: definition.settings?.shouldUseTitleAsName ?? true,
shouldUseUndiscriminatedUnionsWithLiterals:
definition.settings?.shouldUseUndiscriminatedUnionsWithLiterals ?? false,
optionalAdditionalProperties: definition.settings?.shouldUseOptionalAdditionalProperties ?? true
optionalAdditionalProperties: definition.settings?.shouldUseOptionalAdditionalProperties ?? true,
cooerceEnumsToLiterals: definition.settings?.coerceEnumsToLiterals ?? true,
}
});
continue;
Expand Down Expand Up @@ -109,7 +110,8 @@ export async function loadSingleNamespaceAPIWorkspace({
shouldUseUndiscriminatedUnionsWithLiterals:
definition.settings?.shouldUseUndiscriminatedUnionsWithLiterals ?? false,
asyncApiNaming: definition.settings?.asyncApiMessageNaming,
optionalAdditionalProperties: definition.settings?.shouldUseOptionalAdditionalProperties ?? true
optionalAdditionalProperties: definition.settings?.shouldUseOptionalAdditionalProperties ?? true,
cooerceEnumsToLiterals: definition.settings?.coerceEnumsToLiterals ?? true,
},
source: {
type: "openapi",
Expand Down
1 change: 1 addition & 0 deletions packages/cli/workspace-loader/src/types/Workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export interface SpecImportSettings {
shouldUseUndiscriminatedUnionsWithLiterals: boolean;
optionalAdditionalProperties: boolean;
asyncApiNaming?: "v1" | "v2";
cooerceEnumsToLiterals: boolean;
}

export interface OpenAPIFile {
Expand Down

0 comments on commit 75da6e9

Please sign in to comment.