Skip to content

Commit

Permalink
feat: add input.filters.schemas option (#1426)
Browse files Browse the repository at this point in the history
* feat: add `input.filters.schemas` option to types

* chore: refactoring to extruct parse schema

* chore: refactoring for extruct `InputFiltersOption` type

* feat: add filter proccess in generate schema objects

* chore: add test for `input.filters`

* docs: add `input.filters.schemas` option into guide
  • Loading branch information
soartec-lab authored Jun 1, 2024
1 parent e8089a4 commit bc21aad
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 77 deletions.
19 changes: 19 additions & 0 deletions docs/src/pages/reference/configuration/input.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,25 @@ module.exports = {
};
```

#### schemas

Type: Array of `string` or `RegExp`.

Only schemas names match the specified `string` or `RegExp` will be automatically generated.
For instance the example below only generates the `schema` object that matches string `Error` or regular expression `/Cat/`.

```js
module.exports = {
petstore: {
input: {
filters: {
schemas: ['Error', /Cat/],
},
},
},
};
```

### converterOptions

Type: `Object`.
Expand Down
148 changes: 81 additions & 67 deletions packages/core/src/generators/schema-definition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,15 @@ import isEmpty from 'lodash.isempty';
import { SchemaObject, SchemasObject } from 'openapi3-ts/oas30';
import { getEnum, resolveDiscriminators } from '../getters';
import { resolveRef, resolveValue } from '../resolvers';
import { ContextSpecs, GeneratorSchema } from '../types';
import { upath, isReference, jsDoc, pascal, sanitize } from '../utils';
import { ContextSpecs, GeneratorSchema, InputFiltersOption } from '../types';
import {
upath,
isReference,
jsDoc,
pascal,
sanitize,
isString,
} from '../utils';
import { generateInterface } from './interface';

/**
Expand All @@ -15,91 +22,98 @@ export const generateSchemasDefinition = (
schemas: SchemasObject = {},
context: ContextSpecs,
suffix: string,
schemasFilters?: InputFiltersOption['schemas'],
): GeneratorSchema[] => {
if (isEmpty(schemas)) {
return [];
}

const transformedSchemas = resolveDiscriminators(schemas, context);
const models = Object.entries(transformedSchemas).reduce(
(acc, [name, schema]) => {
const schemaName = sanitize(`${pascal(name)}${suffix}`, {
underscore: '_',
whitespace: '_',
dash: true,
es5keyword: true,
es5IdentifierName: true,
});
if (shouldCreateInterface(schema)) {
acc.push(
...generateInterface({
name: schemaName,
schema,
context,
suffix,
}),
);

return acc;
} else {
const resolvedValue = resolveValue({
schema,
let generateSchemas = Object.entries(transformedSchemas);
if (schemasFilters) {
generateSchemas = generateSchemas.filter(([schemaName]) => {
return schemasFilters.some((filter) =>
isString(filter) ? filter === schemaName : filter.test(schemaName),
);
});
}

const models = generateSchemas.reduce((acc, [name, schema]) => {
const schemaName = sanitize(`${pascal(name)}${suffix}`, {
underscore: '_',
whitespace: '_',
dash: true,
es5keyword: true,
es5IdentifierName: true,
});
if (shouldCreateInterface(schema)) {
acc.push(
...generateInterface({
name: schemaName,
schema,
context,
});
suffix,
}),
);

return acc;
} else {
const resolvedValue = resolveValue({
schema,
name: schemaName,
context,
});

let output = '';
let output = '';

let imports = resolvedValue.imports;
let imports = resolvedValue.imports;

output += jsDoc(schema);
output += jsDoc(schema);

if (resolvedValue.isEnum && !resolvedValue.isRef) {
output += getEnum(
resolvedValue.value,
schemaName,
resolvedValue.originalSchema?.['x-enumNames'],
context.output.override.useNativeEnums,
if (resolvedValue.isEnum && !resolvedValue.isRef) {
output += getEnum(
resolvedValue.value,
schemaName,
resolvedValue.originalSchema?.['x-enumNames'],
context.output.override.useNativeEnums,
);
} else if (schemaName === resolvedValue.value && resolvedValue.isRef) {
// Don't add type if schema has same name and the referred schema will be an interface
const { schema: referredSchema } = resolveRef(schema, context);
if (!shouldCreateInterface(referredSchema as SchemaObject)) {
const imp = resolvedValue.imports.find(
(imp) => imp.name === schemaName,
);
} else if (schemaName === resolvedValue.value && resolvedValue.isRef) {
// Don't add type if schema has same name and the referred schema will be an interface
const { schema: referredSchema } = resolveRef(schema, context);
if (!shouldCreateInterface(referredSchema as SchemaObject)) {
const imp = resolvedValue.imports.find(
(imp) => imp.name === schemaName,
);

if (!imp) {
output += `export type ${schemaName} = ${resolvedValue.value};\n`;
} else {
const alias = imp?.specKey
? `${pascal(upath.getSpecName(imp.specKey, context.specKey))}${
resolvedValue.value
}`
: `${resolvedValue.value}Bis`;
if (!imp) {
output += `export type ${schemaName} = ${resolvedValue.value};\n`;
} else {
const alias = imp?.specKey
? `${pascal(upath.getSpecName(imp.specKey, context.specKey))}${
resolvedValue.value
}`
: `${resolvedValue.value}Bis`;

output += `export type ${schemaName} = ${alias};\n`;
output += `export type ${schemaName} = ${alias};\n`;

imports = imports.map((imp) =>
imp.name === schemaName ? { ...imp, alias } : imp,
);
}
imports = imports.map((imp) =>
imp.name === schemaName ? { ...imp, alias } : imp,
);
}
} else {
output += `export type ${schemaName} = ${resolvedValue.value};\n`;
}
} else {
output += `export type ${schemaName} = ${resolvedValue.value};\n`;
}

acc.push(...resolvedValue.schemas, {
name: schemaName,
model: output,
imports,
});
acc.push(...resolvedValue.schemas, {
name: schemaName,
model: output,
imports,
});

return acc;
}
},
[] as GeneratorSchema[],
);
return acc;
}
}, [] as GeneratorSchema[]);

return models;
};
Expand Down
13 changes: 7 additions & 6 deletions packages/core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,7 @@ export type NormalizedInputOptions = {
override: OverrideInput;
converterOptions: swagger2openapi.Options;
parserOptions: SwaggerParserOptions;
filters?: {
tags?: (string | RegExp)[];
};
filters?: InputFiltersOption;
};

export type OutputClientFunc = (
Expand Down Expand Up @@ -190,15 +188,18 @@ export type SwaggerParserOptions = Omit<SwaggerParser.Options, 'validate'> & {
validate?: boolean;
};

export type InputFiltersOption = {
tags?: (string | RegExp)[];
schemas?: (string | RegExp)[];
};

export type InputOptions = {
target: string | Record<string, unknown> | OpenAPIObject;
validation?: boolean;
override?: OverrideInput;
converterOptions?: swagger2openapi.Options;
parserOptions?: SwaggerParserOptions;
filters?: {
tags?: (string | RegExp)[];
};
filters?: InputFiltersOption;
};

export const OutputClient = {
Expand Down
13 changes: 9 additions & 4 deletions packages/orval/src/import-open-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export const importOpenApi = async ({
}: ImportOpenApi): Promise<WriteSpecsBuilder> => {
const specs = await generateInputSpecs({ specs: data, input, workspace });

const schemas = getApiSchemas({ output, target, workspace, specs });
const schemas = getApiSchemas({ input, output, target, workspace, specs });

const api = await getApiBuilder({
// @ts-expect-error // FIXME
Expand Down Expand Up @@ -93,11 +93,13 @@ const generateInputSpecs = async ({
};

const getApiSchemas = ({
input,
output,
target,
workspace,
specs,
}: {
input: InputOptions;
output: NormalizedOutputOptions;
workspace: string;
target: string;
Expand All @@ -113,12 +115,15 @@ const getApiSchemas = ({
output,
};

const parsedSchemas = spec.openapi
? (spec.components?.schemas as SchemasObject)
: getAllSchemas(spec, specKey);

const schemaDefinition = generateSchemasDefinition(
!spec.openapi
? getAllSchemas(spec, specKey)
: (spec.components?.schemas as SchemasObject),
parsedSchemas,
context,
output.override.components.schemas.suffix,
input.filters?.schemas,
);

const responseDefinition = generateComponentDefinition(
Expand Down
10 changes: 10 additions & 0 deletions tests/configs/default.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@ export default defineConfig({
input: '../specifications/petstore.yaml',
output: '../generated/default/petstore/endpoints.ts',
},
'petstore-filter': {
input: {
target: '../specifications/petstore.yaml',
filters: {
tags: ['health'],
schemas: ['Error', /Cat/],
},
},
output: '../generated/default/petstore-filter/endpoints.ts',
},
'petstore-transfomer': {
output: {
target: '../generated/default/petstore-transformer/endpoints.ts',
Expand Down

0 comments on commit bc21aad

Please sign in to comment.