-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathservice.js
132 lines (121 loc) · 3.38 KB
/
service.js
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
130
131
132
/// <reference path="./global.d.ts" />
// @ts-check
//
// The lines above enable type checking for this file. Various IDEs interpret
// the @ts-check and reference directives. Together, they give you helpful
// autocompletion when implementing this exercise. You don't need to understand
// them in order to use it.
//
// In your own projects, files, and code, you can play with @ts-check as well.
export class TranslationService {
/**
* Creates a new service
* @param {ExternalApi} api the original api
*/
constructor(api) {
this.api = api;
}
/**
* Attempts to retrieve the translation for the given text.
*
* - Returns whichever translation can be retrieved, regardless the quality
* - Forwards any error from the translation api
*
* @param {string} text
* @returns {Promise<string>}
*/
free(text) {
return this.api.fetch(text).then(response => response.translation);
}
/**
* Batch translates the given texts using the free service.
*
* - Resolves all the translations (in the same order), if they all succeed
* - Rejects with the first error that is encountered
* - Rejects with a BatchIsEmpty error if no texts are given
*
* @param {string[]} texts
* @returns {Promise<string[]>}
*/
batch(texts) {
if (texts.length === 0) return Promise.reject(new BatchIsEmpty());
return Promise.all(texts.map(text => this.free(text)));
}
/**
* Requests the service for some text to be translated.
*
* Note: the request service is flaky, and it may take up to three times for
* it to accept the request.
*
* @param {string} text
* @returns {Promise<void>}
*/
request(text) {
const api = this.api;
function requestAsPromise(txt) {
return new Promise((resolve, reject) => {
api.request(txt, err => (err ? reject(err) : resolve()));
});
}
return requestAsPromise(text)
.catch(() => requestAsPromise(text))
.catch(() => requestAsPromise(text));
}
/**
* Retrieves the translation for the given text
*
* - Rejects with an error if the quality can not be met
* - Requests a translation if the translation is not available, then retries
*
* @param {string} text
* @param {number} minimumQuality
* @returns {Promise<string>}
*/
premium(text, minimumQuality) {
// function premiumAsPromise(txt, quality) {
// return new Promise((resolve, reject) => {
// if (quality > minimumQuality) return resolve(txt);
// return reject();
// });
// }
return this.api
.fetch(text)
.catch(() => {
return this.request(text).then(() => this.api.fetch(text));
})
.then(response => {
if (response.quality > minimumQuality) return response.translation;
throw new QualityThresholdNotMet(text);
});
}
}
/**
* This error is used to indicate a translation was found, but its quality does
* not meet a certain threshold. Do not change the name of this error.
*/
export class QualityThresholdNotMet extends Error {
/**
* @param {string} text
*/
constructor(text) {
super(
`
The translation of ${text} does not meet the requested quality threshold.
`.trim()
);
this.text = text;
}
}
/**
* This error is used to indicate the batch service was called without any
* texts to translate (it was empty). Do not change the name of this error.
*/
export class BatchIsEmpty extends Error {
constructor() {
super(
`
Requested a batch translation, but there are no texts in the batch.
`.trim()
);
}
}