-
Notifications
You must be signed in to change notification settings - Fork 5
/
TyperighterAdapter.ts
129 lines (120 loc) · 3.56 KB
/
TyperighterAdapter.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
import throttle from "lodash/throttle";
import uniqBy from "lodash/uniqBy";
import uniq from "lodash/uniq";
import v4 from "uuid/v4";
import { IBlock, IMatcherResponse } from "../../interfaces/IMatch";
import { ITypeRighterResponse } from "./interfaces/ITyperighter";
import {
IMatcherAdapter,
TMatchesReceivedCallback,
TRequestErrorCallback,
TRequestCompleteCallback
} from "../../interfaces/IMatcherAdapter";
export const convertTyperighterResponse = (
requestId: string,
response: ITypeRighterResponse
): IMatcherResponse => ({
requestId,
categoryIds: response.categoryIds,
blocks: response.blocks,
matches: response.matches.map(match => ({
matchId: v4(),
from: match.fromPos,
to: match.toPos,
matchedText: match.matchedText,
message: match.shortMessage,
category: match.rule.category,
suggestions: match.suggestions,
replacement: match.rule.replacement,
markAsCorrect: match.markAsCorrect
}))
});
/**
* An adapter for the Typerighter service.
*/
class TyperighterAdapter implements IMatcherAdapter {
constructor(protected url: string, protected responseThrottleMs = 250) {}
protected responseBuffer: ITypeRighterResponse[] = [];
public fetchMatches = async (
requestId: string,
inputs: IBlock[],
categoryIds: string[],
onMatchesReceived: TMatchesReceivedCallback,
onRequestError: TRequestErrorCallback,
_: TRequestCompleteCallback
) => {
inputs.map(async input => {
const body = {
requestId,
blocks: [input],
categoryIds
};
try {
const response = await fetch(`${this.url}/check`, {
method: "POST",
credentials: 'include',
headers: new Headers({
"Content-Type": "application/json"
}),
body: JSON.stringify(body)
});
if (response.status !== 200) {
throw new Error(
`Error fetching matches. The server responded with status code ${response.status}: ${response.statusText}`
);
}
const responseData: ITypeRighterResponse = await response.json();
this.responseBuffer.push(responseData);
this.throttledHandleResponse(requestId, onMatchesReceived);
} catch (e) {
onRequestError({
requestId,
blockId: input.id,
message: e.message
});
}
});
};
public fetchCategories = async () => {
const response = await fetch(`${this.url}/categories`, {
credentials: 'include',
headers: new Headers({
"Content-Type": "application/json"
})
});
if (response.status !== 200) {
throw new Error(
`Error fetching categories. The server responded with status code ${response.status}: ${response.statusText}`
);
}
return await response.json();
};
protected flushResponseBuffer = (
requestId: string,
onMatchesReceived: TMatchesReceivedCallback
) => {
if (!this.responseBuffer.length) {
return;
}
const blocks = uniqBy(
this.responseBuffer.flatMap(_ => _.blocks),
"id"
);
const categoryIds = uniq(this.responseBuffer.flatMap(_ => _.categoryIds));
const matches = this.responseBuffer.flatMap(_ => _.matches);
const socketMessage = {
blocks,
categoryIds,
matches,
requestId
};
onMatchesReceived(convertTyperighterResponse(requestId, socketMessage));
// Clear the buffer
this.responseBuffer = [];
};
protected throttledHandleResponse = throttle(
this.flushResponseBuffer,
this.responseThrottleMs
);
}
export default TyperighterAdapter;