Skip to content

Commit

Permalink
Merge pull request #433 from hey-api/feat/schemas-exports
Browse files Browse the repository at this point in the history
feat: add form type option for schemas
  • Loading branch information
mrlubos authored Apr 19, 2024
2 parents 33adebc + e36502c commit a15612d
Show file tree
Hide file tree
Showing 20 changed files with 1,684 additions and 23 deletions.
5 changes: 5 additions & 0 deletions .changeset/quiet-seals-pay.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@hey-api/openapi-ts": minor
---

feat: add form type option for schemas
14 changes: 13 additions & 1 deletion docs/openapi-ts/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,19 @@ if (userInput.length > maxInputLength) {
}
```

If you're using OpenAPI v3.1, your schemas are JSON Schema compliant and can be used with any other tools supporting JSON Schema. However, if you don't need schemas at all, you can disable them with
If you're using OpenAPI v3.1, your schemas are JSON Schema compliant and can be used with other tools supporting JSON Schema. However, if you only want to validate form input, you don't want to include string descriptions inside your bundle. Instead, use `form` type.

```js{5}
export default {
input: 'path/to/openapi.json',
output: 'src/client',
schemas: {
type: 'form'
},
}
```

If you don't need schemas at all, you can disable them with

```js{4}
export default {
Expand Down
18 changes: 17 additions & 1 deletion packages/openapi-ts/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,22 @@ const logMissingDependenciesWarning = (dependencies: Dependencies) => {
}
};

const getSchemas = (userConfig: UserConfig): Config['schemas'] => {
let schemas: Config['schemas'] = {
export: true,
type: 'json',
};
if (typeof userConfig.schemas === 'boolean') {
schemas.export = userConfig.schemas;
} else {
schemas = {
...schemas,
...userConfig.schemas,
};
}
return schemas;
};

const getServices = (userConfig: UserConfig): Config['services'] => {
let services: Config['services'] = {
export: true,
Expand Down Expand Up @@ -152,7 +168,6 @@ const initConfig = async (
name,
operationId = true,
request,
schemas = true,
serviceResponse = 'body',
useDateType = false,
useOptions = true,
Expand Down Expand Up @@ -182,6 +197,7 @@ const initConfig = async (

const client = userConfig.client || inferClient(dependencies);
const output = path.resolve(process.cwd(), userConfig.output);
const schemas = getSchemas(userConfig);
const services = getServices(userConfig);
const types = getTypes(userConfig);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ describe('getOperationName', () => {
lint: false,
operationId: true,
output: '',
schemas: false,
schemas: {
export: false,
},
serviceResponse: 'body',
services: {
export: false,
Expand All @@ -42,7 +44,9 @@ describe('getOperationName', () => {
lint: false,
operationId: false,
output: '',
schemas: false,
schemas: {
export: false,
},
serviceResponse: 'body',
services: {
export: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ describe('getServices', () => {
lint: false,
operationId: false,
output: '',
schemas: true,
schemas: {},
serviceResponse: 'body',
services: {},
types: {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ describe('getServices', () => {
lint: false,
operationId: true,
output: '',
schemas: true,
schemas: {},
serviceResponse: 'body',
services: {},
types: {},
Expand Down
22 changes: 19 additions & 3 deletions packages/openapi-ts/src/types/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,25 @@ export interface UserConfig {
*/
request?: string;
/**
* Export JSON schemas?
* Generate JSON schemas?
* @default true
*/
schemas?: boolean;
schemas?:
| boolean
| {
/**
* Generate JSON schemas?
* @default true
*/
export?: boolean;
/**
* Choose schema type to generate. Select 'form' if you don't want
* descriptions to reduce bundle size and you plan to use schemas
* for form validation
* @default 'json'
*/
type?: 'form' | 'json';
};
/**
* Define shape of returned value from service calls
* @default 'body'
Expand Down Expand Up @@ -129,9 +144,10 @@ export interface UserConfig {

export type Config = Omit<
Required<UserConfig>,
'base' | 'name' | 'request' | 'services' | 'types'
'base' | 'name' | 'request' | 'schemas' | 'services' | 'types'
> &
Pick<UserConfig, 'base' | 'name' | 'request'> & {
schemas: Extract<Required<UserConfig>['schemas'], object>;
services: Extract<Required<UserConfig>['services'], object>;
types: Extract<Required<UserConfig>['types'], object>;
};
4 changes: 2 additions & 2 deletions packages/openapi-ts/src/utils/__tests__/handlebars.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ describe('registerHandlebarHelpers', () => {
lint: false,
operationId: true,
output: '',
schemas: true,
schemas: {},
serviceResponse: 'body',
services: {},
types: {},
Expand Down Expand Up @@ -50,7 +50,7 @@ describe('registerHandlebarTemplates', () => {
lint: false,
operationId: true,
output: '',
schemas: true,
schemas: {},
serviceResponse: 'body',
services: {},
types: {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ describe('writeClientClass', () => {
name: 'AppClient',
operationId: true,
output: '',
schemas: true,
schemas: {},
serviceResponse: 'body',
services: {},
types: {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ describe('writeClient', () => {
lint: false,
operationId: true,
output: './dist',
schemas: true,
schemas: {},
serviceResponse: 'body',
services: {},
types: {},
Expand Down
6 changes: 3 additions & 3 deletions packages/openapi-ts/src/utils/write/__tests__/core.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ describe('writeCore', () => {
name: 'AppClient',
operationId: true,
output: '',
schemas: true,
schemas: {},
serviceResponse: 'body',
services: {},
types: {},
Expand Down Expand Up @@ -94,7 +94,7 @@ describe('writeCore', () => {
name: 'AppClient',
operationId: true,
output: '',
schemas: true,
schemas: {},
serviceResponse: 'body',
services: {},
types: {},
Expand Down Expand Up @@ -134,7 +134,7 @@ describe('writeCore', () => {
name: 'AppClient',
operationId: true,
output: '',
schemas: true,
schemas: {},
serviceResponse: 'body',
services: {},
types: {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ describe('processIndex', () => {
lint: false,
operationId: true,
output: '',
schemas: true,
schemas: {},
serviceResponse: 'body',
services: {},
types: {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ describe('processTypesAndEnums', () => {
name: 'AppClient',
operationId: true,
output: '',
schemas: true,
schemas: {},
serviceResponse: 'body',
services: {},
types: {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ describe('processSchemas', () => {
name: 'AppClient',
operationId: true,
output: '',
schemas: true,
schemas: {},
serviceResponse: 'body',
services: {},
types: {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ describe('processServices', () => {
lint: false,
operationId: true,
output: '',
schemas: true,
schemas: {},
serviceResponse: 'body',
services: {},
types: {},
Expand Down
2 changes: 1 addition & 1 deletion packages/openapi-ts/src/utils/write/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export const writeClient = async (
name: 'enums.ts',
});
}
if (config.schemas) {
if (config.schemas.export) {
files.schemas = new TypeScriptFile({
dir: config.output,
name: 'schemas.ts',
Expand Down
39 changes: 38 additions & 1 deletion packages/openapi-ts/src/utils/write/schemas.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,39 @@
import { compiler, TypeScriptFile } from '../../compiler';
import type { OpenApi } from '../../openApi';
import { ensureValidTypeScriptJavaScriptIdentifier } from '../../openApi/common/parser/sanitize';
import { getConfig } from '../config';

const schemaToFormSchema = (schema: unknown): object => {
if (Array.isArray(schema)) {
return schema.map((item) => schemaToFormSchema(item));
}

if (typeof schema !== 'object' || schema === null) {
return schema as object;
}

const result = { ...schema };
Object.entries(result).forEach(([key, value]) => {
if (
[
'description',
'x-enum-descriptions',
'x-enum-varnames',
'x-enumNames',
].includes(key)
) {
// @ts-ignore
delete result[key];
return;
}

if (value && typeof value === 'object') {
// @ts-ignore
result[key] = schemaToFormSchema(value);
}
});
return result;
};

export const processSchemas = async ({
file,
Expand All @@ -13,8 +46,12 @@ export const processSchemas = async ({
return;
}

const addSchema = (name: string, obj: any) => {
const config = getConfig();

const addSchema = (name: string, schema: object) => {
const validName = `$${ensureValidTypeScriptJavaScriptIdentifier(name)}`;
const obj =
config.schemas.type === 'form' ? schemaToFormSchema(schema) : schema;
const expression = compiler.types.object({ obj });
const statement = compiler.export.asConst(validName, expression);
file.add(statement);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// This file is auto-generated by @hey-api/openapi-ts

export * from './schemas.gen';
Loading

0 comments on commit a15612d

Please sign in to comment.