mirror of
https://github.com/LukeHagar/openapi-definition-generator.git
synced 2025-12-06 12:37:46 +00:00
Refactored to use better types
This commit is contained in:
@@ -1,3 +1,5 @@
|
|||||||
|
import type { OpenAPIV3_1 } from "openapi-types";
|
||||||
|
|
||||||
export const example = {
|
export const example = {
|
||||||
numbersMock: {
|
numbersMock: {
|
||||||
smallInt: -20,
|
smallInt: -20,
|
||||||
@@ -43,72 +45,16 @@ export type Config = {
|
|||||||
*/
|
*/
|
||||||
includeExamples: boolean;
|
includeExamples: boolean;
|
||||||
|
|
||||||
/**
|
|
||||||
* @description The type to use for null values
|
|
||||||
*/
|
|
||||||
nullType: 'number' | 'string' | 'integer' | 'boolean';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description Whether to allow oneOf for array items schema
|
* @description Whether to allow oneOf for array items schema
|
||||||
*/
|
*/
|
||||||
allowOneOf: boolean;
|
allowOneOf: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type StringType = {
|
export function convertNumber(number: number, config: Config): OpenAPIV3_1.SchemaObject {
|
||||||
type: 'string';
|
let output: OpenAPIV3_1.SchemaObject;
|
||||||
format?: string;
|
|
||||||
examples?: [string];
|
|
||||||
};
|
|
||||||
|
|
||||||
export type NumberType = {
|
|
||||||
type: 'number';
|
|
||||||
format?: string;
|
|
||||||
examples?: [number];
|
|
||||||
};
|
|
||||||
|
|
||||||
export type ObjectType = {
|
|
||||||
type: 'object';
|
|
||||||
properties: { [key: string]: Output };
|
|
||||||
additionalProperties?: boolean;
|
|
||||||
examples?: [object];
|
|
||||||
};
|
|
||||||
|
|
||||||
export type ArrayType = {
|
|
||||||
type: 'array';
|
|
||||||
items?: Output | { oneOf: Output[] };
|
|
||||||
examples?: [unknown[]];
|
|
||||||
};
|
|
||||||
|
|
||||||
export type BooleanType = {
|
|
||||||
type: 'boolean';
|
|
||||||
format?: string;
|
|
||||||
examples?: [boolean];
|
|
||||||
};
|
|
||||||
|
|
||||||
export type IntegerType = {
|
|
||||||
type: 'integer';
|
|
||||||
format?: string;
|
|
||||||
examples?: [number];
|
|
||||||
};
|
|
||||||
|
|
||||||
export type NullableType = {
|
|
||||||
type: string;
|
|
||||||
format: 'nullable';
|
|
||||||
};
|
|
||||||
|
|
||||||
export type Output =
|
|
||||||
| StringType
|
|
||||||
| NumberType
|
|
||||||
| ObjectType
|
|
||||||
| ArrayType
|
|
||||||
| BooleanType
|
|
||||||
| IntegerType
|
|
||||||
| NullableType;
|
|
||||||
|
|
||||||
export function convertNumber(number: number, config: Config) {
|
|
||||||
let output: Output;
|
|
||||||
if (Number.isInteger(number) && config.allowIntegers) {
|
if (Number.isInteger(number) && config.allowIntegers) {
|
||||||
output = { type: 'integer' } as IntegerType;
|
output = { type: 'integer' }
|
||||||
if (number < 2147483647 && number > -2147483647) {
|
if (number < 2147483647 && number > -2147483647) {
|
||||||
output.format = 'int32';
|
output.format = 'int32';
|
||||||
} else if (Number.isSafeInteger(number)) {
|
} else if (Number.isSafeInteger(number)) {
|
||||||
@@ -117,7 +63,7 @@ export function convertNumber(number: number, config: Config) {
|
|||||||
output.format = 'unsafe';
|
output.format = 'unsafe';
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
output = { type: 'number' } as NumberType;
|
output = { type: 'number' };
|
||||||
}
|
}
|
||||||
if (config.includeExamples) {
|
if (config.includeExamples) {
|
||||||
output.examples = [number];
|
output.examples = [number];
|
||||||
@@ -126,39 +72,23 @@ export function convertNumber(number: number, config: Config) {
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isObject = (item: Output): item is ObjectType => {
|
export function convertArray(array: unknown[], config: Config): OpenAPIV3_1.ArraySchemaObject {
|
||||||
return item.type === 'object';
|
const output: OpenAPIV3_1.ArraySchemaObject = { type: 'array', items: {} };
|
||||||
};
|
const outputItems: OpenAPIV3_1.SchemaObject[] = [];
|
||||||
|
|
||||||
const isArray = (item: Output): item is ArrayType => {
|
|
||||||
return item.type === 'array';
|
|
||||||
};
|
|
||||||
|
|
||||||
const isObjectOrArray = (item: Output): item is ObjectType | ArrayType => {
|
|
||||||
return isObject(item) || isArray(item);
|
|
||||||
};
|
|
||||||
|
|
||||||
export function convertArray(array: unknown[], config: Config) {
|
|
||||||
const output: ArrayType = { type: 'array' };
|
|
||||||
const outputItems: Output[] = [];
|
|
||||||
const items: unknown[] = [];
|
const items: unknown[] = [];
|
||||||
const schema = new Map<string, unknown>();
|
const schema = new Map<string, unknown>();
|
||||||
for (const entry of array) {
|
for (const entry of array) {
|
||||||
if (config.allowOneOf) {
|
if (config.allowOneOf) {
|
||||||
const objectMap = convertObject(entry, config);
|
const objectMap = convertObject(entry, config);
|
||||||
if (
|
const isDuplicate = outputItems.some(item => {
|
||||||
!outputItems.some(
|
const hasSameTypeAndFormat = item.type === objectMap.type && item.format === objectMap.format;
|
||||||
(item) =>
|
const hasSameProperties = item.properties && objectMap.properties &&
|
||||||
(item.type === objectMap.type &&
|
JSON.stringify(Object.keys(item.properties).sort()) === JSON.stringify(Object.keys(objectMap.properties).sort());
|
||||||
!isObjectOrArray(item) &&
|
return hasSameTypeAndFormat || hasSameProperties;
|
||||||
!isObjectOrArray(objectMap) &&
|
});
|
||||||
item.format === objectMap.format) ||
|
|
||||||
(isObject(item) &&
|
if (!isDuplicate) {
|
||||||
isObject(objectMap) &&
|
outputItems.push(objectMap as OpenAPIV3_1.SchemaObject);
|
||||||
Object.keys(item.properties).sort() === Object.keys(objectMap.properties).sort())
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
outputItems.push(objectMap);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
items.push(entry);
|
items.push(entry);
|
||||||
@@ -189,8 +119,8 @@ export function convertArray(array: unknown[], config: Config) {
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function convertString(string: string, config: Config) {
|
export function convertString(string: string, config: Config): OpenAPIV3_1.SchemaObject {
|
||||||
const output: StringType = { type: 'string' };
|
const output: OpenAPIV3_1.SchemaObject = { type: 'string' };
|
||||||
const regxDate = /^(19|20)\d{2}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$/;
|
const regxDate = /^(19|20)\d{2}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$/;
|
||||||
const regxDateTime =
|
const regxDateTime =
|
||||||
/^(19|20)\d{2}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01]).([0-1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9](\.[0-9]{1,3})?(Z|(\+|-)([0-1][0-9]|2[0-3]):[0-5][0-9])$/;
|
/^(19|20)\d{2}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01]).([0-1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9](\.[0-9]{1,3})?(Z|(\+|-)([0-1][0-9]|2[0-3]):[0-5][0-9])$/;
|
||||||
@@ -205,16 +135,16 @@ export function convertString(string: string, config: Config) {
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function convertObject(input: unknown, config: Config) {
|
export function convertObject(input: unknown, config: Config): OpenAPIV3_1.SchemaObject {
|
||||||
if (input === null) {
|
if (input === null) {
|
||||||
return { type: config.nullType, format: 'nullable' } as NullableType;
|
return { type: ['null'] };
|
||||||
} else if (typeof input === 'number') {
|
} else if (typeof input === 'number') {
|
||||||
return convertNumber(input, config);
|
return convertNumber(input, config);
|
||||||
} else if (Array.isArray(input)) {
|
} else if (Array.isArray(input)) {
|
||||||
return convertArray(input, config);
|
return convertArray(input, config);
|
||||||
} else if (typeof input === 'object') {
|
} else if (typeof input === 'object') {
|
||||||
const output: ObjectType = { type: 'object', properties: {} };
|
const output: OpenAPIV3_1.SchemaObject = { type: 'object', properties: {} };
|
||||||
const outputObj: Map<string, Output> = new Map();
|
const outputObj: Map<string, OpenAPIV3_1.SchemaObject> = new Map();
|
||||||
for (const prop in input) {
|
for (const prop in input) {
|
||||||
// @ts-expect-error we are looping through self supplied object keys determined at runtime
|
// @ts-expect-error we are looping through self supplied object keys determined at runtime
|
||||||
outputObj.set(prop, convertObject(input[prop], config));
|
outputObj.set(prop, convertObject(input[prop], config));
|
||||||
@@ -224,7 +154,7 @@ export function convertObject(input: unknown, config: Config) {
|
|||||||
} else if (typeof input === 'string') {
|
} else if (typeof input === 'string') {
|
||||||
return convertString(input, config);
|
return convertString(input, config);
|
||||||
} else if (typeof input === 'boolean') {
|
} else if (typeof input === 'boolean') {
|
||||||
const output: BooleanType = { type: 'boolean' };
|
const output: OpenAPIV3_1.SchemaObject = { type: 'boolean' };
|
||||||
if (config.includeExamples) output.examples = [input];
|
if (config.includeExamples) output.examples = [input];
|
||||||
return output;
|
return output;
|
||||||
} else if (input === undefined) {
|
} else if (input === undefined) {
|
||||||
@@ -234,12 +164,12 @@ export function convertObject(input: unknown, config: Config) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function convertJSONToOAS(input: string, config: Config) {
|
export function convertJSONToOAS(input: string, config: Config): OpenAPIV3_1.SchemaObject {
|
||||||
const obj = JSON.parse(input);
|
const obj = JSON.parse(input);
|
||||||
return convertObject(obj, config);
|
return convertObject(obj, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function convertObjectToOAS(input: object, config: Config) {
|
export function convertObjectToOAS(input: object, config: Config): OpenAPIV3_1.SchemaObject {
|
||||||
return convertObject(input, config);
|
return convertObject(input, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user