Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: even more parsing cleanup #151

Merged
merged 6 commits into from
Mar 27, 2024
Merged
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
1 change: 0 additions & 1 deletion rollup.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ export function handlebarsPlugin(): Plugin {
knownHelpers: {
camelCase: true,
dataParameters: true,
debugThis: true,
enumKey: true,
enumName: true,
enumUnionType: true,
Expand Down
4 changes: 4 additions & 0 deletions src/openApi/common/interfaces/WithEnumExtension.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface WithEnumExtension {
'x-enum-descriptions'?: ReadonlyArray<string>;
'x-enum-varnames'?: ReadonlyArray<string>;
}
124 changes: 124 additions & 0 deletions src/openApi/common/interfaces/client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
export interface ModelComposition extends Pick<Model, '$refs' | 'enums' | 'imports' | 'properties'> {
export: Extract<Model['export'], 'all-of' | 'any-of' | 'one-of'>;
}

export interface Enum {
'x-enum-description'?: string;
'x-enum-varname'?: string;
description?: string;
value: string | number;
}

export interface OperationError {
code: number;
description: string;
}

export interface OperationParameter extends Model {
in: 'path' | 'query' | 'header' | 'formData' | 'body' | 'cookie';
prop: string;
mediaType: string | null;
}

export interface OperationParameters extends Pick<Model, '$refs' | 'imports'> {
parameters: OperationParameter[];
parametersBody: OperationParameter | null;
parametersCookie: OperationParameter[];
parametersForm: OperationParameter[];
parametersHeader: OperationParameter[];
parametersPath: OperationParameter[];
parametersQuery: OperationParameter[];
}

export interface OperationResponse extends Model {
in: 'response' | 'header';
code: number;
}

export interface Operation extends OperationParameters {
deprecated: boolean;
description: string | null;
errors: OperationError[];
method: 'DELETE' | 'GET' | 'HEAD' | 'OPTIONS' | 'PATCH' | 'POST' | 'PUT';
/**
* Method name. Methods contain the request logic.
*/
name: string;
path: string;
responseHeader: string | null;
results: OperationResponse[];
/**
* Service name, might be without postfix. This will be used to name the
* exported class.
*/
service: string;
summary: string | null;
}

export interface Schema {
exclusiveMaximum?: boolean;
exclusiveMinimum?: boolean;
format?:
| 'binary'
| 'boolean'
| 'byte'
| 'date-time'
| 'date'
| 'double'
| 'float'
| 'int32'
| 'int64'
| 'password'
| 'string';
isDefinition: boolean;
isNullable: boolean;
isReadOnly: boolean;
isRequired: boolean;
maximum?: number;
maxItems?: number;
maxLength?: number;
maxProperties?: number;
minimum?: number;
minItems?: number;
minLength?: number;
minProperties?: number;
multipleOf?: number;
pattern?: string;
uniqueItems?: boolean;
}

export interface Model extends Schema {
/**
* **Experimental.** Contains list of original refs so they can be used
* to access the schema from anywhere instead of relying on string name.
* This allows us to do things like detect type of ref.
*/
$refs: string[];
base: string;
default?: string;
deprecated?: boolean;
description: string | null;
enum: Enum[];
enums: Model[];
export:
| 'all-of'
| 'any-of'
| 'array'
| 'const'
| 'dictionary'
| 'enum'
| 'generic'
| 'interface'
| 'one-of'
| 'reference';
imports: string[];
link: Model | null;
name: string;
properties: Model[];
template: string | null;
type: string;
}

export interface Service extends Pick<Model, '$refs' | 'imports' | 'name'> {
operations: Operation[];
}
59 changes: 29 additions & 30 deletions src/openApi/common/parser/__tests__/sanitize.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,47 +8,46 @@ import {
} from '../sanitize';

describe('sanitizeOperationName', () => {
it('should remove/replace illegal characters', () => {
expect(sanitizeOperationName('abc')).toEqual('abc');
expect(sanitizeOperationName('æbc')).toEqual('æbc');
expect(sanitizeOperationName('æb.c')).toEqual('æb-c');
expect(sanitizeOperationName('1æb.c')).toEqual('æb-c');
it.each([
{ input: 'abc', expected: 'abc' },
{ input: 'æbc', expected: 'æbc' },
{ input: 'æb.c', expected: 'æb-c' },
{ input: '1æb.c', expected: 'æb-c' },
])('sanitizeOperationName($input) -> $expected', ({ input, expected }) => {
expect(sanitizeOperationName(input)).toEqual(expected);
});
});

describe('sanitizeOperationParameterName', () => {
it('should remove/replace illegal characters', () => {
expect(sanitizeOperationParameterName('abc')).toEqual('abc');
expect(sanitizeOperationParameterName('æbc')).toEqual('æbc');
expect(sanitizeOperationParameterName('æb.c')).toEqual('æb-c');
expect(sanitizeOperationParameterName('1æb.c')).toEqual('æb-c');
expect(sanitizeOperationParameterName('unknown[]')).toEqual('unknownArray');
it.each([
{ input: 'abc', expected: 'abc' },
{ input: 'æbc', expected: 'æbc' },
{ input: 'æb.c', expected: 'æb-c' },
{ input: '1æb.c', expected: 'æb-c' },
{ input: 'unknown[]', expected: 'unknownArray' },
])('sanitizeOperationParameterName($input) -> $expected', ({ input, expected }) => {
expect(sanitizeOperationParameterName(input)).toEqual(expected);
});
});

describe('sanitizeServiceName', () => {
it('should remove/replace illegal characters', () => {
expect(sanitizeServiceName('abc')).toEqual('abc');
expect(sanitizeServiceName('æbc')).toEqual('æbc');
expect(sanitizeServiceName('æb.c')).toEqual('æb-c');
expect(sanitizeServiceName('1æb.c')).toEqual('æb-c');
it.each([
{ input: 'abc', expected: 'abc' },
{ input: 'æbc', expected: 'æbc' },
{ input: 'æb.c', expected: 'æb-c' },
{ input: '1æb.c', expected: 'æb-c' },
])('sanitizeServiceName($input) -> $expected', ({ input, expected }) => {
expect(sanitizeServiceName(input)).toEqual(expected);
});
});

describe('sanitizeTypeName', () => {
it('should remove/replace illegal characters', () => {
expect(sanitizeTypeName('abc')).toEqual('abc');
expect(sanitizeTypeName('æbc')).toEqual('æbc');
expect(sanitizeTypeName('æb.c')).toEqual('æb_c');
expect(sanitizeTypeName('1æb.c')).toEqual('æb_c');
});
});

describe('sanitizeTypeName', () => {
it('should remove/replace illegal characters', () => {
expect(sanitizeTypeName('abc')).toEqual('abc');
expect(sanitizeTypeName('æbc')).toEqual('æbc');
expect(sanitizeTypeName('æb.c')).toEqual('æb_c');
expect(sanitizeTypeName('1æb.c')).toEqual('æb_c');
it.each([
{ input: 'abc', expected: 'abc' },
{ input: 'æbc', expected: 'æbc' },
{ input: 'æb.c', expected: 'æb_c' },
{ input: '1æb.c', expected: 'æb_c' },
])('sanitizeTypeName($input) -> $expected', ({ input, expected }) => {
expect(sanitizeTypeName(input)).toEqual(expected);
});
});
30 changes: 16 additions & 14 deletions src/openApi/common/parser/__tests__/stripNamespace.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,21 @@ import { describe, expect, it } from 'vitest';
import { stripNamespace } from '../stripNamespace';

describe('stripNamespace', () => {
it('should strip namespace', () => {
expect(stripNamespace('#/definitions/Item')).toEqual('Item');
expect(stripNamespace('#/parameters/Item')).toEqual('Item');
expect(stripNamespace('#/responses/Item')).toEqual('Item');
expect(stripNamespace('#/securityDefinitions/Item')).toEqual('Item');
expect(stripNamespace('#/components/schemas/Item')).toEqual('Item');
expect(stripNamespace('#/components/responses/Item')).toEqual('Item');
expect(stripNamespace('#/components/parameters/Item')).toEqual('Item');
expect(stripNamespace('#/components/examples/Item')).toEqual('Item');
expect(stripNamespace('#/components/requestBodies/Item')).toEqual('Item');
expect(stripNamespace('#/components/headers/Item')).toEqual('Item');
expect(stripNamespace('#/components/securitySchemes/Item')).toEqual('Item');
expect(stripNamespace('#/components/links/Item')).toEqual('Item');
expect(stripNamespace('#/components/callbacks/Item')).toEqual('Item');
it.each([
{ input: '#/definitions/Item', expected: 'Item' },
{ input: '#/parameters/Item', expected: 'Item' },
{ input: '#/responses/Item', expected: 'Item' },
{ input: '#/securityDefinitions/Item', expected: 'Item' },
{ input: '#/components/schemas/Item', expected: 'Item' },
{ input: '#/components/responses/Item', expected: 'Item' },
{ input: '#/components/parameters/Item', expected: 'Item' },
{ input: '#/components/examples/Item', expected: 'Item' },
{ input: '#/components/requestBodies/Item', expected: 'Item' },
{ input: '#/components/headers/Item', expected: 'Item' },
{ input: '#/components/securitySchemes/Item', expected: 'Item' },
{ input: '#/components/links/Item', expected: 'Item' },
{ input: '#/components/callbacks/Item', expected: 'Item' },
])('stripNamespace($input) -> $expected', ({ input, expected }) => {
expect(stripNamespace(input)).toEqual(expected);
});
});
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { Enum, WithEnumExtension } from '../types/client';
import { unique } from './unique';
import { unique } from '../../../utils/unique';
import type { Enum } from '../interfaces/client';
import type { WithEnumExtension } from '../interfaces/WithEnumExtension';

export const getEnums = (definition: WithEnumExtension, values?: ReadonlyArray<string | number>): Enum[] => {
if (!Array.isArray(values)) {
Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion src/openApi/common/parser/operation.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import camelCase from 'camelcase';

import type { OperationError, OperationResponse } from '../../../types/client';
import type { Config } from '../../../types/config';
import type { OperationError, OperationResponse } from '../interfaces/client';
import { reservedWords } from './reservedWords';
import { sanitizeOperationName, sanitizeOperationParameterName } from './sanitize';

Expand Down
1 change: 1 addition & 0 deletions src/openApi/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { OpenApi } from './common/interfaces/OpenApi';
import { parse as parseV2 } from './v2/index';
import { parse as parseV3 } from './v3/index';

export { Enum, Model, Operation, OperationParameter, Service } from './common/interfaces/client';
export { OpenApi } from './common/interfaces/OpenApi';

/**
Expand Down
2 changes: 1 addition & 1 deletion src/openApi/v2/interfaces/OpenApiItems.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { WithEnumExtension } from '../../../types/client';
import type { WithEnumExtension } from '../../common/interfaces/WithEnumExtension';

/**
* {@link} https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#items-object)
Expand Down
2 changes: 1 addition & 1 deletion src/openApi/v2/interfaces/OpenApiParameter.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { WithEnumExtension } from '../../../types/client';
import type { WithEnumExtension } from '../../common/interfaces/WithEnumExtension';
import type { WithNullableExtension } from './Extensions/WithNullableExtension';
import type { OpenApiItems } from './OpenApiItems';
import type { OpenApiReference } from './OpenApiReference';
Expand Down
2 changes: 1 addition & 1 deletion src/openApi/v2/interfaces/OpenApiSchema.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { WithEnumExtension } from '../../../types/client';
import type { Dictionary } from '../../common/interfaces/Dictionary';
import type { WithEnumExtension } from '../../common/interfaces/WithEnumExtension';
import type { WithNullableExtension } from './Extensions/WithNullableExtension';
import type { OpenApiExternalDocs } from './OpenApiExternalDocs';
import type { OpenApiReference } from './OpenApiReference';
Expand Down
6 changes: 3 additions & 3 deletions src/openApi/v2/parser/getModel.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { Model } from '../../../types/client';
import { getEnums } from '../../../utils/getEnums';
import { getPattern } from '../../../utils/getPattern';
import type { Model } from '../../common/interfaces/client';
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';
Expand Down
2 changes: 1 addition & 1 deletion src/openApi/v2/parser/getModelComposition.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Model, ModelComposition } from '../../../types/client';
import type { Model, ModelComposition } from '../../common/interfaces/client';
import type { OpenApi } from '../interfaces/OpenApi';
import type { OpenApiSchema } from '../interfaces/OpenApiSchema';
import type { getModel } from './getModel';
Expand Down
4 changes: 2 additions & 2 deletions src/openApi/v2/parser/getModelProperties.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { Model } from '../../../types/client';
import { escapeName } from '../../../utils/escapeName';
import { getPattern } from '../../../utils/getPattern';
import type { Model } from '../../common/interfaces/client';
import { getPattern } from '../../common/parser/getPattern';
import { getType } from '../../common/parser/type';
import type { OpenApi } from '../interfaces/OpenApi';
import type { OpenApiSchema } from '../interfaces/OpenApiSchema';
Expand Down
2 changes: 1 addition & 1 deletion src/openApi/v2/parser/getModels.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Model } from '../../../types/client';
import type { Model } from '../../common/interfaces/client';
import { reservedWords } from '../../common/parser/reservedWords';
import { getType } from '../../common/parser/type';
import type { OpenApi } from '../interfaces/OpenApi';
Expand Down
2 changes: 1 addition & 1 deletion src/openApi/v2/parser/getOperation.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Operation, OperationParameters } from '../../../types/client';
import type { Config } from '../../../types/config';
import type { Operation, OperationParameters } from '../../common/interfaces/client';
import { getOperationErrors, getOperationName, getOperationResponseHeader } from '../../common/parser/operation';
import { toSortedByRequired } from '../../common/parser/sort';
import type { OpenApi } from '../interfaces/OpenApi';
Expand Down
6 changes: 3 additions & 3 deletions src/openApi/v2/parser/getOperationParameter.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { OperationParameter } from '../../../types/client';
import { getEnums } from '../../../utils/getEnums';
import { getPattern } from '../../../utils/getPattern';
import type { OperationParameter } from '../../common/interfaces/client';
import { getEnums } from '../../common/parser/getEnums';
import { getPattern } from '../../common/parser/getPattern';
import { getRef } from '../../common/parser/getRef';
import { getOperationParameterName } from '../../common/parser/operation';
import { getType } from '../../common/parser/type';
Expand Down
2 changes: 1 addition & 1 deletion src/openApi/v2/parser/getOperationParameterDefault.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { OperationParameter } from '../../../types/client';
import type { OperationParameter } from '../../common/interfaces/client';
import type { OpenApiParameter } from '../interfaces/OpenApiParameter';

export const getOperationParameterDefault = (
Expand Down
2 changes: 1 addition & 1 deletion src/openApi/v2/parser/getOperationParameters.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { OperationParameters } from '../../../types/client';
import type { OperationParameters } from '../../common/interfaces/client';
import { getRef } from '../../common/parser/getRef';
import type { OpenApi } from '../interfaces/OpenApi';
import type { OpenApiParameter } from '../interfaces/OpenApiParameter';
Expand Down
4 changes: 2 additions & 2 deletions src/openApi/v2/parser/getOperationResponse.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { OperationResponse } from '../../../types/client';
import { getPattern } from '../../../utils/getPattern';
import type { OperationResponse } from '../../common/interfaces/client';
import { getPattern } from '../../common/parser/getPattern';
import { getRef } from '../../common/parser/getRef';
import { getType } from '../../common/parser/type';
import type { OpenApi } from '../interfaces/OpenApi';
Expand Down
2 changes: 1 addition & 1 deletion src/openApi/v2/parser/getOperationResponses.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { OperationResponse } from '../../../types/client';
import type { OperationResponse } from '../../common/interfaces/client';
import { getRef } from '../../common/parser/getRef';
import { getOperationResponseCode } from '../../common/parser/operation';
import type { OpenApi } from '../interfaces/OpenApi';
Expand Down
2 changes: 1 addition & 1 deletion src/openApi/v2/parser/getOperationResults.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Model, OperationResponse } from '../../../types/client';
import type { Model, OperationResponse } from '../../common/interfaces/client';

const areEqual = (a: Model, b: Model): boolean => {
const equal = a.type === b.type && a.base === b.base && a.template === b.template;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Model } from '../../../types/client';
import type { Model } from '../../common/interfaces/client';
import { getRef } from '../../common/parser/getRef';
import type { OpenApi } from '../interfaces/OpenApi';
import type { OpenApiSchema } from '../interfaces/OpenApiSchema';
Expand Down
2 changes: 1 addition & 1 deletion src/openApi/v2/parser/getServices.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { Service } from '../../../types/client';
import type { Config } from '../../../types/config';
import { unique } from '../../../utils/unique';
import type { Service } from '../../common/interfaces/client';
import type { OpenApi } from '../interfaces/OpenApi';
import { getOperation } from './getOperation';
import { getOperationParameters } from './getOperationParameters';
Expand Down
2 changes: 1 addition & 1 deletion src/openApi/v3/interfaces/OpenApiSchema.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { WithEnumExtension } from '../../../types/client';
import type { Dictionary } from '../../common/interfaces/Dictionary';
import type { WithEnumExtension } from '../../common/interfaces/WithEnumExtension';
import type { OpenApiDiscriminator } from './OpenApiDiscriminator';
import type { OpenApiExternalDocs } from './OpenApiExternalDocs';
import type { OpenApiReference } from './OpenApiReference';
Expand Down
Loading