botium-core
Version:
The Selenium for Chatbots
1,628 lines (1,443 loc) • 238 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var util = _interopDefault(require('util'));
var fs = _interopDefault(require('fs'));
var path = _interopDefault(require('path'));
var async = _interopDefault(require('async'));
var mkdirp = _interopDefault(require('mkdirp'));
var slugify = _interopDefault(require('slugify'));
var moment = _interopDefault(require('moment'));
var randomatic = _interopDefault(require('randomatic'));
var lodash = _interopDefault(require('lodash'));
var boolean = _interopDefault(require('boolean'));
var events = _interopDefault(require('events'));
var debug$h = _interopDefault(require('debug'));
var vm = _interopDefault(require('vm'));
var isClass = _interopDefault(require('is-class'));
var glob = _interopDefault(require('glob'));
var promise = _interopDefault(require('promise.allsettled'));
var v1 = _interopDefault(require('uuid/v1'));
var xlsx = _interopDefault(require('xlsx'));
var isJson$1 = _interopDefault(require('is-json'));
var sync = _interopDefault(require('csv-parse/lib/sync'));
var child_process = _interopDefault(require('child_process'));
var socket = _interopDefault(require('socket.io-client'));
var rimraf = _interopDefault(require('rimraf'));
var writeYaml = _interopDefault(require('write-yaml'));
var mustache = _interopDefault(require('mustache'));
var findRoot = _interopDefault(require('find-root'));
var request = _interopDefault(require('request'));
var copyDir = _interopDefault(require('copy-dir'));
var tcpPortUsed = _interopDefault(require('tcp-port-used'));
var dgram = _interopDefault(require('dgram'));
var readline = _interopDefault(require('readline'));
var facebookChatApi = _interopDefault(require('facebook-chat-api'));
var opn = _interopDefault(require('opn'));
var tinyServer = _interopDefault(require('tiny-server'));
var socket$1 = _interopDefault(require('socket.io'));
var promiseRetry = _interopDefault(require('promise-retry'));
var jsonpath = _interopDefault(require('jsonpath'));
var mimeTypes = _interopDefault(require('mime-types'));
var v4 = _interopDefault(require('uuid/v4'));
var esprima = _interopDefault(require('esprima'));
var name = "botium-core";
var version = "1.5.4";
var description = "The Selenium for Chatbots";
var main = "index.js";
var module$1 = "dist/botium-es.js";
var engines = {
node: ">=8.10.0"
};
var scripts = {
build: "npm run eslint && nyc npm test && nyc check-coverage --lines 50 --functions 50 --branches 35 && rollup -c",
eslint: "eslint \"./src/**/*.js\" \"./test/**/*.js\"",
newpatch: "npm version patch",
agent: "node ./src/grid/agent/agent.js",
"agent-jsdoc": "swagger-jsdoc -d ./src/grid/agent/swaggerDef.json -o ./src/grid/agent/swagger.json ./src/grid/agent/routes.js",
link: "npm link botium-connector-dialogflow botium-connector-webdriverio botium-connector-directline3 botium-connector-watson botium-connector-alexa-smapi botium-connector-echo",
test: "mocha \"./test/**/*.spec.js\"",
"coverage:report": "nyc report --reporter=lcov npm test",
"license-checker": "license-checker > LICENSES-3RDPARTY.txt"
};
var repository = {
type: "git",
url: "git+https://github.com/codeforequity-at/botium-core.git"
};
var author = "Florian Treml";
var license = "MIT";
var bugs = {
url: "https://github.com/codeforequity-at/botium-core/issues"
};
var homepage = "https://github.com/codeforequity-at/botium-core#readme";
var dependencies = {
"@babel/runtime": "7.5.5",
async: "^3.1.0",
"body-parser": "^1.19.0",
boolean: "^1.0.0",
"copy-dir": "^1.1.0",
"csv-parse": "^4.4.3",
debug: "^4.1.1",
esprima: "^4.0.1",
express: "^4.17.1",
"facebook-chat-api": "^1.6.1",
"find-root": "^1.1.0",
glob: "^7.1.4",
"is-class": "0.0.7",
"is-json": "^2.0.1",
jsonpath: "^1.0.2",
lodash: "^4.17.15",
"mime-types": "^2.1.24",
mkdirp: "^0.5.1",
moment: "^2.24.0",
mustache: "^3.0.1",
opn: "^6.0.0",
"promise-retry": "^1.1.1",
"promise.allsettled": "^1.0.1",
randomatic: "^3.1.1",
request: "^2.88.0",
rimraf: "^2.6.3",
slugify: "^1.3.4",
"socket.io": "^2.2.0",
"socket.io-client": "^2.2.0",
"socketio-auth": "^0.1.1",
"swagger-jsdoc": "^3.3.0",
"swagger-ui-express": "^4.0.7",
"tcp-port-used": "^1.0.1",
"tiny-server": "^1.1.0",
uuid: "^3.3.3",
"write-yaml": "^1.0.0",
xlsx: "^0.14.4",
xregexp: "^4.2.4"
};
var devDependencies = {
"@babel/core": "^7.5.5",
"@babel/node": "^7.5.5",
"@babel/plugin-transform-runtime": "^7.5.5",
"@babel/preset-env": "^7.5.5",
chai: "^4.2.0",
"chai-as-promised": "^7.1.1",
"cross-env": "^5.2.1",
eslint: "^6.3.0",
"eslint-config-standard": "^14.1.0",
"eslint-plugin-import": "^2.18.2",
"eslint-plugin-node": "^10.0.0",
"eslint-plugin-promise": "^4.2.1",
"eslint-plugin-standard": "^4.0.1",
"license-checker": "^25.0.1",
mocha: "^6.2.0",
nock: "^11.3.3",
nyc: "^14.1.1",
rollup: "^1.20.3",
"rollup-plugin-babel": "^4.3.3",
"rollup-plugin-commonjs": "^10.1.0",
"rollup-plugin-json": "^4.0.0",
"rollup-plugin-node-resolve": "^5.2.0"
};
var _package = {
name: name,
version: version,
description: description,
main: main,
module: module$1,
engines: engines,
scripts: scripts,
repository: repository,
author: author,
license: license,
bugs: bugs,
homepage: homepage,
dependencies: dependencies,
devDependencies: devDependencies
};
var _package$1 = /*#__PURE__*/Object.freeze({
name: name,
version: version,
description: description,
main: main,
module: module$1,
engines: engines,
scripts: scripts,
repository: repository,
author: author,
license: license,
bugs: bugs,
homepage: homepage,
dependencies: dependencies,
devDependencies: devDependencies,
'default': _package
});
var Capabilities = {
PROJECTNAME: 'PROJECTNAME',
TEMPDIR: 'TEMPDIR',
CLEANUPTEMPDIR: 'CLEANUPTEMPDIR',
WAITFORBOTTIMEOUT: 'WAITFORBOTTIMEOUT',
// "docker" "fbdirect" "watsonconversation", "simplerest", "webspeech", "inprocess"
CONTAINERMODE: 'CONTAINERMODE',
STARTCMD: 'STARTCMD',
// falsy or ms/keystroke
SIMULATE_WRITING_SPEED: 'SIMULATE_WRITING_SPEED',
DOCKERCOMPOSEPATH: 'DOCKERCOMPOSEPATH',
DOCKERMACHINEPATH: 'DOCKERMACHINEPATH',
DOCKERMACHINE: 'DOCKERMACHINE',
DOCKERIMAGE: 'DOCKERIMAGE',
DOCKERUNIQUECONTAINERNAMES: 'DOCKERUNIQUECONTAINERNAMES',
DOCKERSYSLOGPORT: 'DOCKERSYSLOGPORT',
DOCKERSYSLOGPORT_RANGE: 'DOCKERSYSLOGPORT_RANGE',
BOTIUMGRIDURL: 'BOTIUMGRIDURL',
BOTIUMAPITOKEN: 'BOTIUMAPITOKEN',
BOTIUMGRIDSLOT: 'BOTIUMGRIDSLOT',
// General Mocker Settings
BOT_HEALTH_STATUS: 'BOT_HEALTH_STATUS',
BOT_HEALTH_CHECK_PATH: 'BOT_HEALTH_CHECK_PATH',
BOT_HEALTH_CHECK_VERB: 'BOT_HEALTH_CHECK_VERB',
// Facebook Mocker Settings
FACEBOOK_API: 'FACEBOOK_API',
FACEBOOK_WEBHOOK_PORT: 'FACEBOOK_WEBHOOK_PORT',
FACEBOOK_WEBHOOK_PATH: 'FACEBOOK_WEBHOOK_PATH',
FACEBOOK_PUBLISHPORT: 'FACEBOOK_PUBLISHPORT',
FACEBOOK_PUBLISHPORT_RANGE: 'FACEBOOK_PUBLISHPORT_RANGE',
FACEBOOK_SEND_DELIVERY_CONFIRMATION: 'FACEBOOK_SEND_DELIVERY_CONFIRMATION',
// Slack Mocker Settings
SLACK_API: 'SLACK_API',
SLACK_EVENT_PORT: 'SLACK_EVENT_PORT',
SLACK_EVENT_PATH: 'SLACK_EVENT_PATH',
SLACK_OAUTH_PORT: 'SLACK_OAUTH_PORT',
SLACK_OAUTH_PATH: 'SLACK_OAUTH_PATH',
SLACK_PUBLISHPORT: 'SLACK_PUBLISHPORT',
SLACK_PUBLISHPORT_RANGE: 'SLACK_PUBLISHPORT_RANGE',
// Facebook Direct API Settings
FB_PAGEID: 'FB_PAGEID',
FB_USER: 'FB_USER',
FB_PASSWORD: 'FB_PASSWORD',
// Bot Framework Mocker Settings
BOTFRAMEWORK_API: 'BOTFRAMEWORK_API',
BOTFRAMEWORK_APP_ID: 'BOTFRAMEWORK_APP_ID',
BOTFRAMEWORK_CHANNEL_ID: 'BOTFRAMEWORK_CHANNEL_ID',
BOTFRAMEWORK_WEBHOOK_PORT: 'BOTFRAMEWORK_WEBHOOK_PORT',
BOTFRAMEWORK_WEBHOOK_PATH: 'BOTFRAMEWORK_WEBHOOK_PATH',
BOTFRAMEWORK_PUBLISHPORT: 'BOTFRAMEWORK_PUBLISHPORT',
BOTFRAMEWORK_PUBLISHPORT_RANGE: 'BOTFRAMEWORK_PUBLISHPORT_RANGE',
// Simple Reset Bot Settings
SIMPLEREST_PING_URL: 'SIMPLEREST_PING_URL',
SIMPLEREST_PING_VERB: 'SIMPLEREST_PING_VERB',
SIMPLEREST_PING_BODY: 'SIMPLEREST_PING_BODY',
SIMPLEREST_PING_RETRIES: 'SIMPLEREST_PING_RETRIES',
SIMPLEREST_PING_TIMEOUT: 'SIMPLEREST_PING_TIMEOUT',
SIMPLEREST_INIT_CONTEXT: 'SIMPLEREST_INIT_CONTEXT',
SIMPLEREST_INIT_TEXT: 'SIMPLEREST_INIT_TEXT',
SIMPLEREST_URL: 'SIMPLEREST_URL',
SIMPLEREST_METHOD: 'SIMPLEREST_METHOD',
SIMPLEREST_HEADERS_TEMPLATE: 'SIMPLEREST_HEADERS_TEMPLATE',
SIMPLEREST_BODY_TEMPLATE: 'SIMPLEREST_BODY_TEMPLATE',
SIMPLEREST_BODY_RAW: 'SIMPLEREST_BODY_RAW',
SIMPLEREST_REQUEST_HOOK: 'SIMPLEREST_REQUEST_HOOK',
SIMPLEREST_RESPONSE_JSONPATH: 'SIMPLEREST_RESPONSE_JSONPATH',
SIMPLEREST_RESPONSE_HOOK: 'SIMPLEREST_RESPONSE_HOOK',
SIMPLEREST_MEDIA_JSONPATH: 'SIMPLEREST_MEDIA_JSONPATH',
SIMPLEREST_BUTTONS_JSONPATH: 'SIMPLEREST_BUTTONS_JSONPATH',
SIMPLEREST_CONTEXT_JSONPATH: 'SIMPLEREST_CONTEXT_JSONPATH',
SIMPLEREST_CONVERSATION_ID_TEMPLATE: 'SIMPLEREST_CONVERSATION_ID_TEMPLATE',
SIMPLEREST_STEP_ID_TEMPLATE: 'SIMPLEREST_STEP_ID_TEMPLATE',
// Webspeech Settings
WEBSPEECH_SERVER_PORT: 'WEBSPEECH_SERVER_PORT',
WEBSPEECH_LANGUAGE: 'WEBSPEECH_LANGUAGE',
WEBSPEECH_PITCH: 'WEBSPEECH_PITCH',
WEBSPEECH_RATE: 'WEBSPEECH_RATE',
WEBSPEECH_VOLUME: 'WEBSPEECH_VOLUME',
WEBSPEECH_VOICE: 'WEBSPEECH_VOICE',
WEBSPEECH_CLOSEBROWSER: 'WEBSPEECH_CLOSEBROWSER',
WEBSPEECH_BROWSER_APP: 'WEBSPEECH_BROWSER_APP',
// Script Compiler
SCRIPTING_TXT_EOL: 'SCRIPTING_TXT_EOL',
// ROW_PER_MESSAGE or QUESTION_ANSWER
SCRIPTING_XLSX_MODE: 'SCRIPTING_XLSX_MODE',
SCRIPTING_XLSX_EOL_WRITE: 'SCRIPTING_XLSX_EOL_WRITE',
SCRIPTING_XLSX_STARTROW: 'SCRIPTING_XLSX_STARTROW',
SCRIPTING_XLSX_STARTCOL: 'SCRIPTING_XLSX_STARTCOL',
SCRIPTING_XLSX_SHEETNAMES: 'SCRIPTING_XLSX_SHEETNAMES',
SCRIPTING_XLSX_SHEETNAMES_PCONVOS: 'SCRIPTING_XLSX_SHEETNAMES_PCONVOS',
SCRIPTING_XLSX_SHEETNAMES_UTTERANCES: 'SCRIPTING_XLSX_SHEETNAMES_UTTERANCES',
SCRIPTING_XLSX_SHEETNAMES_SCRIPTING_MEMORY: 'SCRIPTING_XLSX_SHEETNAMES_SCRIPTING_MEMORY',
SCRIPTING_CSV_SEPARATOR: 'SCRIPTING_CSV_SEPARATOR',
SCRIPTING_CSV_USE_HEADER: 'SCRIPTING_CSV_USE_HEADER',
// ROW_PER_MESSAGE or QUESTION_ANSWER
SCRIPTING_CSV_MODE: 'SCRIPTING_CSV_MODE',
SCRIPTING_CSV_MODE_ROW_PER_MESSAGE_COL_CONVERSATION_ID: 'SCRIPTING_CSV_MODE_ROW_PER_MESSAGE_COL_CONVERSATION_ID',
SCRIPTING_CSV_MODE_ROW_PER_MESSAGE_COL_SENDER: 'SCRIPTING_CSV_MODE_ROW_PER_MESSAGE_COL_SENDER',
SCRIPTING_CSV_MODE_ROW_PER_MESSAGE_COL_TEXT: 'SCRIPTING_CSV_MODE_ROW_PER_MESSAGE_COL_TEXT',
SCRIPTING_CSV_MODE_QUESTION_ANSWER_COL_QUESTION: 'SCRIPTING_CSV_MODE_QUESTION_ANSWER_COL_QUESTION',
SCRIPTING_CSV_MODE_QUESTION_ANSWER_COL_ANSWER: 'SCRIPTING_CSV_MODE_QUESTION_ANSWER_COL_ANSWER',
SCRIPTING_NORMALIZE_TEXT: 'SCRIPTING_NORMALIZE_TEXT',
SCRIPTING_ENABLE_MEMORY: 'SCRIPTING_ENABLE_MEMORY',
SCRIPTING_ENABLE_MULTIPLE_ASSERT_ERRORS: 'SCRIPTING_ENABLE_MULTIPLE_ASSERT_ERRORS',
// regexp, include, includeLowerCase, equals
SCRIPTING_MATCHING_MODE: 'SCRIPTING_MATCHING_MODE',
// all, first, random
SCRIPTING_UTTEXPANSION_MODE: 'SCRIPTING_UTTEXPANSION_MODE',
SCRIPTING_UTTEXPANSION_RANDOM_COUNT: 'SCRIPTING_UTTEXPANSION_RANDOM_COUNT',
SCRIPTING_UTTEXPANSION_INCOMPREHENSION: 'SCRIPTING_UTTEXPANSION_INCOMPREHENSION',
// Del original convo or not
SCRIPTING_MEMORYEXPANSION_KEEP_ORIG: 'SCRIPTING_MEMORYEXPANSION_KEEP_ORIG',
// word, non_whitespace, joker
SCRIPTING_MEMORY_MATCHING_MODE: 'SCRIPTING_MEMORY_MATCHING_MODE',
// Botium Lifecycle Hooks
CUSTOMHOOK_ONBUILD: 'CUSTOMHOOK_ONBUILD',
CUSTOMHOOK_ONSTART: 'CUSTOMHOOK_ONSTART',
CUSTOMHOOK_ONSTOP: 'CUSTOMHOOK_ONSTOP',
CUSTOMHOOK_ONCLEAN: 'CUSTOMHOOK_ONCLEAN',
// Retry logic
RETRY_USERSAYS_ONERROR_REGEXP: 'RETRY_USERSAYS_ONERROR_REGEXP',
RETRY_USERSAYS_NUMRETRIES: 'RETRY_USERSAYS_NUMRETRIES',
RETRY_USERSAYS_FACTOR: 'RETRY_USERSAYS_FACTOR',
RETRY_USERSAYS_MINTIMEOUT: 'RETRY_USERSAYS_MINTIMEOUT',
// Extension components
ASSERTERS: 'ASSERTERS',
LOGIC_HOOKS: 'LOGIC_HOOKS',
USER_INPUTS: 'USER_INPUTS'
};
var Source = {
LOCALPATH: 'LOCALPATH',
GITPATH: 'GITPATH',
GITURL: 'GITURL',
GITBRANCH: 'GITBRANCH',
GITDIR: 'GITDIR',
GITPREPARECMD: 'GITPREPARECMD'
};
var Defaults = {
Capabilities: {
[Capabilities.PROJECTNAME]: 'defaultproject',
[Capabilities.TEMPDIR]: 'botiumwork',
[Capabilities.CLEANUPTEMPDIR]: true,
[Capabilities.WAITFORBOTTIMEOUT]: 10000,
[Capabilities.SIMULATE_WRITING_SPEED]: false,
[Capabilities.DOCKERCOMPOSEPATH]: 'docker-compose',
[Capabilities.DOCKERMACHINEPATH]: 'docker-machine',
[Capabilities.DOCKERMACHINE]: false,
[Capabilities.DOCKERIMAGE]: 'node:boron',
[Capabilities.DOCKERUNIQUECONTAINERNAMES]: false,
[Capabilities.DOCKERSYSLOGPORT_RANGE]: '47100-47299',
[Capabilities.BOT_HEALTH_STATUS]: 200,
[Capabilities.SLACK_PUBLISHPORT_RANGE]: '46100-46299',
[Capabilities.FACEBOOK_PUBLISHPORT_RANGE]: '46300-46499',
[Capabilities.FACEBOOK_SEND_DELIVERY_CONFIRMATION]: true,
[Capabilities.BOTFRAMEWORK_PUBLISHPORT_RANGE]: '46500-46699',
[Capabilities.BOTFRAMEWORK_WEBHOOK_PORT]: 3978,
[Capabilities.BOTFRAMEWORK_WEBHOOK_PATH]: 'api/messages',
[Capabilities.BOTFRAMEWORK_CHANNEL_ID]: 'facebook',
[Capabilities.SIMPLEREST_PING_RETRIES]: 6,
[Capabilities.SIMPLEREST_PING_TIMEOUT]: 10000,
[Capabilities.SIMPLEREST_PING_VERB]: 'GET',
[Capabilities.SIMPLEREST_METHOD]: 'GET',
[Capabilities.WEBSPEECH_SERVER_PORT]: 46050,
[Capabilities.WEBSPEECH_LANGUAGE]: 'en-US',
[Capabilities.WEBSPEECH_CLOSEBROWSER]: true,
[Capabilities.SCRIPTING_TXT_EOL]: '\n',
[Capabilities.SCRIPTING_XLSX_EOL_WRITE]: '\r\n',
[Capabilities.SCRIPTING_XLSX_STARTROW]: 2,
[Capabilities.SCRIPTING_XLSX_STARTCOL]: 1,
[Capabilities.SCRIPTING_NORMALIZE_TEXT]: true,
[Capabilities.SCRIPTING_ENABLE_MEMORY]: false,
[Capabilities.SCRIPTING_ENABLE_MULTIPLE_ASSERT_ERRORS]: false,
[Capabilities.SCRIPTING_MATCHING_MODE]: 'includeLowerCase',
[Capabilities.SCRIPTING_UTTEXPANSION_MODE]: 'all',
[Capabilities.SCRIPTING_UTTEXPANSION_RANDOM_COUNT]: 1,
[Capabilities.SCRIPTING_MEMORYEXPANSION_KEEP_ORIG]: false,
[Capabilities.RETRY_USERSAYS_ONERROR_REGEXP]: [],
[Capabilities.RETRY_USERSAYS_NUMRETRIES]: 1,
[Capabilities.RETRY_USERSAYS_FACTOR]: 1,
[Capabilities.RETRY_USERSAYS_MINTIMEOUT]: 1000,
[Capabilities.ASSERTERS]: [],
[Capabilities.LOGIC_HOOKS]: [],
[Capabilities.USER_INPUTS]: []
},
Sources: {
[Source.LOCALPATH]: '.',
[Source.GITPATH]: 'git',
[Source.GITBRANCH]: 'master',
[Source.GITDIR]: '.'
},
Envs: {
IS_BOTIUM_CONTAINER: true
}
};
var Fluent_1 = class Fluent {
constructor(driver) {
this.driver = driver;
this.compiler = null;
this.container = null;
this.currentChannel = null;
this.tasks = [];
this.tasks.push(() => {
return new Promise((resolve, reject) => {
this.driver.Build().then(container => {
this.container = container;
resolve();
}).catch(err => {
reject(err);
});
});
});
}
Exec() {
return new Promise((resolve, reject) => {
async.eachSeries(this.tasks, (task, cb) => {
try {
const taskResult = task();
if (taskResult && taskResult.then) {
taskResult.then(() => cb()).catch(cb);
} else {
cb();
}
} catch (err) {
cb(err);
}
}, err => {
if (err) return reject(err);
resolve();
});
});
}
Start() {
this.tasks.push(() => {
return this.container.Start();
});
return this;
}
SwitchChannel(channel) {
this.tasks.push(() => {
this.currentChannel = channel;
return Promise.resolve();
});
return this;
}
ReadScripts(convoDir, globFilter) {
this.tasks.push(() => {
return new Promise((resolve, reject) => {
if (this.compiler == null) {
try {
this.compiler = this.driver.BuildCompiler();
} catch (err) {
return reject(err);
}
}
try {
this.compiler.ReadScriptsFromDirectory(convoDir, globFilter);
resolve();
} catch (err) {
reject(err);
}
});
});
return this;
}
Compile(scriptBuffer, scriptFormat, scriptType) {
this.tasks.push(() => {
return new Promise((resolve, reject) => {
if (this.compiler == null) {
try {
this.compiler = this.driver.BuildCompiler();
} catch (err) {
return reject(err);
}
}
try {
this.compiler.Compile(scriptBuffer, scriptFormat, scriptType);
resolve();
} catch (err) {
reject(err);
}
});
});
return this;
}
RunScripts(assertCb, failCb) {
this.tasks.push(() => {
return new Promise((resolve, reject) => {
if (assertCb) {
this.compiler.scriptingEvents.assertBotResponse = assertCb.bind(this.compiler);
}
if (failCb) {
this.compiler.scriptingEvents.fail = failCb.bind(this.compiler);
}
this.compiler.ExpandConvos();
async.eachSeries(this.compiler.convos, (convo, convoDone) => {
this.container.Start().then(() => convo.Run(this.container)).then(() => this.container.Stop()).then(() => convoDone()).catch(convoDone);
}, err => {
if (err) return reject(err);else resolve();
});
});
});
return this;
}
UserSaysText(msg) {
this.tasks.push(() => {
if (lodash.isFunction(msg)) {
msg = msg();
}
if (this.currentChannel) {
return this.container.UserSays({
messageText: msg,
channel: this.currentChannel
});
} else {
return this.container.UserSaysText(msg);
}
});
return this;
}
UserSays(msg) {
this.tasks.push(() => {
if (lodash.isFunction(msg)) {
msg = msg();
}
if (this.currentChannel && !msg.channel) {
msg = Object.assign({}, msg);
msg.channel = this.currentChannel;
}
return this.container.UserSays(msg);
});
return this;
}
WaitBotSays(channel = null, timeoutMillis = null, callback = null) {
if (!callback) {
if (timeoutMillis && lodash.isFunction(timeoutMillis)) {
callback = timeoutMillis;
timeoutMillis = null;
} else if (!timeoutMillis && channel && lodash.isFunction(channel)) {
callback = channel;
timeoutMillis = null;
channel = null;
}
}
this.tasks.push(() => {
return new Promise((resolve, reject) => {
if (this.currentChannel && !channel) {
channel = this.currentChannel;
}
this.container.WaitBotSays(channel, timeoutMillis).then(botMsg => {
if (callback) callback(botMsg);
resolve();
}).catch(err => {
reject(err);
});
});
});
return this;
}
WaitBotSaysText(channel = null, timeoutMillis = null, callback = null) {
if (!callback) {
if (timeoutMillis && lodash.isFunction(timeoutMillis)) {
callback = timeoutMillis;
timeoutMillis = null;
} else if (!timeoutMillis && channel && lodash.isFunction(channel)) {
callback = channel;
timeoutMillis = null;
channel = null;
}
}
this.tasks.push(() => {
return new Promise((resolve, reject) => {
if (this.currentChannel && !channel) {
channel = this.currentChannel;
}
this.container.WaitBotSaysText(channel, timeoutMillis).then(text => {
if (callback) callback(text);
resolve();
}).catch(err => {
reject(err);
});
});
});
return this;
}
Restart() {
this.tasks.push(() => {
return this.container.Restart();
});
return this;
}
Stop() {
this.tasks.push(() => {
return this.container.Stop();
});
return this;
}
Clean() {
this.tasks.push(() => {
return this.container.Clean();
});
return this;
}
Call(customFunction) {
this.tasks.push(() => {
return customFunction(this) || Promise.resolve();
});
return this;
}
};
var Events = {
// Botium Events
CONTAINER_BUILDING: 'CONTAINER_BUILDING',
CONTAINER_BUILT: 'CONTAINER_BUILT',
CONTAINER_BUILD_ERROR: 'CONTAINER_BUILD_ERROR',
CONTAINER_STARTING: 'CONTAINER_STARTING',
CONTAINER_STARTED: 'CONTAINER_STARTED',
CONTAINER_START_ERROR: 'CONTAINER_START_ERROR',
CONTAINER_STOPPING: 'CONTAINER_STOPPING',
CONTAINER_STOPPED: 'CONTAINER_STOPPED',
CONTAINER_STOP_ERROR: 'CONTAINER_STOP_ERROR',
CONTAINER_CLEANING: 'CONTAINER_CLEANING',
CONTAINER_CLEANED: 'CONTAINER_CLEANED',
CONTAINER_CLEAN_ERROR: 'CONTAINER_CLEAN_ERROR',
BOT_CONNECTED: 'BOT_CONNECTED',
// Chatbot Events
MESSAGE_SENTTOBOT: 'MESSAGE_SENTTOBOT',
MESSAGE_SENDTOBOT_ERROR: 'MESSAGE_SENDTOBOT_ERROR',
MESSAGE_RECEIVEDFROMBOT: 'MESSAGE_RECEIVEDFROMBOT',
MESSAGE_RECEIVEFROMBOT_ERROR: 'MESSAGE_RECEIVEFROMBOT_ERROR',
MESSAGE_ATTACHMENT: 'MESSAGE_ATTACHMENT',
MESSAGE_TRANSCRIPT: 'MESSAGE_TRANSCRIPT',
// Botium Agent Events
TOOMUCHWORKERS_ERROR: 'TOOMUCHWORKERS_ERROR'
};
function commonjsRequire () {
throw new Error('Dynamic requires are not currently supported by rollup-plugin-commonjs');
}
function createCommonjsModule(fn, module) {
return module = { exports: {} }, fn(module, module.exports), module.exports;
}
function getCjsExportFromNamespace (n) {
return n && n['default'] || n;
}
var LogicHookConsts = {
LOGIC_HOOK_INCLUDE: 'INCLUDE'
};
const debug = debug$h('botium-asserterUtils');
const {
LOGIC_HOOK_INCLUDE
} = LogicHookConsts;
const DEFAULT_ASSERTERS = [{
name: 'BUTTONS',
className: 'ButtonsAsserter'
}, {
name: 'MEDIA',
className: 'MediaAsserter'
}, {
name: 'CARDS',
className: 'CardsAsserter'
}, {
name: 'PAUSE_ASSERTER',
className: 'PauseAsserter'
}, {
name: 'ENTITIES',
className: 'EntitiesAsserter'
}, {
name: 'ENTITY_VALUES',
className: 'EntityValuesAsserter'
}, {
name: 'INTENT',
className: 'IntentAsserter'
}, {
name: 'INTENT_UNIQUE',
className: 'IntentUniqueAsserter'
}, {
name: 'INTENT_CONFIDENCE',
className: 'IntentConfidenceAsserter'
}, {
name: 'JSON_PATH',
className: 'JsonPathAsserter'
}];
DEFAULT_ASSERTERS.forEach(asserter => {
asserter.Class = commonjsRequire(`./asserter/${asserter.className}`);
});
const DEFAULT_LOGIC_HOOKS = [{
name: 'PAUSE',
className: 'PauseLogicHook'
}, {
name: 'WAITFORBOT',
className: 'WaitForBotLogicHook'
}, {
name: 'SET_SCRIPTING_MEMORY',
className: 'SetScriptingMemoryLogicHook'
}, {
name: 'CLEAR_SCRIPTING_MEMORY',
className: 'ClearScriptingMemoryLogicHook'
}, {
name: 'UPDATE_CUSTOM',
className: 'UpdateCustomLogicHook'
}, {
name: LOGIC_HOOK_INCLUDE,
className: 'IncludeLogicHook'
}];
DEFAULT_LOGIC_HOOKS.forEach(logicHook => {
logicHook.Class = commonjsRequire(`./logichooks/${logicHook.className}`);
});
const DEFAULT_USER_INPUTS = [{
name: 'BUTTON',
className: 'ButtonInput'
}, {
name: 'MEDIA',
className: 'MediaInput'
}, {
name: 'FORM',
className: 'FormInput'
}];
DEFAULT_USER_INPUTS.forEach(userInput => {
userInput.Class = commonjsRequire(`./userinput/${userInput.className}`);
});
var LogicHookUtils_1 = class LogicHookUtils {
constructor({
buildScriptContext,
caps
}) {
this.asserters = {};
this.globalAsserters = [];
this.logicHooks = {};
this.globalLogicHooks = [];
this.userInputs = {};
this.buildScriptContext = buildScriptContext;
this.caps = caps;
this._setDefaultAsserters();
this._setDefaultLogicHooks();
this._setDefaultUserInputs();
this._fetchAsserters();
this._fetchLogicHooks();
this._fetchUserInputs();
}
_setDefaultAsserters() {
DEFAULT_ASSERTERS.forEach(asserter => {
this.asserters[asserter.name] = new asserter.Class(this.buildScriptContext, this.caps);
});
debug(`Loaded Default asserter - ${util.inspect(Object.keys(this.asserters))}`);
}
_setDefaultLogicHooks() {
DEFAULT_LOGIC_HOOKS.forEach(lh => {
this.logicHooks[lh.name] = new lh.Class(this.buildScriptContext, this.caps);
});
debug(`Loaded Default logic hook - ${util.inspect(Object.keys(this.logicHooks))}`);
}
_setDefaultUserInputs() {
DEFAULT_USER_INPUTS.forEach(ui => {
this.userInputs[ui.name] = new ui.Class(this.buildScriptContext, this.caps);
});
debug(`Loaded Default user input - ${util.inspect(Object.keys(this.userInputs))}`);
}
_fetchAsserters() {
this.caps[Capabilities.ASSERTERS].map(asserter => {
if (this.asserters[asserter.ref]) {
debug(`${asserter.ref} asserter already exists, overwriting.`);
}
this.asserters[asserter.ref] = this._loadClass(asserter, 'asserter');
if (asserter.global) {
this.globalAsserters.push(asserter.ref);
debug(`global asserter: ${asserter.ref} was set and will be executed in every convo`);
}
});
}
_fetchLogicHooks() {
this.caps[Capabilities.LOGIC_HOOKS].map(logicHook => {
if (this.logicHooks[logicHook.ref]) {
debug(`${logicHook.ref} logic hook already exists, overwriting.`);
}
this.logicHooks[logicHook.ref] = this._loadClass(logicHook, 'logic-hook');
debug(`Loaded ${logicHook.ref} SUCCESSFULLY`);
if (logicHook.global) {
this.globalLogicHooks.push(logicHook.ref);
debug(`global logic hook: ${logicHook.ref} was set and will be executed in every convo`);
}
});
}
_fetchUserInputs() {
this.caps[Capabilities.USER_INPUTS].map(userInput => {
if (this.userInputs[userInput.ref]) {
debug(`${userInput.ref} userinput already exists, overwriting.`);
}
this.userInputs[userInput.ref] = this._loadClass(userInput, 'user-input');
debug(`Loaded ${userInput.ref} SUCCESSFULLY`);
});
}
getGlobalAsserter() {
return this.globalAsserters.map(name => this.asserters[name]);
}
getGlobalLogicHook() {
return this.globalLogicHooks.map(name => this.logicHooks[name]);
}
_loadClass({
src,
ref,
args
}, hookType) {
if (hookType !== 'asserter' && hookType !== 'logic-hook' && hookType !== 'user-input') {
throw Error(`Unknown hookType ${hookType}`);
} // 1 gives possibility to use default asserter as global asserter
if (hookType === 'asserter') {
const asserter = DEFAULT_ASSERTERS.find(asserter => src === asserter.className);
if (asserter) {
debug(`Loading ${ref} ${hookType}. Using default asserter ${asserter.className} as global asserter`);
return new asserter.Class(this.buildScriptContext, this.caps, args);
}
}
if (hookType === 'logic-hook') {
const lh = DEFAULT_LOGIC_HOOKS.find(lh => src === lh.className);
if (lh) {
debug(`Loading ${ref} ${hookType}. Using default logic-hook ${lh.className} as global logic-hook`);
return new lh.Class(this.buildScriptContext, this.caps, args);
}
}
if (hookType === 'user-input') {
const ui = DEFAULT_USER_INPUTS.find(ui => src === ui.className);
if (ui) {
debug(`Loading ${ref} ${hookType}. Using default user-input ${ui.className} as global user-input`);
return new ui.Class(this.buildScriptContext, this.caps, args);
}
}
if (!src) {
const packageName = `botium-${hookType}-${ref}`;
try {
const CheckClass = commonjsRequire(packageName);
if (isClass(CheckClass)) {
debug(`Loading ${ref} ${hookType}. Loading from ${packageName} as class. Guessed package name.`);
return new CheckClass(this.buildScriptContext, this.caps, args);
} else if (lodash.isFunction(CheckClass)) {
debug(`Loading ${ref} ${hookType}. Loading from ${packageName} as function. Guessed package name.`);
return CheckClass(this.buildScriptContext, this.caps, args);
} else {
throw new Error(`${packageName} class or function expected`);
}
} catch (err) {
throw new Error(`Failed to fetch package ${packageName} - ${util.inspect(err)}`);
}
}
if (isClass(src)) {
try {
const CheckClass = src;
debug(`Loading ${ref} ${hookType}. Using src as class.`);
return new CheckClass(this.buildScriptContext, this.caps, args);
} catch (err) {
throw new Error(`Failed to load package ${ref} from provided class - ${util.inspect(err)}`);
}
}
if (lodash.isFunction(src)) {
try {
debug(`Loading ${ref} ${hookType}. Using src as function.`);
return src(this.buildScriptContext, this.caps, args);
} catch (err) {
throw new Error(`Failed to load package ${ref} from provided function - ${util.inspect(err)}`);
}
}
if (lodash.isObject(src) && !lodash.isString(src)) {
try {
const hookObject = Object.keys(src).reduce((result, key) => {
result[key] = args => {
const script = src[key];
try {
const sandbox = vm.createContext({
debug,
console,
...args
});
vm.runInContext(script, sandbox);
return sandbox.result || Promise.resolve();
} catch (err) {
throw new Error(`Script "${key}" is not valid - ${util.inspect(err)}`);
}
};
return result;
}, {});
debug(`Loading ${ref} ${hookType}. Using src as function code.`);
return hookObject;
} catch (err) {
throw new Error(`Failed to load package ${ref} from provided function - ${util.inspect(err)}`);
}
}
const loadErr = [];
const tryLoadPackage = src;
try {
let CheckClass = commonjsRequire(tryLoadPackage);
if (CheckClass.default) {
CheckClass = CheckClass.default;
}
if (isClass(CheckClass)) {
debug(`Loading ${ref} ${hookType}. Using src for require. Loading from ${tryLoadPackage} as class`);
return new CheckClass(this.buildScriptContext, this.caps, args);
} else if (lodash.isFunction(CheckClass)) {
debug(`Loading ${ref} ${hookType}. Using src for require. Loading from ${tryLoadPackage} as class`);
return CheckClass(this.buildScriptContext, this.caps, args);
} else {
throw new Error(`${tryLoadPackage} class or function expected`);
}
} catch (err) {
loadErr.push(`Failed to fetch ${ref} ${hookType} from ${tryLoadPackage} - ${util.inspect(err)}`);
}
const tryLoadFile = path.resolve(process.cwd(), src);
try {
let CheckClass = commonjsRequire(tryLoadFile);
if (CheckClass.default) {
CheckClass = CheckClass.default;
}
if (isClass(CheckClass)) {
debug(`Loading ${ref} ${hookType}. Using src as relative path to module with a class. Loading from ${tryLoadFile} as class`);
return new CheckClass(this.buildScriptContext, this.caps, args);
} else if (lodash.isFunction(CheckClass)) {
debug(`Loading ${ref} ${hookType}. Using src as relative path to module with a function. Loading from ${tryLoadFile} as class`);
return CheckClass(this.buildScriptContext, this.caps, args);
} else {
throw new Error(`${tryLoadFile} class or function expected`);
}
} catch (err) {
loadErr.push(`Failed to fetch ${ref} ${hookType} from ${tryLoadFile} - ${util.inspect(err)} `);
}
loadErr.forEach(debug);
throw new Error(`Failed to fetch ${ref} ${hookType}, no idea how to load ...`);
}
};
var Constants = {
SCRIPTING_FORMAT_XSLX: 'SCRIPTING_FORMAT_XSLX',
SCRIPTING_FORMAT_TXT: 'SCRIPTING_FORMAT_TXT',
SCRIPTING_FORMAT_YAML: 'SCRIPTING_FORMAT_YAML',
SCRIPTING_FORMAT_CSV: 'SCRIPTING_FORMAT_CSV',
SCRIPTING_TYPE_CONVO: 'SCRIPTING_TYPE_CONVO',
SCRIPTING_TYPE_PCONVO: 'SCRIPTING_TYPE_PCONVO',
SCRIPTING_TYPE_UTTERANCES: 'SCRIPTING_TYPE_UTTERANCES',
SCRIPTING_TYPE_SCRIPTING_MEMORY: 'SCRIPTING_TYPE_SCRIPTING_MEMORY'
};
var BotiumMockAttachment_1 = class BotiumMockAttachment {
constructor(fromJson = {}) {
this.name = fromJson.name;
this.mimeType = fromJson.mimeType;
this.base64 = fromJson.base64;
}
};
class BotiumMockMedia {
constructor(fromJson = {}) {
this.mediaUri = fromJson.mediaUri;
this.mimeType = fromJson.mimeType;
this.altText = fromJson.altText;
}
}
class BotiumMockButton {
constructor(fromJson = {}) {
this.text = fromJson.text;
this.payload = fromJson.payload;
this.imageUri = fromJson.imageUri;
}
}
class BotiumMockCard {
constructor(fromJson = {}) {
this.text = fromJson.text;
this.subtext = fromJson.subtext;
this.content = fromJson.content;
this.image = fromJson.image ? new BotiumMockMedia(fromJson.image) : null;
this.buttons = fromJson.buttons ? fromJson.buttons.map(a => new BotiumMockButton(a)) : null;
this.media = fromJson.media ? fromJson.media.map(a => new BotiumMockMedia(a)) : null;
}
}
class BotiumMockForm {
constructor(fromJson = {}) {
this.name = fromJson.name;
this.value = fromJson.value;
}
}
var BotiumMockRichMessageTypes = {
BotiumMockMedia,
BotiumMockButton,
BotiumMockCard,
BotiumMockForm
};
class BotiumMockAsserter {
constructor(fromJson = {}) {
this.name = fromJson.name;
this.args = lodash.cloneDeep(fromJson.args);
}
}
class BotiumMockUserInput {
constructor(fromJson = {}) {
this.name = fromJson.name;
this.args = lodash.cloneDeep(fromJson.args);
}
}
class BotiumMockLogicHook {
constructor(fromJson = {}) {
this.name = fromJson.name;
this.args = lodash.cloneDeep(fromJson.args);
}
}
var BotiumMockScripting = {
BotiumMockAsserter,
BotiumMockUserInput,
BotiumMockLogicHook
};
const {
BotiumMockMedia: BotiumMockMedia$1,
BotiumMockButton: BotiumMockButton$1,
BotiumMockCard: BotiumMockCard$1,
BotiumMockForm: BotiumMockForm$1
} = BotiumMockRichMessageTypes;
const {
BotiumMockAsserter: BotiumMockAsserter$1,
BotiumMockUserInput: BotiumMockUserInput$1,
BotiumMockLogicHook: BotiumMockLogicHook$1
} = BotiumMockScripting;
var BotiumMockMessage_1 = class BotiumMockMessage {
constructor(fromJson = {}) {
this.sender = fromJson.sender;
this.channel = fromJson.channel;
this.messageText = fromJson.messageText;
this.media = fromJson.media ? fromJson.media.map(a => new BotiumMockMedia$1(a)) : null;
this.buttons = fromJson.buttons ? fromJson.buttons.map(a => new BotiumMockButton$1(a)) : null;
this.cards = fromJson.cards ? fromJson.cards.map(a => new BotiumMockCard$1(a)) : null;
this.forms = fromJson.forms ? fromJson.forms.map(a => new BotiumMockForm$1(a)) : null;
this.nlp = fromJson.nlp;
this.sourceData = fromJson.sourceData;
this.sourceAction = fromJson.sourceAction;
this.attachments = fromJson.attachments ? fromJson.attachments.map(a => new BotiumMockAttachment_1(a)) : null;
this.asserters = fromJson.asserters ? fromJson.asserters.map(a => new BotiumMockAsserter$1(a)) : null;
this.userInputs = fromJson.userInputs ? fromJson.userInputs.map(a => new BotiumMockUserInput$1(a)) : null;
this.logicHooks = fromJson.logicHooks ? fromJson.logicHooks.map(a => new BotiumMockLogicHook$1(a)) : null;
}
};
const debug$1 = debug$h('botium-ScriptingMemory'); // If they got parameter, then it will be a string always.
// the receiver can decide what to do with it,
// convert to int,
// split by ',' for multiple params,
// or something else
const SCRIPTING_FUNCTIONS = {
$now: () => {
return new Date().toLocaleString();
},
$now_EN: () => {
return new Date().toLocaleString('en-EN');
},
$now_DE: () => {
return moment().format('DD.MM.YYYY, HH:mm:ss');
},
$now_ISO: () => {
return new Date().toISOString();
},
$date: pattern => {
if (pattern) {
return moment().format(pattern);
}
return new Date().toLocaleDateString();
},
$date_EN: () => {
return new Date().toLocaleDateString('en-EN');
},
$date_DE: () => {
return moment().format('YYYY.MM.DD');
},
$date_ISO: () => {
return moment().format('YYYY-MM-DD');
},
$time: () => {
return new Date().toLocaleTimeString();
},
$time_EN: () => {
return new Date().toLocaleTimeString('en-EN');
},
$time_DE: () => {
return moment().format('HH:mm:ss');
},
$time_ISO: () => {
return moment().format('HH:mm:ss');
},
$time_HH_MM: () => {
return moment().format('HH:mm');
},
$time_HH: () => {
return moment().format('HH');
},
$time_H_A: () => {
return moment().format('h A');
},
$timestamp: () => {
return Date.now();
},
$year: () => {
return new Date().getFullYear();
},
$month: () => {
return moment().format('MMMM');
},
$month_MM: () => {
return moment().format('MM');
},
$day_of_month: () => {
return new Date().getDate();
},
$day_of_week: () => {
return moment().format('dddd');
},
$random: length => {
if (length == null) {
throw Error('random function used without args!');
}
return randomatic('0', length);
},
$random10: () => {
return randomatic('0', 10);
},
$uniqid: () => {
return v1();
},
$func: code => {
if (code == null) {
throw Error('func function used without args!');
}
try {
return vm.runInNewContext(code, {
debug: debug$1,
console: console,
require: commonjsRequire
});
} catch (err) {
throw Error(`func function execution failed - ${err}`);
}
}
};
const RESERVED_WORDS = Object.keys(SCRIPTING_FUNCTIONS);
const apply = (container, scriptingMemory, str) => {
if (container.caps[Capabilities.SCRIPTING_ENABLE_MEMORY]) {
str = _apply(scriptingMemory, str);
}
return str;
};
const applyToArgs = (args, scriptingMemory) => {
return (args || []).map(arg => {
return _apply(scriptingMemory, arg);
});
}; // we have two replace longer variable first. if there is $year, and $years, $years should not be found by $year
const _longestFirst = (a, b) => b.length - a.length;
const _apply = (scriptingMemory, str) => {
if (str) {
// merge all keys: longer is stronger, type does not matter
// Not clean: what if a variable references other variable/function?
const allKeys = Object.keys(SCRIPTING_FUNCTIONS).concat(Object.keys(scriptingMemory)).sort(_longestFirst);
for (const key of allKeys) {
// scripting memory is stronger
if (scriptingMemory[key]) {
str = str.replace(key, scriptingMemory[key]);
} else {
const regex = `\\${key}(\\(.+(?<!\\\\)\\))?`;
const matches = str.match(new RegExp(regex, 'g')) || [];
for (const match of matches) {
if (match.indexOf('(') > 0) {
const arg = match.substring(match.indexOf('(') + 1, match.lastIndexOf(')')).replace(/\\\)/g, ')');
str = str.replace(match, SCRIPTING_FUNCTIONS[key](arg));
} else {
str = str.replace(match, SCRIPTING_FUNCTIONS[key]());
}
}
}
}
}
return str;
};
const fill = (container, scriptingMemory, result, utterance, scriptingEvents) => {
debug$1(`fill start: ${util.inspect(scriptingMemory)}`);
let varRegex;
switch (container.caps[Capabilities.SCRIPTING_MEMORY_MATCHING_MODE]) {
case 'word':
varRegex = '(\\w+)';
break;
case 'joker':
varRegex = '([\\w\\W]+)';
break;
default:
varRegex = '(\\S+)';
break;
}
if (result && lodash.isString(result) && utterance && container.caps[Capabilities.SCRIPTING_ENABLE_MEMORY]) {
const utterances = scriptingEvents.resolveUtterance({
utterance
});
utterances.forEach(expected => {
let reExpected = expected;
if (container.caps[Capabilities.SCRIPTING_MATCHING_MODE] !== 'regexp') {
reExpected = lodash.isString(expected) ? expected.replace(/[-\\^*+?.()|[\]{}]/g, '\\$&') : expected;
}
const varMatches = ((lodash.isString(expected) ? expected.match(/\$[A-Za-z]\w+/g) : false) || []).sort(_longestFirst);
for (let i = 0; i < varMatches.length; i++) {
reExpected = reExpected.replace(varMatches[i], varRegex);
}
const resultMatches = result.match(reExpected) || [];
for (let i = 1; i < resultMatches.length; i++) {
if (i <= varMatches.length) {
const varName = varMatches[i - 1];
if (RESERVED_WORDS.indexOf(varName) >= 0) {
debug$1(`fill Variable "${varName}" is not overwritten, because it is reserved word. `);
} else {
scriptingMemory[varName] = resultMatches[i];
}
}
}
});
debug$1(`fill end: ${util.inspect(scriptingMemory)}`);
}
};
var ScriptingMemory = {
apply,
applyToArgs,
fill,
RESERVED_WORDS,
SCRIPTING_FUNCTIONS
};
const BotiumError = class BotiumError extends Error {
/**
*
* @param message
* @param context A JSON with struct
* {
* type: 'some free text to identity the exception type',
* source: 'source of the event',
* ...
*/
constructor(message, context, supressChildCheck) {
super(message.message || message);
if (!supressChildCheck && _getChildErrorsFromContext(context)) {
throw Error('Create BotiumError with child errors using the fromList() method!');
} // Saving class name in the property of our custom error as a shortcut.
this.name = this.constructor.name; // Capturing stack trace, excluding constructor call from it.
Error.captureStackTrace(this, this.constructor);
this.context = context || {};
this.context.message = message.message || message;
}
};
const _getChildErrorsFromContext = context => {
if (context && context.errors && lodash.isArray(context.errors)) {
return context.errors;
}
return false;
};
const _getChildErrorsFromError = error => {
if (error.context) {
return _getChildErrorsFromContext(error.context);
}
return false;
};
var getErrorsFromError = (error, safe = true) => {
const childErrors = _getChildErrorsFromError(error);
if (childErrors) {
return childErrors;
}
if (safe) {
return error;
}
throw Error('Invalid error format!');
};
const botiumErrorFromErr = (message, err) => {
if (err instanceof BotiumError) {
return new BotiumError(message, err.context, true);
} else {
return new BotiumError(message, {
err
}, true);
}
};
const botiumErrorFromList = (errors, {
type = 'list',
source = 'BotiumError',
flat = true
}) => {
const message = errors.map(err => err.message || err.toString()).join(',\n');
let children = [];
for (const error of errors) {
if (error instanceof BotiumError) {
const childErrors = flat && _getChildErrorsFromContext(error.context);
if (childErrors && childErrors.length) {
children = children.concat(childErrors);
} else if (error.context) {
children.push(error.context);
}
} else {
children.push(error);
}
}
const result = new BotiumError(message, {
errors: children,
type,
source
}, true);
return result;
};
var BotiumError_1 = {
BotiumError,
botiumErrorFromErr,
botiumErrorFromList
};
BotiumError_1.getErrorsFromError = getErrorsFromError;
const debug$2 = debug$h('botium-Convo');
const {
BotiumError: BotiumError$1,
botiumErrorFromErr: botiumErrorFromErr$1,
botiumErrorFromList: botiumErrorFromList$1
} = BotiumError_1;
const {
LOGIC_HOOK_INCLUDE: LOGIC_HOOK_INCLUDE$1
} = LogicHookConsts;
class ConvoHeader {
constructor(fromJson = {}) {
this.name = fromJson.name;
this.sort = fromJson.sort;
this.order = fromJson.order;
this.description = fromJson.description;
}
toString() {
return this.order + ' ' + this.name + (this.description ? ` (${this.description})` : '');
}
}
class ConvoStepAssert {
constructor(fromJson = {}) {
this.name = fromJson.name;
this.args = fromJson.args;
}
toString() {
return this.name + '(' + (this.args ? this.args.join(',') : 'no args') + ')';
}
}
class ConvoStepLogicHook {
constructor(fromJson = {}) {
this.name = fromJson.name;
this.args = fromJson.args;
}
toString() {
return this.name + '(' + (this.args ? this.args.join(',') : 'no args') + ')';
}
}
class ConvoStepUserInput {
constructor(fromJson = {}) {
this.name = fromJson.name;
this.args = fromJson.args;
}
toString() {
return this.name + '(' + (this.args ? this.args.join(',') : 'no args') + ')';
}
}
class ConvoStep {
constructor(fromJson = {}) {
this.sender = fromJson.sender;
this.channel = fromJson.channel;
this.messageText = fromJson.messageText;
this.sourceData = fromJson.sourceData;
this.stepTag = fromJson.stepTag;
this.not = fromJson.not;
this.asserters = lodash.map(fromJson.asserters, asserter => new ConvoStepAssert(asserter));
this.logicHooks = lodash.map(fromJson.logicHooks, logicHook => new ConvoStepLogicHook(logicHook));
this.userInputs = lodash.map(fromJson.userInputs, userInput => new ConvoStepUserInput(userInput));
}
hasInteraction() {
return this.messageText && this.messageText.length > 0 || this.sourceData || this.asserters && this.asserters.length > 0 || this.logicHooks && this.logicHooks.findIndex(l => l.name !== LOGIC_HOOK_INCLUDE$1) >= 0 || this.userInputs && this.userInputs.length > 0;
}
toString() {
return this.stepTag + ': #' + this.sender + ' - ' + (this.not ? '!' : '') + this.messageText + (this.asserters && this.asserters.length > 0 ? ' ' + this.asserters.map(a => a.toString()).join(' ASS: ') : '') + (this.logicHooks && this.logicHooks.length > 0 ? ' ' + this.logicHooks.map(l => l.toString()).join(' LH: ') : '') + (this.userInputs && this.userInputs.length > 0 ? ' ' + this.userInputs.map(u => u.toString()).join(' UI: ') : '');
}
}
class Transcript {
constructor({
steps,
scriptingMemory,
convoBegin,
convoEnd,
err
}) {
this.steps = steps;
this.scriptingMemory = scriptingMemory;
this.convoBegin = convoBegin;
this.convoEnd = convoEnd;
this.err = err;
}
}
class TranscriptStep {
constructor({
expected,
not,
actual,
stepBegin,
stepEnd,
botBegin,
botEnd,
err
}) {
this.expected = expected;
this.not = not;
this.actual = actual;
this.stepBegin = stepBegin;
this.stepEnd = stepEnd;
this.botBegin = botBegin;
this.botEnd = botEnd;
this.err = err;
}
}
class TranscriptError extends Error {
constructor(err, transcript) {
super(err.message);
this.name = this.constructor.name;
this.transcript = transcript;
this.cause = err;
Error.captureStackTrace(this, this.constructor);
}
}
class Convo {
constructor(context, fromJson = {}) {
if (fromJson instanceof Convo) {
debug$2('Illegal state!!! Parameter should be a JSON, but it is a Convo');
} else if (fromJson.beginAsserter) {
// beginAsserter is one of the fields which are lost
debug$2('Illegal state!!! Parameter should be a native JSON, but looks as a Convo converted to JSON');
}
this.scriptingEvents = context.scriptingEvents;
this.context = context;
this.header = new ConvoHeader(fromJson.header);
if (fromJson.conversation && lodash.isArray(fromJson.conversation)) {
this.conversation = lodash.map(fromJson.conversation, step => new ConvoStep(step));
} else {
this.conversation = [];
}
this.sourceTag = fromJson.sourceTag;
const {
beginAsserter,
endAsserter
} = this.setConvoBeginAndEndAsserter(fromJson);
this.beginAsserter = beginAsserter;
this.endAsserter = endAsserter;
const {
beginLogicHook,
endLogicHook
} = this.setConvoBeginAndEndLogicHook(fromJson);
this.beginLogicHook = beginLogicHook;
this.endLogicHook = endLogicHook;
this.effectiveConversation = null;
}
setConvoBeginAndEndAsserter(fromJson) {
const beginAsserter = fromJson.conversation.filter(s => s.sender === 'begin' && s.asserters && s.asserters.length > 0).map(s => s.asserters).reduce((acc, val) => acc.concat(val), []);
const endAsserter = fromJson.conversation.filter(s => s.sender === 'end' && s.asserters && s.asserters.length > 0).map(s => s.asserters).reduce((acc, val) => acc.concat(val), []);
return {
beginAsserter,
endAsserter
};
}
setConvoBeginAndEndLogicHook(fromJson) {
const beginLogicHook = fromJson.conversation.filter(s => s.sender === 'begin' && s.logicHooks && s.logicHooks.length > 0).map(s => s.logicHooks).reduce((acc, val) => acc.concat(val), []);
const endLogicHook = fromJson.conversation.filter(s => s.sender === 'end' && s.logicHooks && s.logicHooks.length > 0).map(s => s.logicHooks).reduce((acc, val) => acc.concat(val), []);
return {
beginLogicHook,
endLogicHook
};
}
toString() {
return this.header.toString() + (this.sourceTag ? ` (${util.inspect(this.sourceTag)})` : '') + ': ' + this.conversation.map(c => c.toString()).join(' | ');
}
Run(container) {
return new Promise((resolve, reject) => {
const scriptingMemory = {};
async.waterfall([// onConvoBegin first or assertConvoBegin? If onConvoBegin, then it is possible to assert it too
cb => {
this.scriptingEvents.onConvoBegin({
convo: this,
container,
scriptingMemory
}).then(() => cb()).catch(err => cb(botiumErrorFromErr$1(`${this.header.name}: error begin handler - ${err.message}`, err)));
}, cb => {
this.scriptingEvents.assertConvoBegin({
convo: