Skip to content

Commit

Permalink
refactor: simplify resolveRef
Browse files Browse the repository at this point in the history
BREAKING CHANGE: language is now a Reader of ResolveRefContext
BREAKING CHANGE: resolveRef now requires decoder as a second argument
  • Loading branch information
raveclassic committed Dec 9, 2019
1 parent 3cec483 commit 763cc68
Show file tree
Hide file tree
Showing 9 changed files with 117 additions and 140 deletions.
20 changes: 14 additions & 6 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,22 @@ import * as path from 'path';
import * as $RefParser from 'json-schema-ref-parser';
import { pipe } from 'fp-ts/lib/pipeable';
import { array, either, taskEither } from 'fp-ts';
import { Either, isLeft } from 'fp-ts/lib/Either';
import { Either, isLeft, toError } from 'fp-ts/lib/Either';
import { identity } from 'fp-ts/lib/function';
import { reportIfFailed } from './utils/io-ts';
import { TaskEither } from 'fp-ts/lib/TaskEither';
import { sketchParser121 } from './parsers/sketch-121';
import { ResolveRef, ResolveRefContext } from './utils/ref';
import { Reader } from 'fp-ts/lib/Reader';

export interface Language<A> {
(documents: Record<string, A>): Either<unknown, FSEntity>;
}
export interface GenerateOptions<A> {
readonly out: string;
readonly spec: string;
readonly decoder: Decoder<unknown, A>;
readonly language: (
documents: Record<string, A>,
resolveRef: (ref: string) => Either<unknown, unknown>,
) => Either<unknown, FSEntity>;
readonly language: Reader<ResolveRefContext, Language<A>>;
}

const log = (...args: unknown[]) => console.log('[SWAGGER-CODEGEN-TS]:', ...args);
Expand Down Expand Up @@ -64,7 +66,13 @@ export const generate = <A>(options: GenerateOptions<A>): TaskEither<unknown, vo

log('Writing to', out);

await write(out, getUnsafe(options.language(specs, ref => either.tryCatch(() => $refs.get(ref), identity))));
const resolveRef: ResolveRef = ($ref, decoder) =>
pipe(
either.tryCatch(() => $refs.get($ref), toError),
either.chain(resolved => reportIfFailed(decoder.decode(resolved))),
);

await write(out, getUnsafe(options.language({ resolveRef })(specs)));

log('Done');
}, identity);
Expand Down
10 changes: 4 additions & 6 deletions src/language/typescript/2.0/serializers/operation-object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ import { fromSerializedType } from '../../common/data/serialized-parameter';
import { getSerializedKindDependency, serializedDependency } from '../../common/data/serialized-dependency';
import { concatIf } from '../../../../utils/array';
import { when } from '../../../../utils/string';
import { Context, getJSDoc, getKindValue, getURL, HTTPMethod } from '../../common/utils';
import { getJSDoc, getKindValue, getURL, HTTPMethod } from '../../common/utils';
import { Either, isLeft, left, right } from 'fp-ts/lib/Either';
import { array, either, nonEmptyArray, option } from 'fp-ts';
import { combineEither } from '@devexperts/utils/dist/adt/either.utils';
import { fromString, getRelativePath, Ref } from '../../../../utils/ref';
import { ResolveRefContext, fromString, getRelativePath, Ref } from '../../../../utils/ref';
import { clientRef } from '../../common/bundled/client';
import {
ArrayParameterObjectCollectionFormat,
Expand Down Expand Up @@ -71,7 +71,7 @@ const contains = array.elem(
);

const getParameters = combineReader(
ask<Context>(),
ask<ResolveRefContext>(),
e => (from: Ref, operation: OperationObject, pathItem: PathItemObject): Either<Error, Parameters> => {
const processedParameters: ParameterObject[] = [];
const pathParameters: PathParameterObject[] = [];
Expand All @@ -93,9 +93,7 @@ const getParameters = combineReader(
for (const parameter of parameters) {
const resolved = ReferenceObjectCodec.is(parameter)
? pipe(
parameter,
e.resolveRef,
ParameterObjectCodec.decode,
e.resolveRef(parameter.$ref, ParameterObjectCodec),
either.mapLeft(() => new Error(`Unable to resolve parameter with $ref "${parameter.$ref}"`)),
)
: right(parameter);
Expand Down
122 changes: 62 additions & 60 deletions src/language/typescript/2.0/serializers/path-item-object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,65 +11,67 @@ import { decapitalize } from '@devexperts/utils/dist/string';
import { Either } from 'fp-ts/lib/Either';
import { combineEither, sequenceEither } from '@devexperts/utils/dist/adt/either.utils';
import { either, nonEmptyArray, option, record } from 'fp-ts';
import { getRelativePath, Ref } from '../../../../utils/ref';
import { ResolveRefContext, getRelativePath, Ref } from '../../../../utils/ref';
import { clientRef } from '../../common/bundled/client';
import { OperationObject } from '../../../../schema/2.0/operation-object';
import { tuple } from 'fp-ts/lib/function';
import { uniqString } from '../../../../utils/array';
import { combineReader } from '@devexperts/utils/dist/adt/reader.utils';
import { ask } from 'fp-ts/lib/Reader';
import { Context } from '../../common/utils';

const serializePath = combineReader(ask<Context>(), serializeOperationObject, (e, serializeOperationObject) => {
const run = (from: Ref, url: string, kind: Kind, item: PathItemObject): Either<Error, SerializedType> => {
if (isSome(item.$ref)) {
const $ref = item.$ref.value;
return pipe(
e.resolveRef({ $ref }),
PathItemObjectCodec.decode,
either.mapLeft(() => new Error(`Unable to resolve PathItem $ref: "${$ref}"`)),
either.chain(resolved => run(from, url, kind, resolved)),
);
} else {
const get = pipe(
item.get,
map(operation => serializeOperationObject(from, url, 'GET', kind, operation, item)),
);
const put = pipe(
item.put,
map(operation => serializeOperationObject(from, url, 'PUT', kind, operation, item)),
);
const post = pipe(
item.post,
map(operation => serializeOperationObject(from, url, 'POST', kind, operation, item)),
);
const remove = pipe(
item.delete,
map(operation => serializeOperationObject(from, url, 'DELETE', kind, operation, item)),
);
const options = pipe(
item.options,
map(operation => serializeOperationObject(from, url, 'OPTIONS', kind, operation, item)),
);
const head = pipe(
item.head,
map(operation => serializeOperationObject(from, url, 'HEAD', kind, operation, item)),
);
const patch = pipe(
item.patch,
map(operation => serializeOperationObject(from, url, 'PATCH', kind, operation, item)),
);
const operations = [get, put, post, remove, options, head, patch];
return pipe(
operations,
array.compact,
sequenceEither,
either.map(foldSerializedTypes),
);
}
};
return run;
});
const serializePath = combineReader(
ask<ResolveRefContext>(),
serializeOperationObject,
(e, serializeOperationObject) => {
const run = (from: Ref, url: string, kind: Kind, item: PathItemObject): Either<Error, SerializedType> => {
if (isSome(item.$ref)) {
const $ref = item.$ref.value;
return pipe(
e.resolveRef($ref, PathItemObjectCodec),
either.mapLeft(() => new Error(`Unable to resolve PathItem $ref: "${$ref}"`)),
either.chain(resolved => run(from, url, kind, resolved)),
);
} else {
const get = pipe(
item.get,
map(operation => serializeOperationObject(from, url, 'GET', kind, operation, item)),
);
const put = pipe(
item.put,
map(operation => serializeOperationObject(from, url, 'PUT', kind, operation, item)),
);
const post = pipe(
item.post,
map(operation => serializeOperationObject(from, url, 'POST', kind, operation, item)),
);
const remove = pipe(
item.delete,
map(operation => serializeOperationObject(from, url, 'DELETE', kind, operation, item)),
);
const options = pipe(
item.options,
map(operation => serializeOperationObject(from, url, 'OPTIONS', kind, operation, item)),
);
const head = pipe(
item.head,
map(operation => serializeOperationObject(from, url, 'HEAD', kind, operation, item)),
);
const patch = pipe(
item.patch,
map(operation => serializeOperationObject(from, url, 'PATCH', kind, operation, item)),
);
const operations = [get, put, post, remove, options, head, patch];
return pipe(
operations,
array.compact,
sequenceEither,
either.map(foldSerializedTypes),
);
}
};
return run;
},
);

export const serializePathGroup = combineReader(
serializePath,
Expand Down Expand Up @@ -113,21 +115,21 @@ export const serializePathGroup = combineReader(
]);
return file(
`${from.name}.ts`,
`
${dependencies}
`
${dependencies}
export interface ${from.name}<F> {
${serializedHKT.type}
}
export interface ${from.name}1<F extends URIS> {
${serializedKind.type}
${serializedKind.type}
}
export interface ${from.name}2<F extends URIS2> {
${serializedKind2.type}
${serializedKind2.type}
}
export function ${decapitalize(from.name)}<F extends URIS2>(e: { httpClient: HTTPClient2<F> }): ${from.name}2<F>
export function ${decapitalize(from.name)}<F extends URIS>(e: { httpClient: HTTPClient1<F> }): ${from.name}1<F>
export function ${decapitalize(from.name)}<F>(e: { httpClient: HTTPClient<F> }): ${from.name}<F>;
Expand Down
36 changes: 8 additions & 28 deletions src/language/typescript/3.0/serializers/components-object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const serializeSchema = (from: Ref, schema: SchemaObject): Either<Error, File> =
`${from.name}.ts`,
`
${dependencies}
export type ${typeName} = ${serialized.type};
export const ${ioName} = ${serialized.io};
`,
Expand All @@ -51,12 +51,7 @@ const serializeSchemas = combineReader(
schemas,
record.collect((name, schema) => {
const resolved = ReferenceObjectCodec.is(schema)
? pipe(
schema,
e.resolveRef,
SchemaObjectCodec.decode,
reportIfFailed,
)
? e.resolveRef(schema.$ref, SchemaObjectCodec)
: right(schema);
const ref = pipe(
from,
Expand All @@ -82,7 +77,7 @@ const serializeParameter = (from: Ref, parameterObject: ParameterObject): Either
`${from.name}.ts`,
`
${dependencies}
export type ${getTypeName(from.name)} = ${serialized.type};
export const ${getIOName(from.name)} = ${serialized.io};
`,
Expand All @@ -97,12 +92,7 @@ const serializeParameters = combineReader(
parameters,
record.collect((name, parameter) => {
const resolved = ReferenceObjectCodec.is(parameter)
? pipe(
parameter,
e.resolveRef,
ParameterObjectCodec.decode,
reportIfFailed,
)
? e.resolveRef(parameter.$ref, ParameterObjectCodec)
: right(parameter);
const ref = pipe(
from,
Expand All @@ -129,7 +119,7 @@ const serializeResponse = (from: Ref, responseObject: ResponseObject): Either<Er
`${from.name}.ts`,
`
${dependencies}
export type ${getTypeName(from.name)} = ${serialized.type};
export const ${getIOName(from.name)} = ${serialized.io};
`,
Expand All @@ -144,12 +134,7 @@ const serializeResponses = combineReader(
responses,
record.collect((name, response) => {
const resolved = ReferenceObjectCodec.is(response)
? pipe(
response,
e.resolveRef,
ResponseObjectCodec.decode,
reportIfFailed,
)
? e.resolveRef(response.$ref, ResponseObjectCodec)
: right(response);
const ref = pipe(
from,
Expand All @@ -173,7 +158,7 @@ const serializeRequestBody = (from: Ref, requestBody: RequestBodyObject): Either
`${from.name}.ts`,
`
${serializeDependencies(serialized.dependencies)}
export type ${getTypeName(from.name)} = ${serialized.type};
export const ${getIOName(from.name)} = ${serialized.io};
`,
Expand All @@ -188,12 +173,7 @@ const serializeRequestBodies = combineReader(
requestBodies,
record.collect((name, requestBody) => {
const resolved = ReferenceObjectCodec.is(requestBody)
? pipe(
requestBody,
e.resolveRef,
RequestBodyObjectCodec.decode,
reportIfFailed,
)
? e.resolveRef(requestBody.$ref, RequestBodyObjectCodec)
: right(requestBody);
const ref = pipe(
from,
Expand Down
14 changes: 7 additions & 7 deletions src/language/typescript/3.0/serializers/operation-object.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Context, getJSDoc, getKindValue, getURL, HTTPMethod } from '../../common/utils';
import { getJSDoc, getKindValue, getURL, HTTPMethod } from '../../common/utils';
import {
getSerializedPropertyType,
getSerializedObjectType,
Expand Down Expand Up @@ -30,7 +30,7 @@ import {
import { concatIf } from '../../../../utils/array';
import { when } from '../../../../utils/string';
import { serializeRequestBodyObject } from './request-body-object';
import { fromString, getRelativePath, Ref } from '../../../../utils/ref';
import { ResolveRefContext, fromString, getRelativePath, Ref } from '../../../../utils/ref';
import { OperationObject } from '../../../../schema/3.0/operation-object';
import { ParameterObject, ParameterObjectCodec } from '../../../../schema/3.0/parameter-object';
import { RequestBodyObjectCodec } from '../../../../schema/3.0/request-body-object';
Expand Down Expand Up @@ -72,7 +72,7 @@ const eqParameterByNameAndIn: Eq<ParameterObject> = getStructEq({
const contains = array.elem(eqParameterByNameAndIn);

const getParameters = combineReader(
ask<Context>(),
ask<ResolveRefContext>(),
e => (from: Ref, operation: OperationObject, pathItem: PathItemObject): Either<Error, Parameters> => {
const processedParameters: ParameterObject[] = [];
const pathParameters: ParameterObject[] = [];
Expand All @@ -87,7 +87,7 @@ const getParameters = combineReader(

for (const parameter of parameters) {
const resolved = ReferenceObjectCodec.is(parameter)
? reportIfFailed(ParameterObjectCodec.decode(e.resolveRef(parameter)))
? e.resolveRef(parameter.$ref, ParameterObjectCodec)
: right(parameter);

if (isLeft(resolved)) {
Expand Down Expand Up @@ -134,7 +134,7 @@ const getParameters = combineReader(
schema,
either.chain(schema =>
ReferenceObjectCodec.is(schema)
? reportIfFailed(SchemaObjectCodec.decode(e.resolveRef(schema)))
? e.resolveRef(schema.$ref, SchemaObjectCodec)
: right(schema),
),
);
Expand Down Expand Up @@ -172,7 +172,7 @@ const getParameters = combineReader(
if (isLeft(reference)) {
return left(new Error(`Invalid RequestBodyObject.$ref "${requestBody.$ref}"`));
}
const resolved = option.fromEither(RequestBodyObjectCodec.decode(e.resolveRef(requestBody)));
const resolved = option.fromEither(e.resolveRef(requestBody.$ref, RequestBodyObjectCodec));

if (!isSome(resolved)) {
return left(new Error(`Unable to resolve RequestBodyObject with ref ${requestBody.$ref}`));
Expand Down Expand Up @@ -308,7 +308,7 @@ export const serializeOperationObject = combineReader(
${operationName}: (${argsIO}) => {
${bodyIO}
${queryIO}
return e.httpClient.chain(
e.httpClient.request({
url: ${getURL(pattern, parameters.serializedPathParameters)},
Expand Down
Loading

0 comments on commit 763cc68

Please sign in to comment.