Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add camelcase option to schema type generation #215

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 80 additions & 5 deletions plugins/typescript/src/core/schemaToTypeAliasDeclaration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
OpenAPIComponentType,
schemaToTypeAliasDeclaration,
} from "./schemaToTypeAliasDeclaration";
import { unset } from "lodash";

describe("schemaToTypeAliasDeclaration", () => {
it("should generate null", () => {
Expand Down Expand Up @@ -119,10 +120,10 @@ describe("schemaToTypeAliasDeclaration", () => {
it("should skip example which contains `*/` to avoid confusion", () => {
const schema: SchemaObject = {
title: "CronTimingCreate",
required: ["type", "cron_expression"],
required: ["type", "expression"],
type: "object",
properties: {
cron_expression: {
expression: {
title: "Cron Expression",
type: "string",
description: "The string representing the timing's cron expression.",
Expand All @@ -145,7 +146,7 @@ describe("schemaToTypeAliasDeclaration", () => {
* @format cron-string
* @example [see original specs]
*/
cron_expression: string;
expression: string;
};"
`);
});
Expand Down Expand Up @@ -272,6 +273,78 @@ describe("schemaToTypeAliasDeclaration", () => {
};"
`);
});

it("should generate an object with escaped keys", () => {

const schema: SchemaObject = {
type: "object",
properties: {
["foo.foo_bar"]: {
type: "string",
},
},
};

expect(printSchema(schema)).toMatchInlineSnapshot(`
"export type Test = {
[\\"foo.foo_bar\\"]?: string;
};"
`);
});


it("should generate an object with keys", () => {
const schema: SchemaObject = {
type: "object",
properties: {
["foo_bar"]: {
type: "string",
},
},
};

expect(printSchema(schema)).toMatchInlineSnapshot(`
"export type Test = {
foo_bar?: string;
};"
`);
});

it("should generate an object with escaped camelized keys", () => {

const schema: SchemaObject = {
type: "object",
properties: {
["foo.foo_bar"]: {
type: "string",
},
},
};

expect(printSchema(schema, undefined, undefined, undefined, true)).toMatchInlineSnapshot(`
"export type Test = {
[\\"foo.fooBar\\"]?: string;
};"
`);
});


it("should generate an object with camelized keys", () => {
const schema: SchemaObject = {
type: "object",
properties: {
["foo_bar"]: {
type: "string",
},
},
};

expect(printSchema(schema, undefined, undefined, undefined, true)).toMatchInlineSnapshot(`
"export type Test = {
fooBar?: string;
};"
`);
});

it("should generate a nested object", () => {
const schema: SchemaObject = {
Expand Down Expand Up @@ -974,7 +1047,8 @@ const printSchema = (
schema: SchemaObject,
currentComponent: OpenAPIComponentType = "schemas",
components?: OpenAPIObject["components"],
useEnums?: boolean
useEnums?: boolean,
useCamelCasedProps?: boolean
) => {
const nodes = schemaToTypeAliasDeclaration(
"Test",
Expand All @@ -983,7 +1057,8 @@ const printSchema = (
currentComponent,
openAPIDocument: { components },
},
useEnums
useEnums,
useCamelCasedProps
);

const sourceFile = ts.createSourceFile(
Expand Down
12 changes: 8 additions & 4 deletions plugins/typescript/src/core/schemaToTypeAliasDeclaration.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { pascal } from "case";
import { camel, pascal } from "case";
import { findKey, get, intersection, merge, omit } from "lodash";
import {
ComponentsObject,
Expand Down Expand Up @@ -38,6 +38,7 @@ export type Context = {
};

let useEnumsConfigBase: boolean | undefined;
let useCamelCasedPropsConfigBase: boolean | undefined;

/**
* Transform an OpenAPI Schema Object to Typescript Nodes (comment & declaration).
Expand All @@ -50,9 +51,11 @@ export const schemaToTypeAliasDeclaration = (
name: string,
schema: SchemaObject,
context: Context,
useEnums?: boolean
useEnums?: boolean,
useCamelCasedProps?: boolean
): ts.Node[] => {
useEnumsConfigBase = useEnums;
useCamelCasedPropsConfigBase = useCamelCasedProps;
const jsDocNode = getJSDocComment(schema, context);
const declarationNode = f.createTypeAliasDeclaration(
[f.createModifier(ts.SyntaxKind.ExportKeyword)],
Expand Down Expand Up @@ -228,12 +231,13 @@ export const getType = (
schema.properties || {}
).map(([key, property]) => {
const isEnum = typeof property === "object" && "enum" in property && useEnumsConfigBase;
const camelizeProps = useCamelCasedPropsConfigBase;

const propertyNode = f.createPropertySignature(
undefined,
isValidIdentifier(key)
? f.createIdentifier(key)
: f.createComputedPropertyName(f.createStringLiteral(key)),
? f.createIdentifier(camelizeProps ? camel(key): key)
: f.createComputedPropertyName(f.createStringLiteral(camelizeProps ? key.split('.').map(camel).join('.') : key)),
schema.required?.includes(key)
? undefined
: f.createToken(ts.SyntaxKind.QuestionToken),
Expand Down
29 changes: 18 additions & 11 deletions plugins/typescript/src/generators/generateSchemaTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,15 @@ export const generateSchemaTypes = async (
componentSchema.reduce<ts.Node[]>(
(mem, [name, schema]) => [
...mem,
...schemaToTypeAliasDeclaration(
...schemaToTypeAliasDeclaration( // @note schemaToTypeAliasDeclaration called here
name,
schema,
{
openAPIDocument: context.openAPIDocument,
currentComponent: "schemas",
},
config.useEnums
config.useEnums,
config.useCamelCasedProps
),
],
[]
Expand Down Expand Up @@ -91,23 +92,23 @@ export const generateSchemaTypes = async (
const enumSchemas = enumSchemaEntries.reduce<ts.Node[]>(
(mem, [name, schema]) => [
...mem,
...schemaToEnumDeclaration(name, schema, {
...schemaToEnumDeclaration(name, schema, { // @note schemaToEnumDeclaration called here
openAPIDocument: context.openAPIDocument,
currentComponent: "schemas",
}),
],
[]
);

const componentsSchemas = handleTypeAlias(
const componentsSchemas = handleTypeAlias( // @note schemaToTypeAliasDeclaration indirectly called here
componentSchemaEntries.filter(
([name]) => !enumSchemaEntries.some(([enumName]) => name === enumName)
)
);

schemas.push(...enumSchemas, ...componentsSchemas);
} else {
const componentsSchemas = handleTypeAlias(componentSchemaEntries);
const componentsSchemas = handleTypeAlias(componentSchemaEntries); // @note schemaToTypeAliasDeclaration called here
schemas.push(...componentsSchemas);
}

Expand All @@ -131,10 +132,12 @@ export const generateSchemaTypes = async (

return [
...mem,
...schemaToTypeAliasDeclaration(name, mediaType?.schema || {}, {
...schemaToTypeAliasDeclaration(name, mediaType?.schema || {}, { // @note schemaToTypeAliasDeclaration called here
openAPIDocument: context.openAPIDocument,
currentComponent: "responses",
}),
},
undefined,
config.useCamelCasedProps),
];
}, []);

Expand All @@ -161,10 +164,12 @@ export const generateSchemaTypes = async (

return [
...mem,
...schemaToTypeAliasDeclaration(name, mediaType.schema, {
...schemaToTypeAliasDeclaration(name, mediaType.schema, { // @note schemaToTypeAliasDeclaration called here
openAPIDocument: context.openAPIDocument,
currentComponent: "requestBodies",
}),
},
undefined,
config.useCamelCasedProps),
];
}, []);

Expand All @@ -190,10 +195,12 @@ export const generateSchemaTypes = async (
}
return [
...mem,
...schemaToTypeAliasDeclaration(name, parameterObject.schema, {
...schemaToTypeAliasDeclaration(name, parameterObject.schema, { // @note schemaToTypeAliasDeclaration called here
openAPIDocument: context.openAPIDocument,
currentComponent: "parameters",
}),
},
undefined,
config.useCamelCasedProps),
];
}, []);

Expand Down
6 changes: 6 additions & 0 deletions plugins/typescript/src/generators/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,10 @@ export type ConfigBase = {
* @default false
*/
useEnums?: boolean;
/**
* Uses camelized property names instead of snake case.
*
* @default false
*/
useCamelCasedProps?: boolean;
};