Skip to content

Commit

Permalink
Merge pull request #197 from hey-api/feat/additional-schema-properties
Browse files Browse the repository at this point in the history
feat(schema): additional schema properties
  • Loading branch information
jordanshatford authored Apr 2, 2024
2 parents 7a19cf3 + 80967f8 commit ca2847f
Show file tree
Hide file tree
Showing 24 changed files with 179 additions and 84 deletions.
5 changes: 5 additions & 0 deletions .changeset/fresh-timers-train.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@hey-api/openapi-ts": minor
---

feat(schema): add support for default values
5 changes: 5 additions & 0 deletions .changeset/swift-candles-melt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@hey-api/openapi-ts": minor
---

feat(schema): add array of enum values for enums
2 changes: 1 addition & 1 deletion src/openApi/common/interfaces/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export interface Operation extends OperationParameters {
}

export interface Schema {
default?: unknown;
exclusiveMaximum?: boolean;
exclusiveMinimum?: boolean;
format?:
Expand Down Expand Up @@ -95,7 +96,6 @@ export interface Model extends Schema {
*/
$refs: string[];
base: string;
default?: string;
deprecated?: boolean;
description: string | null;
enum: Enum[];
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import type { Model } from '../../common/interfaces/client';
import type { OpenApiSchema } from '../interfaces/OpenApiSchema';

export const getModelDefault = (definition: OpenApiSchema, model?: Model): string | undefined => {
import type { OpenApiParameter } from '../../v2/interfaces/OpenApiParameter';
import type { OpenApiSchema } from '../../v3/interfaces/OpenApiSchema';
import type { OperationParameter } from '../interfaces/client';

export const getDefault = (
definition: OpenApiSchema | OpenApiParameter,
model?: Model | OperationParameter
): string | undefined => {
if (definition.default === undefined) {
return undefined;
}
Expand All @@ -16,25 +21,21 @@ export const getModelDefault = (definition: OpenApiSchema, model?: Model): strin
case 'int':
case 'integer':
case 'number':
if (model?.export === 'enum' && model.enum?.[definition.default]) {
const { value } = model.enum[definition.default];
if (model?.export === 'enum' && model.enum?.[definition.default as number]) {
const { value } = model.enum[definition.default as number];
return typeof value === 'string' ? `'${value}'` : String(value);
}
return String(definition.default);

case 'boolean':
return JSON.stringify(definition.default);

case 'string':
return `'${definition.default}'`;

case 'array':
case 'boolean':
case 'object':
try {
return JSON.stringify(definition.default, null, 4);
} catch (e) {
// Ignore
}
}

return undefined;
};
2 changes: 1 addition & 1 deletion src/openApi/common/parser/sort.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Sort list of values and ensure that required parameters are first so that we do not generate
* invalid types. Optional parameters cannot be positioned after required ones.
*/
export function toSortedByRequired<T extends { isRequired: boolean; default?: string }>(values: T[]): T[] {
export function toSortedByRequired<T extends { isRequired: boolean; default?: unknown }>(values: T[]): T[] {
return values.sort((a, b) => {
const aNeedsValue = a.isRequired && a.default === undefined;
const bNeedsValue = b.isRequired && b.default === undefined;
Expand Down
2 changes: 1 addition & 1 deletion src/openApi/v2/interfaces/OpenApiParameter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export interface OpenApiParameter extends OpenApiReference, WithEnumExtension, W
allowEmptyValue?: boolean;
items?: OpenApiItems;
collectionFormat?: 'csv' | 'ssv' | 'tsv' | 'pipes' | 'multi';
default?: number;
default?: unknown;
maximum?: number;
exclusiveMaximum?: boolean;
minimum?: number;
Expand Down
16 changes: 8 additions & 8 deletions src/openApi/v2/parser/getOperationParameter.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { OperationParameter } from '../../common/interfaces/client';
import { getDefault } from '../../common/parser/getDefault';
import { getEnums } from '../../common/parser/getEnums';
import { getPattern } from '../../common/parser/getPattern';
import { getRef } from '../../common/parser/getRef';
Expand All @@ -8,7 +9,6 @@ import type { OpenApi } from '../interfaces/OpenApi';
import type { OpenApiParameter } from '../interfaces/OpenApiParameter';
import type { OpenApiSchema } from '../interfaces/OpenApiSchema';
import { getModel } from './getModel';
import { getOperationParameterDefault } from './getOperationParameterDefault';

export const getOperationParameter = (openApi: OpenApi, parameter: OpenApiParameter): OperationParameter => {
const operationParameter: OperationParameter = {
Expand Down Expand Up @@ -52,7 +52,7 @@ export const getOperationParameter = (openApi: OpenApi, parameter: OpenApiParame
operationParameter.base = definitionRef.base;
operationParameter.template = definitionRef.template;
operationParameter.imports.push(...definitionRef.imports);
operationParameter.default = getOperationParameterDefault(parameter, operationParameter);
operationParameter.default = getDefault(parameter, operationParameter);
return operationParameter;
}

Expand All @@ -63,7 +63,7 @@ export const getOperationParameter = (openApi: OpenApi, parameter: OpenApiParame
operationParameter.enum.push(...enums);
operationParameter.export = 'enum';
operationParameter.type = 'string';
operationParameter.default = getOperationParameterDefault(parameter, operationParameter);
operationParameter.default = getDefault(parameter, operationParameter);
return operationParameter;
}
}
Expand All @@ -75,7 +75,7 @@ export const getOperationParameter = (openApi: OpenApi, parameter: OpenApiParame
operationParameter.base = items.base;
operationParameter.template = items.template;
operationParameter.imports.push(...items.imports);
operationParameter.default = getOperationParameterDefault(parameter, operationParameter);
operationParameter.default = getDefault(parameter, operationParameter);
return operationParameter;
}

Expand All @@ -86,7 +86,7 @@ export const getOperationParameter = (openApi: OpenApi, parameter: OpenApiParame
operationParameter.base = items.base;
operationParameter.template = items.template;
operationParameter.imports.push(...items.imports);
operationParameter.default = getOperationParameterDefault(parameter, operationParameter);
operationParameter.default = getDefault(parameter, operationParameter);
return operationParameter;
}

Expand All @@ -102,7 +102,7 @@ export const getOperationParameter = (openApi: OpenApi, parameter: OpenApiParame
operationParameter.base = model.base;
operationParameter.template = model.template;
operationParameter.imports.push(...model.imports);
operationParameter.default = getOperationParameterDefault(parameter, operationParameter);
operationParameter.default = getDefault(parameter, operationParameter);
return operationParameter;
} else {
const model = getModel(openApi, schema);
Expand All @@ -115,7 +115,7 @@ export const getOperationParameter = (openApi: OpenApi, parameter: OpenApiParame
operationParameter.enum.push(...model.enum);
operationParameter.enums.push(...model.enums);
operationParameter.properties.push(...model.properties);
operationParameter.default = getOperationParameterDefault(parameter, operationParameter);
operationParameter.default = getDefault(parameter, operationParameter);
return operationParameter;
}
}
Expand All @@ -128,7 +128,7 @@ export const getOperationParameter = (openApi: OpenApi, parameter: OpenApiParame
operationParameter.base = definitionType.base;
operationParameter.template = definitionType.template;
operationParameter.imports.push(...definitionType.imports);
operationParameter.default = getOperationParameterDefault(parameter, operationParameter);
operationParameter.default = getDefault(parameter, operationParameter);
return operationParameter;
}

Expand Down
43 changes: 0 additions & 43 deletions src/openApi/v2/parser/getOperationParameterDefault.ts

This file was deleted.

2 changes: 1 addition & 1 deletion src/openApi/v3/interfaces/OpenApiSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export interface OpenApiSchema extends OpenApiReference, WithEnumExtension {
allOf?: OpenApiSchema[];
anyOf?: OpenApiSchema[];
const?: string | number | boolean | null;
default?: number;
default?: unknown;
deprecated?: boolean;
description?: string;
discriminator?: OpenApiDiscriminator;
Expand Down
14 changes: 7 additions & 7 deletions src/openApi/v3/parser/getModel.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import type { Model } from '../../common/interfaces/client';
import { getDefault } from '../../common/parser/getDefault';
import { getEnums } from '../../common/parser/getEnums';
import { getPattern } from '../../common/parser/getPattern';
import { getType } from '../../common/parser/type';
import type { OpenApi } from '../interfaces/OpenApi';
import type { OpenApiSchema } from '../interfaces/OpenApiSchema';
import { findModelComposition, getModelComposition } from './getModelComposition';
import { getModelDefault } from './getModelDefault';
import { getAdditionalPropertiesModel, getModelProperties } from './getModelProperties';
import { inferType } from './inferType';

Expand Down Expand Up @@ -59,7 +59,7 @@ export const getModel = (
model.imports = [...model.imports, ...definitionRef.imports];
model.template = definitionRef.template;
model.type = definitionRef.type;
model.default = getModelDefault(definition, model);
model.default = getDefault(definition, model);
return model;
}

Expand All @@ -70,7 +70,7 @@ export const getModel = (
model.enum = [...model.enum, ...enums];
model.export = 'enum';
model.type = 'string';
model.default = getModelDefault(definition, model);
model.default = getDefault(definition, model);
return model;
}
}
Expand All @@ -84,7 +84,7 @@ export const getModel = (
model.imports = [...model.imports, ...arrayItems.imports];
model.template = arrayItems.template;
model.type = arrayItems.type;
model.default = getModelDefault(definition, model);
model.default = getDefault(definition, model);
return model;
}

Expand Down Expand Up @@ -112,7 +112,7 @@ export const getModel = (
model.link = arrayItems;
model.template = arrayItems.template;
model.type = arrayItems.type;
model.default = getModelDefault(definition, model);
model.default = getDefault(definition, model);
return model;
}

Expand All @@ -133,7 +133,7 @@ export const getModel = (
model.base = 'any';
model.export = 'interface';
model.type = 'any';
model.default = getModelDefault(definition, model);
model.default = getDefault(definition, model);

const modelProperties = getModelProperties(openApi, definition, getModel, model);
modelProperties.forEach(modelProperty => {
Expand Down Expand Up @@ -176,7 +176,7 @@ export const getModel = (
model.isNullable = definitionType.isNullable || model.isNullable;
model.template = definitionType.template;
model.type = definitionType.type;
model.default = getModelDefault(definition, model);
model.default = getDefault(definition, model);
return model;
}

Expand Down
10 changes: 6 additions & 4 deletions src/openApi/v3/parser/getModelProperties.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { escapeName } from '../../../utils/escapeName';
import type { Model } from '../../common/interfaces/client';
import { getDefault } from '../../common/parser/getDefault';
import { getPattern } from '../../common/parser/getPattern';
import { getType } from '../../common/parser/type';
import type { OpenApi } from '../interfaces/OpenApi';
import type { OpenApiSchema } from '../interfaces/OpenApiSchema';
import { findOneOfParentDiscriminator, mapPropertyValue } from './discriminator';
import type { getModel } from './getModel';
import { getModelDefault } from './getModelDefault';

// Fix for circular dependency
export type GetModelFn = typeof getModel;
Expand All @@ -21,7 +21,7 @@ export const getAdditionalPropertiesModel = (
const apModel = getModel(openApi, ap);

if (definition.additionalProperties === true && definition.properties) {
apModel.default = getModelDefault(definition, model);
apModel.default = getDefault(definition, model);
apModel.export = 'generic';
apModel.isRequired = true;
apModel.name = '[key: string]';
Expand All @@ -31,7 +31,7 @@ export const getAdditionalPropertiesModel = (
if (ap.$ref) {
const apType = getType(ap.$ref);
model.base = apType.base;
model.default = getModelDefault(definition, model);
model.default = getDefault(definition, model);
model.export = 'dictionary';
model.imports.push(...apType.imports);
model.template = apType.template;
Expand All @@ -40,7 +40,7 @@ export const getAdditionalPropertiesModel = (
}

model.base = apModel.base;
model.default = getModelDefault(definition, model);
model.default = getDefault(definition, model);
model.export = 'dictionary';
model.imports.push(...apModel.imports);
model.link = apModel;
Expand Down Expand Up @@ -78,6 +78,7 @@ export const getModelProperties = (
> = {
deprecated: property.deprecated === true,
description: property.description || null,
default: property.default,
exclusiveMaximum: property.exclusiveMaximum,
exclusiveMinimum: property.exclusiveMinimum,
format: property.format,
Expand Down Expand Up @@ -138,6 +139,7 @@ export const getModelProperties = (
enum: model.enum,
enums: model.enums,
export: model.export,
default: model.default,
imports: model.imports,
isNullable: model.isNullable || property.nullable === true,
link: model.link,
Expand Down
4 changes: 2 additions & 2 deletions src/openApi/v3/parser/getOperationParameter.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { OperationParameter } from '../../common/interfaces/client';
import { getDefault } from '../../common/parser/getDefault';
import { getPattern } from '../../common/parser/getPattern';
import { getRef } from '../../common/parser/getRef';
import { getOperationParameterName } from '../../common/parser/operation';
Expand All @@ -7,7 +8,6 @@ import type { OpenApi } from '../interfaces/OpenApi';
import type { OpenApiParameter } from '../interfaces/OpenApiParameter';
import type { OpenApiSchema } from '../interfaces/OpenApiSchema';
import { getModel } from './getModel';
import { getModelDefault } from './getModelDefault';

export const getOperationParameter = (openApi: OpenApi, parameter: OpenApiParameter): OperationParameter => {
const operationParameter: OperationParameter = {
Expand Down Expand Up @@ -57,7 +57,7 @@ export const getOperationParameter = (openApi: OpenApi, parameter: OpenApiParame
operationParameter.template = model.template;
operationParameter.$refs = [...operationParameter.$refs, ...model.$refs];
operationParameter.imports = [...operationParameter.imports, ...model.imports];
operationParameter.default = getModelDefault(schema);
operationParameter.default = getDefault(schema);
return operationParameter;
} else {
const model = getModel(openApi, schema);
Expand Down
3 changes: 3 additions & 0 deletions src/templates/partials/schemaArray.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
type: '{{{base}}}',
},
{{/if}}
{{#notEquals default undefined}}
default: {{{default}}},
{{/notEquals}}
{{#if isReadOnly}}
isReadOnly: {{{isReadOnly}}},
{{/if}}
Expand Down
3 changes: 3 additions & 0 deletions src/templates/partials/schemaComposition.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
description: `{{{escapeDescription description}}}`,
{{/if}}
contains: [{{#each properties}}{{>schema}}{{#unless @last}}, {{/unless}}{{/each}}],
{{#notEquals default undefined}}
default: {{{default}}},
{{/notEquals}}
{{#if isReadOnly}}
isReadOnly: {{{isReadOnly}}},
{{/if}}
Expand Down
3 changes: 3 additions & 0 deletions src/templates/partials/schemaDictionary.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
type: '{{{base}}}',
},
{{/if}}
{{#notEquals default undefined}}
default: {{{default}}},
{{/notEquals}}
{{#if isReadOnly}}
isReadOnly: {{{isReadOnly}}},
{{/if}}
Expand Down
Loading

0 comments on commit ca2847f

Please sign in to comment.