Skip to content
Open
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
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,10 @@ Create config file in project root
module.exports = {
input: 'api', // "input" of aspida is "output" for openapi2aspida
outputEachDir: true, // Generate $api.ts in each endpoint directory
openapi: { inputFile: 'https://petstore.swagger.io/v2/swagger.json' },
openapi: {
inputFile: 'https://petstore.swagger.io/v2/swagger.json',
includeDeprecated: false, // Optional: include deprecated fields/endpoints (default: false)
},
};
```

Expand Down
25 changes: 25 additions & 0 deletions samples/deprecated-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
openapi: 3.0.0
info:
title: Test API
version: 1.0.0
paths:
/test:
get:
deprecated: true
responses:
'200':
description: Success
post:
responses:
'200':
description: Success
components:
schemas:
TestSchema:
type: object
properties:
active_field:
type: string
deprecated_field:
type: string
deprecated: true
7 changes: 5 additions & 2 deletions src/buildTemplate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ import resolveExternalRefs from './resolveExternalRefs';

const isV3 = (openapi: OpenAPI.Document): openapi is OpenAPIV3.Document => 'openapi' in openapi;

export default async ({ input, isYaml }: Config) => {
export default async (config: Config) => {
const { input, isYaml } = config;
const openapi = await SwaggerParser.parse(input, { parse: { json: !isYaml } });
const docs = isV3(openapi)
? openapi
: await require('swagger2openapi').convertObj(openapi, { direct: true, resolveInternal: true });

return resolveExternalRefs(docs, typeof input === 'string' ? input : '').then(buildV3);
return resolveExternalRefs(docs, typeof input === 'string' ? input : '').then((resolvedDocs) =>
buildV3(resolvedDocs, config),
);
};
19 changes: 15 additions & 4 deletions src/buildV3.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { OpenAPIV3 } from 'openapi-types';
import { setIncludeDeprecated } from './builderUtils/conversionContext';
import {
$ref2Type,
BINARY_TYPE,
Expand All @@ -15,6 +16,7 @@ import requestBodies2Props from './builderUtils/requestBodies2Props';
import { resolveParamsRef, resolveReqRef, resolveResRef } from './builderUtils/resolvers';
import responses2Props from './builderUtils/responses2Props';
import schemas2Props from './builderUtils/schemas2Props';
import type { Config } from './getConfig';

const methodNames = ['get', 'post', 'put', 'delete', 'head', 'options', 'patch'] as const;

Expand All @@ -23,10 +25,14 @@ const getParamsList = (
params?: (OpenAPIV3.ReferenceObject | OpenAPIV3.ParameterObject)[],
) => params?.map((p) => (isRefObject(p) ? resolveParamsRef(openapi, p.$ref) : p)) || [];

export default (openapi: OpenAPIV3.Document) => {
export default (openapi: OpenAPIV3.Document, config: Config) => {
setIncludeDeprecated(config.includeDeprecated || false);

const files: { file: string[]; methods: string }[] = [];
const schemas = schemas2Props(openapi.components?.schemas, openapi) || [];
const parameters = parameters2Props(openapi.components?.parameters, openapi) || [];
const schemas =
schemas2Props(openapi.components?.schemas, openapi, config.includeDeprecated) || [];
const parameters =
parameters2Props(openapi.components?.parameters, openapi, config.includeDeprecated) || [];
const requestBodies = requestBodies2Props(openapi.components?.requestBodies) || [];
const responses = responses2Props(openapi.components?.responses) || [];
const headers = headers2Props(openapi.components?.headers) || [];
Expand Down Expand Up @@ -67,7 +73,7 @@ export default (openapi: OpenAPIV3.Document) => {
.map<Prop | null>((method) => {
const target = openapi.paths[path]![method]!;

if (target.deprecated) return null;
if (target.deprecated && !config.includeDeprecated) return null;

const params: Prop[] = [];

Expand All @@ -82,6 +88,9 @@ export default (openapi: OpenAPIV3.Document) => {
(p) => {
if (isRefObject(p)) {
const ref = resolveParamsRef(openapi, p.$ref);

if (ref.deprecated && !config.includeDeprecated) return;

const val = {
isArray: false,
isEnum: false,
Expand All @@ -102,6 +111,8 @@ export default (openapi: OpenAPIV3.Document) => {
break;
}
} else {
if (p.deprecated && !config.includeDeprecated) return;

const value = schema2value(p.schema);
if (!value) return;

Expand Down
7 changes: 7 additions & 0 deletions src/builderUtils/conversionContext.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
let includeDeprecated = false;

export const setIncludeDeprecated = (value: boolean) => {
includeDeprecated = value;
};

export const getIncludeDeprecated = (): boolean => includeDeprecated;
4 changes: 3 additions & 1 deletion src/builderUtils/converters.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { OpenAPIV3 } from 'openapi-types';
import { getIncludeDeprecated } from './conversionContext';
import type { Prop, PropValue } from './props2String';

export const defKey2defName = (key: string) =>
Expand Down Expand Up @@ -53,7 +54,8 @@ const object2value = (obj: OpenAPIV3.NonArraySchemaObject): Prop[] => {
const value = Object.keys(properties)
.filter((name) => {
const target = properties[name];
return isRefObject(target) || !target.deprecated;
if (isRefObject(target)) return true;
return getIncludeDeprecated() || !target.deprecated;
})
.map<Prop | null>((name) => {
const val = schema2value(properties[name]);
Expand Down
9 changes: 7 additions & 2 deletions src/builderUtils/parameters2Props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,17 @@ import { resolveParamsRef } from './resolvers';

export type Parameter = { name: string; prop: string | Prop };

export default (params: OpenAPIV3.ComponentsObject['parameters'], openapi: OpenAPIV3.Document) =>
export default (
params: OpenAPIV3.ComponentsObject['parameters'],
openapi: OpenAPIV3.Document,
includeDeprecated = false,
) =>
params &&
Object.keys(params)
.filter((defKey) => {
const target = params[defKey];
return !(isRefObject(target) ? resolveParamsRef(openapi, target.$ref) : target).deprecated;
const resolved = isRefObject(target) ? resolveParamsRef(openapi, target.$ref) : target;
return includeDeprecated || !resolved.deprecated;
})
.map((defKey) => {
const target = params[defKey];
Expand Down
9 changes: 7 additions & 2 deletions src/builderUtils/schemas2Props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,17 @@ import { resolveSchemasRef } from './resolvers';

export type Schema = { name: string; value: PropValue };

export default (schemas: OpenAPIV3.ComponentsObject['schemas'], openapi: OpenAPIV3.Document) =>
export default (
schemas: OpenAPIV3.ComponentsObject['schemas'],
openapi: OpenAPIV3.Document,
includeDeprecated = false,
) =>
schemas &&
Object.keys(schemas)
.filter((defKey) => {
const target = schemas[defKey];
return !(isRefObject(target) ? resolveSchemasRef(openapi, target.$ref) : target).deprecated;
const resolved = isRefObject(target) ? resolveSchemasRef(openapi, target.$ref) : target;
return includeDeprecated || !resolved.deprecated;
})
.map((defKey) => {
const value = schema2value(schemas[defKey]);
Expand Down
3 changes: 3 additions & 0 deletions src/getConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ export type Config = Pick<AspidaConfig, 'outputEachDir' | 'outputMode' | 'traili
input: string | OpenAPI.Document;
output: string;
isYaml: boolean;
includeDeprecated?: boolean;
};

export type ConfigFile = AspidaConfig & {
openapi?: {
inputFile: string;
yaml?: boolean;
outputDir?: string;
includeDeprecated?: boolean;
};
};

Expand All @@ -25,6 +27,7 @@ const createConfig = (config: ConfigFile): Config => {
outputEachDir: config.outputEachDir,
outputMode: config.outputMode,
isYaml: openapi.yaml ?? !openapi.inputFile.endsWith('.json'),
includeDeprecated: openapi.includeDeprecated ?? false,
};
};

Expand Down
47 changes: 47 additions & 0 deletions tests/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,51 @@ describe('cli test', () => {
}),
);
});

describe('includeDeprecated configuration', () => {
beforeAll(async () => {
const configExclude = {
input: '_test-deprecated-exclude',
outputEachDir: true,
openapi: { inputFile: 'samples/deprecated-test.yml', includeDeprecated: false },
};

const configInclude = {
input: '_test-deprecated-include',
outputEachDir: true,
openapi: { inputFile: 'samples/deprecated-test.yml', includeDeprecated: true },
};

await Promise.all([build(configExclude)[0], build(configInclude)[0]]);
});

afterAll(() => {
fs.rmSync('_test-deprecated-exclude', { recursive: true });
fs.rmSync('_test-deprecated-include', { recursive: true });
});

test('main', async () => {
const excludeIndexContent = fs.readFileSync('_test-deprecated-exclude/test/index.ts', 'utf8');
expect(excludeIndexContent).not.toContain('get:');
expect(excludeIndexContent).toContain('post:');

const includeIndexContent = fs.readFileSync('_test-deprecated-include/test/index.ts', 'utf8');
expect(includeIndexContent).toContain('get:');
expect(includeIndexContent).toContain('post:');

const excludeTypesContent = fs.readFileSync(
'_test-deprecated-exclude/@types/index.ts',
'utf8',
);
expect(excludeTypesContent).not.toContain('deprecated_field');
expect(excludeTypesContent).toContain('active_field');

const includeTypesContent = fs.readFileSync(
'_test-deprecated-include/@types/index.ts',
'utf8',
);
expect(includeTypesContent).toContain('deprecated_field');
expect(includeTypesContent).toContain('active_field');
});
});
});