wingbot 3.38.1 → 3.39.0-alpha.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wingbot",
3
- "version": "3.38.1",
3
+ "version": "3.39.0-alpha.1",
4
4
  "description": "Enterprise Messaging Bot Conversation Engine",
5
5
  "main": "index.js",
6
6
  "scripts": {
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
  }
@@ -172,12 +192,18 @@ class AiMatching {
172
192
  }
173
193
 
174
194
  _hbsOrFn (value, cb) {
175
- if (typeof value === 'string' && value.match(/\{\{.+\}\}/)) {
176
- const compiler = handlebars.compile(value);
177
- return (data) => {
178
- const res = compiler(data);
179
- return cb(res);
180
- };
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
+ return (data) => {
203
+ const res = compiler(data);
204
+ return cb(res);
205
+ };
206
+ }
181
207
  }
182
208
  return cb(value);
183
209
  }
@@ -427,7 +453,7 @@ class AiMatching {
427
453
 
428
454
  let useState;
429
455
  if (stateless || intents.length === 0) {
430
- useState = Object.entries(req.state)
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.state;
464
+ useState = stateData(req);
439
465
  }
440
466
 
441
467
  const { score, handicap, matched } = this
@@ -706,9 +732,10 @@ class AiMatching {
706
732
  : false;
707
733
  }
708
734
 
709
- const useCmp = (compare || []).map((c) => (typeof c === 'function'
710
- ? c(requestState)
711
- : c));
735
+ const useCmp = (compare || [])
736
+ .map((c) => (typeof c === 'function'
737
+ ? c(requestState)
738
+ : c));
712
739
 
713
740
  switch (operation) {
714
741
  case COMPARE.EQUAL:
@@ -740,6 +767,9 @@ class AiMatching {
740
767
  }
741
768
 
742
769
  _numberComparison (op, cmp, normalized) {
770
+ if (typeof cmp !== typeof normalized) {
771
+ return false;
772
+ }
743
773
  switch (op) {
744
774
  case COMPARE.GT:
745
775
  return normalized > cmp;
@@ -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 };
@@ -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 {Request} req
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
- ...req.actionData(),
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
  };