wingbot 3.38.1 → 3.39.0-alpha.2
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.
- package/package.json +1 -1
- package/src/AiMatching.js +57 -22
- package/src/Request.js +9 -1
- package/src/utils/datetime.js +50 -0
- package/src/utils/quickReplies.js +1 -0
- package/src/utils/stateData.js +26 -2
package/package.json
CHANGED
package/src/AiMatching.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
const { replaceDiacritics } = require('./utils/tokenizer');
|
|
7
7
|
const { vars } = require('./utils/stateVariables');
|
|
8
|
+
const stateData = require('./utils/stateData');
|
|
8
9
|
|
|
9
10
|
/** @typedef {import('handlebars')} Handlebars */
|
|
10
11
|
|
|
@@ -22,6 +23,20 @@ const FULL_EMOJI_REGEX = /^#((?:[\u2600-\u27bf].?|(?:\ud83c[\udde6-\uddff]){2}|[
|
|
|
22
23
|
const HAS_CLOSING_HASH = /^#(.+)#$/;
|
|
23
24
|
const ENTITY_REGEX = /^@([^=><!?]+)(\?)?([!=><]{1,2})?([^=><!]+)?$/i;
|
|
24
25
|
|
|
26
|
+
/**
|
|
27
|
+
* RegExp to test a string for a ISO 8601 Date spec
|
|
28
|
+
* YYYY
|
|
29
|
+
* YYYY-MM
|
|
30
|
+
* YYYY-MM-DD
|
|
31
|
+
* YYYY-MM-DDThh:mmTZD
|
|
32
|
+
* YYYY-MM-DDThh:mm:ssTZD
|
|
33
|
+
* YYYY-MM-DDThh:mm:ss.sTZD
|
|
34
|
+
*
|
|
35
|
+
* @see https://www.w3.org/TR/NOTE-datetime
|
|
36
|
+
* @type {RegExp}
|
|
37
|
+
*/
|
|
38
|
+
const ISO_8601_REGEX = /^\d{4}-\d\d-\d\d(T\d\d:\d\d(:\d\d)?(\.\d+)?(([+-]\d\d:\d\d)|Z)?)?$/i;
|
|
39
|
+
|
|
25
40
|
/**
|
|
26
41
|
* @typedef {string} Compare
|
|
27
42
|
*/
|
|
@@ -88,7 +103,9 @@ const COMPARE = {
|
|
|
88
103
|
* @prop {Function} text
|
|
89
104
|
* @prop {Intent[]|null} intents
|
|
90
105
|
* @prop {Entity[]} entities
|
|
106
|
+
* @prop {object} [configuration]
|
|
91
107
|
* @prop {object} [state]
|
|
108
|
+
* @prop {Function} [actionData]
|
|
92
109
|
*/
|
|
93
110
|
|
|
94
111
|
/**
|
|
@@ -162,6 +179,9 @@ class AiMatching {
|
|
|
162
179
|
|
|
163
180
|
_normalizeToNumber (value, returnIfEmpty = null) {
|
|
164
181
|
if (typeof value === 'string') {
|
|
182
|
+
if (value.match(ISO_8601_REGEX)) {
|
|
183
|
+
return value;
|
|
184
|
+
}
|
|
165
185
|
const flt = parseFloat(value);
|
|
166
186
|
return Number.isNaN(flt) ? returnIfEmpty : flt;
|
|
167
187
|
}
|
|
@@ -171,15 +191,20 @@ class AiMatching {
|
|
|
171
191
|
return returnIfEmpty;
|
|
172
192
|
}
|
|
173
193
|
|
|
174
|
-
_hbsOrFn (value
|
|
175
|
-
if (typeof value === 'string'
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
}
|
|
194
|
+
_hbsOrFn (value) {
|
|
195
|
+
if (typeof value === 'string') {
|
|
196
|
+
let useValue = value;
|
|
197
|
+
if (useValue.match(/^\$[a-zA-Z0-9_-]+$/)) {
|
|
198
|
+
useValue = `{{${useValue}}}`;
|
|
199
|
+
}
|
|
200
|
+
if (useValue.match(/\{\{.+\}\}/)) {
|
|
201
|
+
const compiler = handlebars.compile(useValue);
|
|
202
|
+
// @ts-ignore
|
|
203
|
+
compiler.template = useValue;
|
|
204
|
+
return compiler;
|
|
205
|
+
}
|
|
181
206
|
}
|
|
182
|
-
return
|
|
207
|
+
return value;
|
|
183
208
|
}
|
|
184
209
|
|
|
185
210
|
_normalizeComparisonArray (compare, op) {
|
|
@@ -194,7 +219,7 @@ class AiMatching {
|
|
|
194
219
|
const [val] = arr;
|
|
195
220
|
|
|
196
221
|
return [
|
|
197
|
-
this._hbsOrFn(val
|
|
222
|
+
this._hbsOrFn(val)
|
|
198
223
|
];
|
|
199
224
|
}
|
|
200
225
|
|
|
@@ -202,12 +227,12 @@ class AiMatching {
|
|
|
202
227
|
const [min, max] = arr;
|
|
203
228
|
|
|
204
229
|
return [
|
|
205
|
-
this._hbsOrFn(min
|
|
206
|
-
this._hbsOrFn(max
|
|
230
|
+
this._hbsOrFn(min),
|
|
231
|
+
this._hbsOrFn(max)
|
|
207
232
|
];
|
|
208
233
|
}
|
|
209
234
|
|
|
210
|
-
return arr.map((cmp) => this._hbsOrFn(cmp
|
|
235
|
+
return arr.map((cmp) => this._hbsOrFn(cmp));
|
|
211
236
|
}
|
|
212
237
|
|
|
213
238
|
_stringOpToOperation (op) {
|
|
@@ -259,6 +284,7 @@ class AiMatching {
|
|
|
259
284
|
*/
|
|
260
285
|
getSetStateForEntityRules ({ entities }) {
|
|
261
286
|
return entities.reduce((o, rule) => {
|
|
287
|
+
|
|
262
288
|
if (rule instanceof RegExp) {
|
|
263
289
|
return o;
|
|
264
290
|
}
|
|
@@ -271,13 +297,13 @@ class AiMatching {
|
|
|
271
297
|
|
|
272
298
|
if (rule.op === COMPARE.EQUAL
|
|
273
299
|
&& rule.compare
|
|
274
|
-
&& rule.compare.length === 1
|
|
275
|
-
&& typeof rule.compare[0] !== 'function') {
|
|
300
|
+
&& rule.compare.length === 1) {
|
|
276
301
|
|
|
277
302
|
const key = `@${rule.entity}`;
|
|
278
303
|
const value = rule.compare[0];
|
|
279
304
|
|
|
280
|
-
|
|
305
|
+
// @ts-ignore
|
|
306
|
+
return vars.dialogContext(key, value && (value.template || value));
|
|
281
307
|
}
|
|
282
308
|
return o;
|
|
283
309
|
}, {});
|
|
@@ -427,7 +453,7 @@ class AiMatching {
|
|
|
427
453
|
|
|
428
454
|
let useState;
|
|
429
455
|
if (stateless || intents.length === 0) {
|
|
430
|
-
useState = Object.entries(req
|
|
456
|
+
useState = Object.entries(stateData(req))
|
|
431
457
|
.reduce((o, [k, v]) => {
|
|
432
458
|
if (k.startsWith('@')) {
|
|
433
459
|
return o;
|
|
@@ -435,7 +461,7 @@ class AiMatching {
|
|
|
435
461
|
return Object.assign(o, { [k]: v });
|
|
436
462
|
}, {});
|
|
437
463
|
} else {
|
|
438
|
-
useState = req
|
|
464
|
+
useState = stateData(req);
|
|
439
465
|
}
|
|
440
466
|
|
|
441
467
|
const { score, handicap, matched } = this
|
|
@@ -706,9 +732,14 @@ class AiMatching {
|
|
|
706
732
|
: false;
|
|
707
733
|
}
|
|
708
734
|
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
735
|
+
let useCmp = (compare || [])
|
|
736
|
+
.map((c) => (typeof c === 'function'
|
|
737
|
+
? c(requestState)
|
|
738
|
+
: c));
|
|
739
|
+
|
|
740
|
+
if ([COMPARE.EQUAL, COMPARE.NOT_EQUAL].includes(operation)) {
|
|
741
|
+
useCmp = useCmp.map((c) => (typeof c === 'string' ? c : `${c}`));
|
|
742
|
+
}
|
|
712
743
|
|
|
713
744
|
switch (operation) {
|
|
714
745
|
case COMPARE.EQUAL:
|
|
@@ -721,7 +752,8 @@ class AiMatching {
|
|
|
721
752
|
if (normalized === null) {
|
|
722
753
|
return false;
|
|
723
754
|
}
|
|
724
|
-
return normalized >= min
|
|
755
|
+
return normalized >= this._normalizeToNumber(min, -Infinity)
|
|
756
|
+
&& normalized <= this._normalizeToNumber(max, Infinity);
|
|
725
757
|
}
|
|
726
758
|
case COMPARE.GT:
|
|
727
759
|
case COMPARE.LT:
|
|
@@ -732,7 +764,7 @@ class AiMatching {
|
|
|
732
764
|
if (normalized === null) {
|
|
733
765
|
return false;
|
|
734
766
|
}
|
|
735
|
-
return this._numberComparison(op, cmp, normalized);
|
|
767
|
+
return this._numberComparison(op, this._normalizeToNumber(cmp, 0), normalized);
|
|
736
768
|
}
|
|
737
769
|
default:
|
|
738
770
|
return true;
|
|
@@ -740,6 +772,9 @@ class AiMatching {
|
|
|
740
772
|
}
|
|
741
773
|
|
|
742
774
|
_numberComparison (op, cmp, normalized) {
|
|
775
|
+
if (typeof cmp !== typeof normalized) {
|
|
776
|
+
return false;
|
|
777
|
+
}
|
|
743
778
|
switch (op) {
|
|
744
779
|
case COMPARE.GT:
|
|
745
780
|
return normalized > cmp;
|
package/src/Request.js
CHANGED
|
@@ -1137,7 +1137,15 @@ class Request {
|
|
|
1137
1137
|
let { setState = {} } = res;
|
|
1138
1138
|
for (const gi of this.globalIntents.values()) {
|
|
1139
1139
|
if (gi.action === res.action) {
|
|
1140
|
-
|
|
1140
|
+
entitiesSetState = { ...gi.entitiesSetState };
|
|
1141
|
+
|
|
1142
|
+
const values = Array.from(Object.values(entitiesSetState));
|
|
1143
|
+
|
|
1144
|
+
for (const value of values) {
|
|
1145
|
+
if (typeof value === 'function') {
|
|
1146
|
+
Object.assign(entitiesSetState, value(stateData(this)));
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1141
1149
|
}
|
|
1142
1150
|
}
|
|
1143
1151
|
const newState = {
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @author David Menger
|
|
3
|
+
*/
|
|
4
|
+
'use strict';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
*
|
|
8
|
+
* @param {Date} inputDate
|
|
9
|
+
* @param {boolean} toZeroTimezone
|
|
10
|
+
* @returns {string}
|
|
11
|
+
*/
|
|
12
|
+
function dateToISO8601String (inputDate, toZeroTimezone = false) {
|
|
13
|
+
const padDigits = function padDigits (number, digits) {
|
|
14
|
+
return Array(Math.max(digits - String(number).length + 1, 0)).join('0') + number;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
let d = inputDate;
|
|
18
|
+
const offsetMinutes = d.getTimezoneOffset();
|
|
19
|
+
const offsetHours = offsetMinutes / 60;
|
|
20
|
+
let offset = 'Z';
|
|
21
|
+
if (toZeroTimezone) {
|
|
22
|
+
d = new Date(d.toISOString());
|
|
23
|
+
d.setMinutes(d.getMinutes() + offsetMinutes);
|
|
24
|
+
} else if (offsetHours < 0) {
|
|
25
|
+
offset = `+${padDigits(`${offsetHours.toString().replace('-', '')}00`, 4)}`;
|
|
26
|
+
} else if (offsetHours > 0) {
|
|
27
|
+
offset = `-${padDigits(`${offsetHours}00`, 4)}`;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return `${d.getFullYear()
|
|
31
|
+
}-${padDigits((d.getMonth() + 1), 2)
|
|
32
|
+
}-${padDigits(d.getDate(), 2)
|
|
33
|
+
}T${padDigits(d.getHours(), 2)
|
|
34
|
+
}:${padDigits(d.getMinutes(), 2)
|
|
35
|
+
}:${padDigits(d.getSeconds(), 2)
|
|
36
|
+
}.${padDigits(d.getMilliseconds(), 2)
|
|
37
|
+
}${offset}`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Make zero date
|
|
42
|
+
*
|
|
43
|
+
* @param {Date} d
|
|
44
|
+
* @returns {Date}
|
|
45
|
+
*/
|
|
46
|
+
function zeroHourDate (d) {
|
|
47
|
+
return new Date(d.getFullYear(), d.getMonth(), d.getDate(), 0, -d.getTimezoneOffset());
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
module.exports = { dateToISO8601String, zeroHourDate };
|
package/src/utils/stateData.js
CHANGED
|
@@ -6,9 +6,19 @@
|
|
|
6
6
|
/** @typedef {import('../Request')} Request */
|
|
7
7
|
/** @typedef {import('../Responder')} Responder */
|
|
8
8
|
|
|
9
|
+
const { dateToISO8601String, zeroHourDate } = require('./datetime');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @typedef {object} IStateRequest
|
|
13
|
+
* @prop {object} [state]
|
|
14
|
+
* @prop {object} [configuration]
|
|
15
|
+
* @prop {Function} text
|
|
16
|
+
* @prop {Function} [actionData]
|
|
17
|
+
*/
|
|
18
|
+
|
|
9
19
|
/**
|
|
10
20
|
*
|
|
11
|
-
* @param {
|
|
21
|
+
* @param {IStateRequest} req
|
|
12
22
|
* @param {Responder} res
|
|
13
23
|
* @param {object} configuration
|
|
14
24
|
* @param {object} [stateOverride]
|
|
@@ -19,6 +29,15 @@ module.exports = function stateData (req, res = null, configuration = null, stat
|
|
|
19
29
|
|
|
20
30
|
const $this = req.text();
|
|
21
31
|
|
|
32
|
+
const now = new Date();
|
|
33
|
+
|
|
34
|
+
const $now = dateToISO8601String(now, true);
|
|
35
|
+
const $today = dateToISO8601String(zeroHourDate(now), true);
|
|
36
|
+
now.setDate(now.getDate() + 1);
|
|
37
|
+
const $tomorrow = dateToISO8601String(zeroHourDate(now), true);
|
|
38
|
+
now.setDate(now.getDate() - 2);
|
|
39
|
+
const $yesterday = dateToISO8601String(zeroHourDate(now), true);
|
|
40
|
+
|
|
22
41
|
return {
|
|
23
42
|
c,
|
|
24
43
|
configuration: c,
|
|
@@ -26,7 +45,12 @@ module.exports = function stateData (req, res = null, configuration = null, stat
|
|
|
26
45
|
...(res ? res.newState : {}),
|
|
27
46
|
...stateOverride,
|
|
28
47
|
$this,
|
|
29
|
-
|
|
48
|
+
$now,
|
|
49
|
+
$today,
|
|
50
|
+
$tomorrow,
|
|
51
|
+
$yesterday,
|
|
52
|
+
// yes - res because of circular dependency
|
|
53
|
+
...(res && req.actionData()),
|
|
30
54
|
...(res ? res.data : {}),
|
|
31
55
|
$input: $this
|
|
32
56
|
};
|