@reality.eth/reality-eth-lib 3.0.1 → 3.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -171,7 +171,7 @@ exports.secondsTodHms = function(sec) {
171
171
  return dDisplay + hDisplay + mDisplay + sDisplay;
172
172
  }
173
173
 
174
- exports.parseQuestionJSON = function(data) {
174
+ exports.parseQuestionJSON = function(data, errors_to_title) {
175
175
 
176
176
  var question_json;
177
177
  try {
@@ -179,23 +179,43 @@ exports.parseQuestionJSON = function(data) {
179
179
  } catch(e) {
180
180
  question_json = {
181
181
  'title': '[Badly formatted question]: ' + data,
182
- 'type': 'broken-question'
182
+ 'type': 'broken-question',
183
+ 'errors': {"json_parse_failed": true}
183
184
  };
184
185
  }
185
186
  if (question_json['outcomes'] && question_json['outcomes'].length > QUESTION_MAX_OUTCOMES) {
186
- throw Error("Too many outcomes");
187
+ question_json['errors'] = {'too_many_outcomes': true}
188
+ }
189
+ if ('type' in question_json && question_json['type'] == 'datetime' && 'precision' in question_json) {
190
+ if (!(['Y', 'm', 'd', 'H', 'i', 's'].includes(question_json['precision']))) {
191
+ question_json['errors'] = {'invalid_precision': true};
192
+ }
193
+ }
194
+ // If errors_to_title is specified, we add any error message to the title to make sure we don't lose it
195
+ if (errors_to_title) {
196
+ if ('errors' in question_json) {
197
+ const prependers = {
198
+ 'invalid_precision': 'Invalid date format',
199
+ 'too_many_outcomes': 'Too many outcomes'
200
+ }
201
+ for (var e in question_json['errors']) {
202
+ if (e in prependers) {
203
+ question_json['title'] = '['+prependers[e]+'] ' + question_json['title'];
204
+ }
205
+ }
206
+ }
187
207
  }
188
208
  return question_json;
189
209
 
190
210
  }
191
211
 
192
- exports.populatedJSONForTemplate = function(template, question) {
212
+ exports.populatedJSONForTemplate = function(template, question, errors_to_title) {
193
213
  var qbits = question.split(module.exports.delimiter());
194
214
  //console.log('pp', template);
195
215
  //console.log('qbits', qbits);
196
216
  var interpolated = vsprintf(template, qbits);
197
217
  //console.log('resulting template', interpolated);
198
- return module.exports.parseQuestionJSON(interpolated);
218
+ return module.exports.parseQuestionJSON(interpolated, errors_to_title);
199
219
  }
200
220
 
201
221
  exports.encodeText = function(qtype, txt, outcomes, category, lang) {
@@ -292,18 +312,72 @@ exports.getAnswerString = function(question_json, answer) {
292
312
  }
293
313
  break;
294
314
  case 'datetime':
315
+ let precision = 'd';
316
+ if ('precision' in question_json && ['Y', 'm', 'd', 'H', 'i', 's'].includes(question_json['precision'])) {
317
+ precision = question_json['precision'];
318
+ }
295
319
  let ts = parseInt(module.exports.bytes32ToString(answer, question_json));
296
320
  let dateObj = new Date(ts * 1000);
297
- let year = dateObj.getUTCFullYear();
298
- let month = dateObj.getUTCMonth() + 1;
299
- let date = dateObj.getUTCDate();
300
- label = year + '/' + month + '/' + date;
321
+
322
+ const year = dateObj.getUTCFullYear();
323
+ const month = dateObj.getUTCMonth() + 1;
324
+ const date = dateObj.getUTCDate();
325
+ const hour = dateObj.getUTCHours();
326
+ const min = dateObj.getUTCMinutes();
327
+ const sec = dateObj.getUTCSeconds();
328
+
329
+ // We need whatever the precision states, plus anything above
330
+ const needy = true;
331
+ const needm = (precision != 'Y');
332
+ const needd = needm && (precision != 'm');
333
+ const needH = needd && (precision != 'd');
334
+ const needi = needH && (precision != 'H');
335
+ const needs = needi && (precision != 'i');
336
+
337
+ // If anything is set then we've got it.
338
+ // We also consider that anything required by the precision is there, but set to 0
339
+ const hass = needs || sec > 0;
340
+ const hasi = needi || hass || min > 0;
341
+ const hasH = needH || hasi || hour > 0;
342
+ const hasd = needd || hasH || date > 1;
343
+ const hasm = needm || hasd || month > 1;
344
+ const hasy = true;
345
+
346
+ // We'll show an invalid warning if we've got a more precise date than the precision demands
347
+ let invalid = false;
348
+ if (!needm && hasm) invalid = true;
349
+ if (!needd && hasd) invalid = true;
350
+ if (!needH && hasH) invalid = true;
351
+ if (!needi && hasi) invalid = true;
352
+ if (!needs && hass) invalid = true;
353
+
354
+ if (invalid) {
355
+ label = '[Invalid datetime]: ';
356
+ }
301
357
 
302
358
  function pad2(n) { return ("0" + n).slice(-2); }
303
- time_label = pad2(dateObj.getUTCHours()) + ':' + pad2(dateObj.getUTCMinutes()) + ':' + pad2(dateObj.getUTCSeconds());
304
- if (time_label != '00:00:00') {
305
- label = label + ' ' + time_label;
359
+
360
+ if (hasy) {
361
+ label += year;
362
+ }
363
+ if (hasm) {
364
+ label += '-'+pad2(month);
365
+ }
366
+ if (hasd) {
367
+ label += '-'+pad2(date);
368
+ }
369
+ if (hasH) {
370
+ label += ' '+pad2(hour);
371
+ }
372
+ if (hasi) {
373
+ label += ':'+pad2(min);
374
+ } else if (hasH) {
375
+ // "2021-12-23 11" without the minutes at the end is hard to understand so add "hr"
376
+ label += 'hr';
306
377
  }
378
+ if (hass) {
379
+ label += ':'+pad2(sec);
380
+ }
307
381
  break;
308
382
  }
309
383
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reality.eth/reality-eth-lib",
3
- "version": "3.0.1",
3
+ "version": "3.1.1",
4
4
  "description": "Tools for handling questions in the reality.eth fact verification platform",
5
5
  "scripts": {
6
6
  "test": "env TZ='Asia/Kabul' mocha ./test"
@@ -16,14 +16,14 @@
16
16
  "author": "Edmund Edgar (https://reality.eth.link)",
17
17
  "license": "GPL-3.0",
18
18
  "dependencies": {
19
- "@reality.eth/contracts": "^3.0.1",
19
+ "@reality.eth/contracts": "^3.0.3",
20
20
  "bignumber.js": "^7.2.1",
21
- "bn.js": "^4.11.8",
21
+ "bn.js": "^5.2.1",
22
22
  "ethereumjs-abi": "^0.6.5",
23
23
  "sprintf-js": "^1.1.1"
24
24
  },
25
25
  "devDependencies": {
26
- "chai": "^4.1.2",
26
+ "chai": "^4.3.6",
27
27
  "chai-bignumber": "^2.0.2",
28
28
  "mocha": "^5.2.0",
29
29
  "truffle": "^4.0.1"
@@ -36,5 +36,5 @@
36
36
  "url": "https://github.com/RealityETH/monorepo/issues"
37
37
  },
38
38
  "homepage": "https://reality.eth.link",
39
- "gitHead": "ec3439b604fe5fc18f20ad26cb30f2e511629a71"
39
+ "gitHead": "b9fcb24ff3274a58c4f98c0c97b58c4d5c5b0fcd"
40
40
  }
@@ -116,13 +116,66 @@ describe('Answer strings', function() {
116
116
  expect(rc_question.getAnswerString(q, '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff')).to.equal('-1e-18');
117
117
  });
118
118
  */
119
- it('Handles datetimes as expected', function() {
119
+ it('Handles datetimes of default precision as expected', function() {
120
120
  var q = rc_question.populatedJSONForTemplate(rc_template.defaultTemplateForType('datetime'), '');
121
- expect(rc_question.getAnswerString(q, '0x0000000000000000000000000000000000000000000000000000000000000000')).to.equal('1970/1/1');
122
- expect(rc_question.getAnswerString(q, '0x000000000000000000000000000000000000000000000000000000005B0DE980')).to.equal('2018/5/30');
123
- expect(rc_question.getAnswerString(q, '0x000000000000000000000000000000000000000000000000000000005B0DE981')).to.equal('2018/5/30 00:00:01');
124
- expect(rc_question.getAnswerString(q, '0x000000000000000000000000000000000000000000000000000000005B0E02F7')).to.equal('2018/5/30 01:48:39'); // TODO: Change this to include time if it's not 00:00
121
+ expect(rc_question.getAnswerString(q, '0x0000000000000000000000000000000000000000000000000000000000000000')).to.equal('1970-01-01');
122
+ expect(rc_question.getAnswerString(q, '0x000000000000000000000000000000000000000000000000000000005B0DE980')).to.equal('2018-05-30');
123
+ expect(rc_question.getAnswerString(q, '0x000000000000000000000000000000000000000000000000000000005B0DE981')).to.equal('[Invalid datetime]: 2018-05-30 00:00:01');
124
+ expect(rc_question.getAnswerString(q, '0x000000000000000000000000000000000000000000000000000000005B0E02F7')).to.equal('[Invalid datetime]: 2018-05-30 01:48:39');
125
125
  });
126
+ it('Handles datetimes of specified precision as expected', function() {
127
+ var q = rc_question.populatedJSONForTemplate(rc_template.defaultTemplateForType('datetime'), '');
128
+ q['precision'] = 'd';
129
+ expect(rc_question.getAnswerString(q, '0x0000000000000000000000000000000000000000000000000000000000000000')).to.equal('1970-01-01');
130
+ expect(rc_question.getAnswerString(q, '0x000000000000000000000000000000000000000000000000000000005B0DE980')).to.equal('2018-05-30');
131
+ expect(rc_question.getAnswerString(q, '0x000000000000000000000000000000000000000000000000000000005B0DE981')).to.equal('[Invalid datetime]: 2018-05-30 00:00:01');
132
+ expect(rc_question.getAnswerString(q, '0x000000000000000000000000000000000000000000000000000000005B0E02F7')).to.equal('[Invalid datetime]: 2018-05-30 01:48:39');
133
+
134
+ q['precision'] = 'H';
135
+ expect(rc_question.getAnswerString(q, '0x000000000000000000000000000000000000000000000000000000005B0E02F7')).to.equal('[Invalid datetime]: 2018-05-30 01:48:39');
136
+ expect(rc_question.getAnswerString(q, '0x000000000000000000000000000000000000000000000000000000005B0DE980')).to.equal('2018-05-30 00hr');
137
+
138
+ q['precision'] = 'i';
139
+ expect(rc_question.getAnswerString(q, '0x000000000000000000000000000000000000000000000000000000005B0E02F7')).to.equal('[Invalid datetime]: 2018-05-30 01:48:39');
140
+ expect(rc_question.getAnswerString(q, '0x000000000000000000000000000000000000000000000000000000005B0DE980')).to.equal('2018-05-30 00:00');
141
+
142
+ q['precision'] = 's';
143
+ expect(rc_question.getAnswerString(q, '0x000000000000000000000000000000000000000000000000000000005B0E02F7')).to.equal('2018-05-30 01:48:39');
144
+ expect(rc_question.getAnswerString(q, '0x000000000000000000000000000000000000000000000000000000005B0DE980')).to.equal('2018-05-30 00:00:00');
145
+
146
+ q['precision'] = 'i';
147
+ expect(rc_question.getAnswerString(q, '0x000000000000000000000000000000000000000000000000000000006163683C')).to.equal('2021-10-10 22:25');
148
+
149
+ q['precision'] = 'H';
150
+ expect(rc_question.getAnswerString(q, '0x000000000000000000000000000000000000000000000000000000006163683C')).to.equal('[Invalid datetime]: 2021-10-10 22:25');
151
+ expect(rc_question.getAnswerString(q, '0x0000000000000000000000000000000000000000000000000000000061636260')).to.equal('2021-10-10 22hr');
152
+ // q['precision'] = 'H';
153
+
154
+ q['precision'] = 'd';
155
+ expect(rc_question.getAnswerString(q, '0x0000000000000000000000000000000000000000000000000000000061636260')).to.equal('[Invalid datetime]: 2021-10-10 22hr');
156
+
157
+ q['precision'] = 's';
158
+ expect(rc_question.getAnswerString(q, '0x000000000000000000000000000000000000000000000000000000005FEE6600')).to.equal('2021-01-01 00:00:00');
159
+ q['precision'] = 'i';
160
+ expect(rc_question.getAnswerString(q, '0x000000000000000000000000000000000000000000000000000000005FEE6600')).to.equal('2021-01-01 00:00');
161
+ q['precision'] = 'H';
162
+ expect(rc_question.getAnswerString(q, '0x000000000000000000000000000000000000000000000000000000005FEE6600')).to.equal('2021-01-01 00hr');
163
+ q['precision'] = 'd';
164
+ expect(rc_question.getAnswerString(q, '0x000000000000000000000000000000000000000000000000000000005FEE6600')).to.equal('2021-01-01');
165
+ q['precision'] = 'm';
166
+ expect(rc_question.getAnswerString(q, '0x000000000000000000000000000000000000000000000000000000005FEE6600')).to.equal('2021-01');
167
+ q['precision'] = 'Y';
168
+ expect(rc_question.getAnswerString(q, '0x000000000000000000000000000000000000000000000000000000005FEE6600')).to.equal('2021');
169
+
170
+ // 1609426800 2021 5FEE6600
171
+
172
+ //1633904700 6163683C
173
+ //1633903200 61636260
174
+ //1609426800 5FEDE770
175
+
176
+
177
+ });
178
+
126
179
  it('Handles single selects as expected', function() {
127
180
  var outcomes = ['thing1', 'thing2', 'thing3'];
128
181
  var qtext = rc_question.encodeText('single-select', 'oink', outcomes, 'my-category');
@@ -139,7 +192,21 @@ describe('Answer strings', function() {
139
192
  expect(rc_question.getAnswerString(q, '0x0000000000000000000000000000000000000000000000000000000000000002')).to.equal('thing2');
140
193
  expect(rc_question.getAnswerString(q, '0x0000000000000000000000000000000000000000000000000000000000000003')).to.equal('thing1 / thing2');
141
194
  });
142
-
195
+ it('Sets an error if there are too many outcomes', function() {
196
+ var outcomes = [];
197
+ for(var i=0; i<129; i++) {
198
+ outcomes.push('thing'+i);
199
+ }
200
+ var qtext = rc_question.encodeText('multiple-select', 'oink', outcomes, 'my-category');
201
+ var q1 = rc_question.populatedJSONForTemplate(rc_template.defaultTemplateForType('multiple-select'), qtext);
202
+ expect(q1.errors.too_many_outcomes).to.equal(true);
203
+ console.log(q1.title);
204
+ expect(q1.title).to.equal('oink');
205
+ var q2 = rc_question.populatedJSONForTemplate(rc_template.defaultTemplateForType('multiple-select'), qtext, true);
206
+ expect(q2.errors.too_many_outcomes).to.equal(true);
207
+ expect(q2.title).to.equal('[Too many outcomes] oink');
208
+ //expect(rc_question.getAnswerString(q, '0x0000000000000000000000000000000000000000000000000000000000000003')).to.equal('thing1 / thing2');
209
+ });
143
210
  });
144
211
  /*
145
212
  describe('Min Number Formatter', function() {
@@ -161,6 +228,16 @@ describe('Broken questions', function() {
161
228
  var broken = '{ "title": "You need to quote your "quotation marks" before parsing", "type": "bool" }';
162
229
  var q = rc_question.populatedJSONForTemplate(rc_template.defaultTemplateForType('bool'), broken);
163
230
  expect(q.type).to.equal('broken-question');
231
+ expect(q.errors.json_parse_failed).to.equal(true);
232
+ });
233
+ it('Sets the invalid_precision error if the precision is set but to something other than Y m d H i s', function() {
234
+ var broken = '{ "title": "This datetime will not work", "type": "datetime", "precision": "X" }';
235
+ var q1 = rc_question.populatedJSONForTemplate(broken, '');
236
+ expect(q1.errors.invalid_precision).to.equal(true);
237
+ expect(q1.title).to.equal('This datetime will not work');
238
+ var q2 = rc_question.populatedJSONForTemplate(broken, '', true);
239
+ expect(q2.errors.invalid_precision).to.equal(true);
240
+ expect(q2.title).to.equal('[Invalid date format] This datetime will not work');
164
241
  });
165
242
  });
166
243