Skip to content

Commit 9278b66

Browse files
authoredSep 13, 2019
Use Option for all the negotiator parts (stoplightio#600)
* refactor: functional internal helpers * refactor: tmp * refactor: pipe again * refactor: final pipe * refactor: pipe * refactor: explicit imports * inference for the win * refactor: use regex accordingly * refactor: restore code * refactor: look for a generic response only if required
1 parent 98c9ef6 commit 9278b66

File tree

3 files changed

+226
-180
lines changed

3 files changed

+226
-180
lines changed
 

‎packages/http/src/mocker/negotiator/InternalHelpers.ts

+44-19
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import { IHttpContent, IHttpOperationResponse, IMediaTypeContent } from '@stoplight/types';
22
// @ts-ignore
33
import * as accepts from 'accepts';
4+
import { filter, findFirst, head, sort } from 'fp-ts/lib/Array';
5+
import { alt, map, Option } from 'fp-ts/lib/Option';
6+
import { ord, ordNumber } from 'fp-ts/lib/Ord';
7+
import { pipe } from 'fp-ts/lib/pipeable';
48
import { ContentExample, NonEmptyArray, PickRequired } from '../../';
59

610
export type IWithExampleMediaContent = IMediaTypeContent & { examples: NonEmptyArray<ContentExample> };
@@ -20,48 +24,69 @@ export function hasContents(v: IHttpOperationResponse): v is PickRequired<IHttpO
2024
export function findBestHttpContentByMediaType(
2125
response: PickRequired<IHttpOperationResponse, 'contents'>,
2226
mediaType: string[],
23-
): IMediaTypeContent | undefined {
27+
): Option<IMediaTypeContent> {
2428
const bestType = accepts({
2529
headers: {
2630
accept: mediaType.join(','),
2731
},
2832
}).type(response.contents.map(c => c.mediaType));
2933

30-
return response.contents.find(content => content.mediaType === bestType);
34+
return pipe(
35+
response.contents,
36+
findFirst(content => content.mediaType === bestType),
37+
);
3138
}
3239

3340
export function findDefaultContentType(
3441
response: PickRequired<IHttpOperationResponse, 'contents'>,
35-
): IMediaTypeContent | undefined {
36-
return response.contents.find(content => content.mediaType === '*/*');
42+
): Option<IMediaTypeContent> {
43+
return pipe(
44+
response.contents,
45+
findFirst(content => content.mediaType === '*/*'),
46+
);
3747
}
3848

39-
export function findLowest2xx(httpResponses: IHttpOperationResponse[]): IHttpOperationResponse | undefined {
40-
const generic2xxResponse =
41-
findResponseByStatusCode(httpResponses, '2XX') || createResponseFromDefault(httpResponses, '200');
42-
const sorted2xxResponses = httpResponses
43-
.filter(response => response.code.match(/2\d\d/))
44-
.sort((a: IHttpOperationResponse, b: IHttpOperationResponse) => Number(a.code) - Number(b.code));
49+
const byResponseCode = ord.contramap<number, IHttpOperationResponse>(ordNumber, response => parseInt(response.code));
4550

46-
return sorted2xxResponses[0] || generic2xxResponse;
51+
export function findLowest2xx(httpResponses: IHttpOperationResponse[]): Option<IHttpOperationResponse> {
52+
const generic2xxResponse = () =>
53+
pipe(
54+
findResponseByStatusCode(httpResponses, '2XX'),
55+
alt(() => createResponseFromDefault(httpResponses, '200')),
56+
);
57+
58+
const first2xxResponse = pipe(
59+
httpResponses,
60+
filter(response => /2\d\d/.test(response.code)),
61+
sort(byResponseCode),
62+
head,
63+
);
64+
65+
return pipe(
66+
first2xxResponse,
67+
alt(generic2xxResponse),
68+
);
4769
}
4870

4971
export function findResponseByStatusCode(
5072
responses: IHttpOperationResponse[],
5173
statusCode: string,
52-
): IHttpOperationResponse | undefined {
53-
return responses.find(response => response.code.toLowerCase() === statusCode.toLowerCase());
74+
): Option<IHttpOperationResponse> {
75+
return pipe(
76+
responses,
77+
findFirst(response => response.code.toLowerCase() === statusCode.toLowerCase()),
78+
);
5479
}
5580

5681
export function createResponseFromDefault(
5782
responses: IHttpOperationResponse[],
5883
statusCode: string,
59-
): IHttpOperationResponse | undefined {
60-
const defaultResponse = responses.find(response => response.code === 'default');
61-
if (defaultResponse) {
62-
return Object.assign({}, defaultResponse, { code: statusCode });
63-
}
64-
return undefined;
84+
): Option<IHttpOperationResponse> {
85+
return pipe(
86+
responses,
87+
findFirst(response => response.code === 'default'),
88+
map(response => Object.assign({}, response, { code: statusCode })),
89+
);
6590
}
6691

6792
export function contentHasExamples(content: IMediaTypeContent): content is IWithExampleMediaContent {

0 commit comments

Comments
 (0)