Skip to content

Commit 0c74423

Browse files
committed
Merge remote-tracking branch 'origin/master' into docs/readme
2 parents aff35d2 + b4bc263 commit 0c74423

File tree

11 files changed

+499
-143
lines changed

11 files changed

+499
-143
lines changed

src/language/typescript/3.0/serializers/__tests__/operation-object.spec.ts

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { pipe } from 'fp-ts/lib/pipeable';
77
import { either, option } from 'fp-ts';
88
import { OperationObjectCodec } from '../../../../../schema/3.0/operation-object';
99
import { sequenceTEither } from '@devexperts/utils/dist/adt/either.utils';
10+
import { normalizeCodeSnippet } from '../../../../../../test/utils';
1011

1112
describe('OperationObject', () => {
1213
describe('getParameters', () => {
@@ -51,20 +52,23 @@ describe('OperationObject', () => {
5152
result,
5253
option.fromEither,
5354
option.chain(result => result.serializedQueryString),
54-
option.fold(constant(''), fragment => fragment.value.replace(/\s+/g, ' ')),
55+
option.fold(constant(''), fragment => normalizeCodeSnippet(fragment.value)),
5556
);
5657

5758
expect(generated).toEqual(
58-
`compact([pipe(
59-
optionFromNullable(number).encode(parameters.query['offset']),
60-
option.fromNullable,
61-
option.chain(value => fromEither(serializePrimitiveParameter('form', 'offset', value))),
62-
),pipe(
63-
number.encode(parameters.query['limit']),
64-
value => fromEither(serializePrimitiveParameter('form', 'limit', value)),
65-
)]).join('&')`
66-
.trim()
67-
.replace(/\s+/g, ' '),
59+
normalizeCodeSnippet(`
60+
compact([
61+
pipe(
62+
optionFromNullable(number).encode(parameters.query['offset']),
63+
option.fromNullable,
64+
option.chain(value => fromEither(serializePrimitiveParameter('form', 'offset', value))),
65+
),
66+
pipe(
67+
number.encode(parameters.query['limit']),
68+
value => fromEither(serializePrimitiveParameter('form', 'limit', value)),
69+
)
70+
]).join('&')
71+
`),
6872
);
6973
});
7074
});
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
import { constant } from 'fp-ts/lib/function';
2+
import { fromString } from '../../../../../utils/ref';
3+
import { pipe } from 'fp-ts/lib/pipeable';
4+
import { either, record } from 'fp-ts';
5+
import { sequenceTEither } from '@devexperts/utils/dist/adt/either.utils';
6+
import { ChannelItemObjectCodec } from '../../../../../schema/asyncapi-2.0.0/channel-item-object';
7+
import { serializeChannelItemObject as createSerializeChannelItemObject } from '../channel-item-object';
8+
import { normalizeType } from '../../../../../../test/utils';
9+
import { reportIfFailed } from '../../../../../utils/io-ts';
10+
import { flow } from 'fp-ts/lib/function';
11+
12+
const refs = {
13+
'#/components/schemas/ChatCategory': {
14+
schema: {
15+
type: 'string',
16+
},
17+
},
18+
};
19+
20+
describe('ChannelItemObject', () => {
21+
describe('serializeChannelItemObject', () => {
22+
const serializeChannelItemObject = createSerializeChannelItemObject({
23+
resolveRef: (ref, dec) =>
24+
pipe(
25+
record.lookup(ref, refs),
26+
either.fromOption(() => new Error('Refs not supported')),
27+
either.chain(flow(dec.decode, reportIfFailed)),
28+
),
29+
});
30+
31+
it('should correctly handle channel path parameters without other parameters', () => {
32+
const operation = pipe(
33+
ChannelItemObjectCodec.decode({
34+
description: 'Sample channel',
35+
parameters: {
36+
userId: {
37+
schema: { type: 'number' },
38+
},
39+
topic: {
40+
schema: { type: 'string' },
41+
},
42+
},
43+
publish: {
44+
message: {
45+
payload: {
46+
type: 'object',
47+
properties: {
48+
text: { type: 'string' },
49+
},
50+
},
51+
},
52+
},
53+
}),
54+
either.mapLeft(constant(new Error())),
55+
);
56+
57+
const result = pipe(
58+
sequenceTEither(operation, fromString('#/whatever')),
59+
either.chain(([op, ref]) => serializeChannelItemObject(ref, '/message/{userId}/{topic}', op, 'HKT')),
60+
either.map(result =>
61+
normalizeType({
62+
...result,
63+
io: `const channels = {${result.io}}`,
64+
type: `type Channels = {${result.type}}`,
65+
}),
66+
),
67+
);
68+
69+
expect(result).toEqual(
70+
either.right(
71+
normalizeType({
72+
type: `
73+
type Channels = {
74+
['/message/{userId}/{topic}']:
75+
(parameters: { topic: string; userId: number }) =>
76+
{ send: (payload: { text: Option<string> }) => void }
77+
}
78+
`,
79+
io: `
80+
const channels = {['/message/{userId}/{topic}']: (parameters) => {
81+
const channel = e.webSocketClient.channel({
82+
channel: \`/message/\${encodeURIComponent(number.encode(parameters.userId).toString())}/\${encodeURIComponent(string.encode(parameters.topic).toString())}\`,
83+
method: 'GET',
84+
})
85+
86+
return {
87+
send: payload => {
88+
channel.send(type({ text: optionFromNullable(string) }).encode(payload));
89+
}
90+
};
91+
}}`,
92+
dependencies: [
93+
{ name: 'string', path: 'io-ts' },
94+
{ name: 'Option', path: 'fp-ts/lib/Option' },
95+
{ name: 'optionFromNullable', path: 'io-ts-types/lib/optionFromNullable' },
96+
{ name: 'type', path: 'io-ts' },
97+
{ name: 'number', path: 'io-ts' },
98+
{ name: 'WebSocketClient', path: './/client/client' },
99+
{ name: 'partial', path: 'io-ts' },
100+
],
101+
refs: [],
102+
}),
103+
),
104+
);
105+
});
106+
107+
it('should correctly handle channel path parameters with other parameters', () => {
108+
const operation = pipe(
109+
ChannelItemObjectCodec.decode({
110+
description: 'Sample channel',
111+
parameters: {
112+
userId: {
113+
schema: { type: 'number' },
114+
},
115+
category: {
116+
$ref: '#/components/schemas/ChatCategory',
117+
},
118+
},
119+
bindings: {
120+
ws: {
121+
query: {
122+
type: 'object',
123+
properties: {
124+
search: { type: 'string' },
125+
},
126+
},
127+
},
128+
},
129+
publish: {
130+
message: {
131+
payload: {
132+
type: 'object',
133+
properties: {
134+
text: { type: 'string' },
135+
},
136+
},
137+
},
138+
},
139+
}),
140+
either.mapLeft(constant(new Error())),
141+
);
142+
143+
const result = pipe(
144+
sequenceTEither(operation, fromString('#/whatever')),
145+
either.chain(([op, ref]) => serializeChannelItemObject(ref, '/message/{userId}/{category}', op, 'HKT')),
146+
either.map(result =>
147+
normalizeType({
148+
...result,
149+
io: `const channels = {${result.io}}`,
150+
type: `type Channels = {${result.type}}`,
151+
}),
152+
),
153+
);
154+
155+
expect(result).toEqual(
156+
either.right(
157+
normalizeType({
158+
type: `
159+
type Channels = {
160+
['/message/{userId}/{category}']:
161+
(parameters: {query?: {search: Option<string>}; category: string; userId: number }) =>
162+
{ send: (payload: { text: Option<string> }) => void }
163+
}
164+
`,
165+
io: `
166+
const channels = {
167+
['/message/{userId}/{category}']: (parameters) => {
168+
const encoded = partial({
169+
query: type({ search: optionFromNullable(string) })
170+
}).encode(parameters);
171+
const channel = e.webSocketClient.channel({
172+
channel: \`/message/\${
173+
encodeURIComponent(number.encode(parameters.userId).toString())
174+
}/\${
175+
encodeURIComponent(string.encode(parameters.category).toString())
176+
}\`,
177+
method: 'GET',
178+
...encoded
179+
});
180+
181+
return {
182+
send: payload => {
183+
channel.send(type({ text: optionFromNullable(string) }).encode(payload));
184+
}
185+
};
186+
}
187+
}
188+
`,
189+
dependencies: [
190+
{ name: 'string', path: 'io-ts' },
191+
{ name: 'Option', path: 'fp-ts/lib/Option' },
192+
{ name: 'optionFromNullable', path: 'io-ts-types/lib/optionFromNullable' },
193+
{ name: 'type', path: 'io-ts' },
194+
{ name: 'number', path: 'io-ts' },
195+
{ name: 'WebSocketClient', path: './/client/client' },
196+
{ name: 'partial', path: 'io-ts' },
197+
],
198+
refs: [],
199+
}),
200+
),
201+
);
202+
});
203+
});
204+
});

src/language/typescript/asyncapi-2.0.0/serializers/asyncapi-object.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@ import { utilsFile } from '../../common/bundled/utils';
1313

1414
export const serializeAsyncAPIObject = combineReader(
1515
serializeComponentsObject,
16-
serializeComponentsObject => (name: string, asyncAPIObject: AsyncAPIObject): Either<Error, FSEntity> => {
16+
serializeChannelsObject,
17+
(serializeComponentsObject, serializeChannelsObject) => (
18+
name: string,
19+
asyncAPIObject: AsyncAPIObject,
20+
): Either<Error, FSEntity> => {
1721
const components = pipe(
1822
asyncAPIObject.components,
1923
option.map(components =>

0 commit comments

Comments
 (0)