initial push

This commit is contained in:
notgne2 2019-08-08 22:09:03 -07:00
commit 09dae249ef
12 changed files with 1787 additions and 0 deletions

12
.editorconfig Normal file
View File

@ -0,0 +1,12 @@
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = space
indent_size = 2
[*.{bat,cmd}]
end_of_line = crlf

3
.eslintrc.json Normal file
View File

@ -0,0 +1,3 @@
{
"extends" : "@edenjs/eden"
}

22
.gitattributes vendored Normal file
View File

@ -0,0 +1,22 @@
# Automatically normalize line endings for all text-based files
# http://git-scm.com/docs/gitattributes#_end_of_line_conversion
* text=auto
# For the following file types, normalize line endings to LF on
# checkin and prevent conversion to CRLF when they are checked out
# (this is required in order to prevent newline related issues like,
# for example, after the build script is run)
.* text eol=lf
*.css text eol=lf
*.html text eol=lf
*.jade text eol=lf
*.js text eol=lf
*.json text eol=lf
*.less text eol=lf
*.scss text eol=lf
*.md text eol=lf
*.sh text eol=lf
*.txt text eol=lf
*.xml text eol=lf
*.bat text eol=crlf
*.cmd text eol=crlf

52
.gitignore vendored Normal file
View File

@ -0,0 +1,52 @@
# Debug log from npm
npm-debug.log
# Error log from yarn
yarn-error.log
# yarn lock - do work pls
yarn.lock
# nodejs modules
node_modules/
# edenjs stuff
data/
config.js
edenappconfig.js
# IDE
.idea
.remote-sync.json
# Log and Sentry
*.log
*.sentry
# Redis
*.rdb
# sqlite files
*.db
*.sdb
*.sqlite
*.db3
*.s3db
*.sqlite3
*.sl3
*.db2
*.s2db
*.sqlite2
*.sl2
# Other junk
.*.swp
._*
.DS_Store
.hg
.npmrc
.lock-wscript
.svn
.wafpickle-*
config.gypi
CVS

3
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"eslint.enable": true
}

View File

@ -0,0 +1,755 @@
const Daemon = require('daemon');
const config = require('config');
const messageArgsParser = require('parsers/chatbot/messageparts');
const { EventEmitter } = require('events');
const equal = require('deep-equal');
const User = model('user');
const Chat = model('chat');
const chatHelper = helper('chat');
const setChatDefaults = require('../includes/chatdefaults.js');
const EMOJI_LIST = ['🇦', '🇧', '🇨', '🇩', '🇪', '🇫', '🇬', '🇭', '🇮', '🇯', '🇰', '🇱', '🇲', '🇳', '🇴', '🇵', '🇶', '🇷', '🇸', '🇹', '🇺', '🇻', '🇼', '🇽', '🇾', '🇿'];
const CANCEL_EMOJI = '🚫';
async function carelessCall(fn) {
try { await fn(); } catch (_) { /* whocare */ }
}
/**
* Create Chat Bot Daemon Class
*
* @cluster bot
*/
class ChatBot extends Daemon {
/**
* Construct Chat Bot Daemon Class
*/
constructor() {
// Run super
super();
this._commandRegistry = [];
this._argRegistry = new Map();
this._responseRegistry = new Map();
this._events = new EventEmitter();
this._events.on('error', err => global.printError(err));
setChatDefaults(this);
// Run build
this.building = this.build();
this.eden.endpoint('chatbot.setResponse', async (...args) => {
return await this.setResponse(...args);
}, false);
this.eden.endpoint('chatbot.setArg', async (...args) => {
return await this.setArg(...args);
}, false);
this.eden.endpoint('chatbot.addCommand', async (...args) => {
return await this.addCommand(...args);
}, false);
this.eden.endpoint('chatbot.setStatus', async (...args) => {
return await this.setStatus(...args);
}, false);
this.eden.endpoint('chatbot.respond', async (...args) => {
return await this.respond(...args);
}, false);
this.eden.endpoint('chatbot.isReady', () => {
return true;
}, false);
this.eden.emit('chatbot.ready', false);
}
async setStatus(name) {
// i feel dirty
chatHelper.member.set(this._botUser, { get() { return ''; }, set() {} }, 'playing', name);
}
async _getResponse(responseName) {
let registeredResponse = this._responseRegistry.get(responseName);
if (!registeredResponse) {
registeredResponse = await new Promise(resolve => this._events.on(`addedResponse.${responseName}`, resolve));
}
return registeredResponse;
}
async setResponse(name, fn) {
const response = async (...responseArgs) => {
const getResponse = async a => this._getResponse(a);
return await fn(getResponse, ...responseArgs);
};
this._responseRegistry.set(name, response);
this._events.emit(`addedResponse.${name}`, response);
}
async setArg(typeName, opts) {
const arg = {
query : opts.query || (name => `Please enter \`${name}\``),
handle : opts.handle ? opts.handle : v => v,
getOptions : opts.getOptions || null,
strict : opts.strict || false,
strictCheck : opts.strictCheck || false,
schemas : opts.schemas || [],
};
this._argRegistry.set(typeName, arg);
this._events.emit(`addedArg.${typeName}`, arg);
}
async addCommand(rawSchemas, fn = null, desc = null, emoji = null, ver = 1) {
// If rawSchemas is singular wrap in an array
if (!(rawSchemas instanceof Array)) rawSchemas = [rawSchemas];
// Be able to handle addCommand(schemas, desc, emoji?, ver?)
if (typeof fn === 'string') {
ver = emoji;
emoji = desc;
desc = fn;
fn = null;
}
const schemas = rawSchemas.map((rawSchema) => {
let schema = [];
if (typeof rawSchema === 'string') {
for (const schemaPart of rawSchema.split(' ')) {
if (schemaPart[0] === '[' && schemaPart[schemaPart.length - 1] === ']') {
const [partName, argType] = schemaPart.slice(1, -1).split(':');
schema.push({ name : partName, argType });
} else {
schema.push({ type : 'text', text : schemaPart });
}
}
} else if (rawSchema instanceof Array) {
schema = rawSchema;
}
return schema;
});
// Wait for all args to be defined
for (const schema of schemas) {
for (const schemaPart of schema) {
if (schemaPart.name === undefined || schemaPart.name === null) continue;
if (!this._argRegistry.get(schemaPart.argType)) {
await new Promise(resolve => this._events.on(`addedArg.${schemaPart.argType}`, resolve));
}
}
}
this._commandRegistry.push({
schemas, fn, desc, emoji, ver,
});
}
async build() {
this.eden.on('eden.chat.message', async (messageData) => {
try { await this._onRawMesage(messageData); } catch (err) {
global.printError(err);
}
}, true);
this._botUser = await User.findById(config.get('chatbot.userId'));
}
async respond(chat, responseName, ...responseArgs) {
await this._respond(chat, responseName, ...responseArgs);
}
async dm(user, responseName, ...responseArgs) {
const chat = await chatHelper.create(user, [user, this._botUser], { type : 'dm' });
await this._respond(chat, responseName, ...responseArgs);
}
async _respond(chat, responseName, ...responseArgs) {
const registeredResponse = await this._getResponse(responseName);
const response = await registeredResponse(...responseArgs);
return await chatHelper.message.send(this._botUser, chat, {
message : response.message || '',
react : (response.reactions || []).reduce((a, c) => { a[c] = { [this._botUser.get('_id')] : new Date() }; return a; }, {}),
embeds : [{
primary : true,
buttons : response.buttons || [],
fields : response.fields || [],
image : response.image || null,
color : response.color || [],
thumbnail : response.thumbnail || null,
url : response.url || null,
title : response.title || null,
}],
});
}
async _callInputArgHandles(message, inputArg, argMap) {
const argDef = this._argRegistry.get(inputArg.commandArg.argType);
const matchingSchema = argDef.schemas.find(s => equal(this._argToSchema(inputArg.arg), s));
if (!matchingSchema) return [null, await this.respond(message.chat, 'badType')];
if (argDef.handle !== null) {
try {
const handleRes = await argDef.handle(inputArg.arg, message.from, argMap);
if (handleRes !== null && handleRes !== undefined) inputArg.arg = handleRes;
} catch (err) {
return [null, await this.respond(message.chat, 'handleError', err)];
}
}
if (argDef.strictCheck) {
const options = await argDef.getOptions(message.from, argMap);
if (!options.find(option => equal(option.val, inputArg.arg))) {
return [null, await this.respond(message.chat, 'badType')];
}
}
return [inputArg, null];
}
async _query(message, props) {
// Automatically enable strict if strict checking enabled
if (props.strictCheck) props.strict = true;
// If strict, handle having 1 or 0 options automatically
if (props.strict && props.options !== null) {
if (props.options.length === 1) {
return [props.options[0].val, true, null]; // lol
} if (props.options.length === 0) {
return [null, null, await this._respond(message.chat, 'noValidArg')];
}
}
await this.eden.set(`chatbot.awaitingreply.${message.from.get('_id')}`, this.eden.cluster + this.eden.id, 1000 * 40);
const safeOptions = props.options ? props.options.slice(0, 19) : [];
const buttons = safeOptions.map((option, i) => {
return {
emoji : option.emoji || EMOJI_LIST[i],
label : option.label,
id : i,
};
});
const rawQueryMessage = await this._respond(message.chat, 'query', {
message : props.message,
fields : safeOptions.length >= 1 ? [{
name : 'Options:',
text : safeOptions.map((option, i) => {
return `${option.emoji || EMOJI_LIST[i]} - **${option.label}** - ${option.desc}`;
}).join('\n'),
}] : [],
buttons : [{ emoji : CANCEL_EMOJI, label : 'cancel', id : 'cancel' }, ...buttons],
});
let [replyArg, replyButtonID, foundCommandData] = [null, null];
// Create promise and hoist the resolve and reject methods
let responsePromiseResolve = null;
let responsePromiseReject = null;
const responsePromise = new Promise((resolve, reject) => {
responsePromiseResolve = resolve;
responsePromiseReject = reject;
});
// Create timeout for this query
setTimeout(() => {
responsePromiseReject(new Error('timeout'));
}, 1000 * 35);
// Create listener for button presses
const buttonListener = ({ button, member }) => {
if (member !== message.from.get('_id')) return;
responsePromiseResolve([null, button.id, null]);
};
// Create listener for replies
const replyListener = (recievedReplyArgs, recievedReplyText) => {
if (recievedReplyArgs.length === 0) {
responsePromiseResolve([null, null, null]);
return;
}
const [registeredCommand, inputArgMap] = this._findRegisteredCommand(recievedReplyArgs);
if (recievedReplyArgs.length > 1 && registeredCommand !== null) {
responsePromiseResolve([null, null, [recievedReplyArgs, registeredCommand, inputArgMap]]);
} else if (props.allowText && recievedReplyArgs.length > 1 && recievedReplyArgs[0].type === 'text' && registeredCommand === null) {
responsePromiseResolve([{ type : 'text', text : recievedReplyText }, null, null]);
} else {
responsePromiseResolve([recievedReplyArgs[0], null, null]);
}
};
// Register the listeners to events
this._events.once(`reply.${message.from.get('_id')}`, replyListener);
this.eden.on(`eden.chat.message.buttonPress.${rawQueryMessage.get('_id')}`, buttonListener, true);
// Macro to remove listeners and the query message
const done = async () => {
try {
await this.eden.del(`chatbot.awaitingreply.${message.from.get('_id')}`);
carelessCall(async () => await chatHelper.message.remove(rawQueryMessage));
} catch (err) {
global.printError(err);
}
this._events.off(`reply.${message.from.get('_id')}`, replyListener);
this.eden.off(`eden.chat.message.buttonPress.${rawQueryMessage.get('_id')}`, buttonListener);
};
try {
[replyArg, replyButtonID, foundCommandData] = await responsePromise;
} catch (err) {
await done();
if (err.message === 'timeout') {
return [null, null, await this._respond(message.chat, 'queryTimeout')];
}
throw err;
}
await done();
if (replyArg !== null) {
if (replyArg.type === 'text' && replyArg.text === 'cancel') {
return [null, null, await this._respond(message.chat, 'argCancelled')];
}
if (safeOptions.find(o => equal(o.val, this._argToGeneric(replyArg)))) {
return [replyArg, true, null];
}
return [replyArg, false];
} if (replyButtonID !== null) {
if (replyButtonID === 'cancel') {
return [null, null, await this._respond(message.chat, 'argCancelled')];
}
return [safeOptions[replyButtonID].val, true, null];
}
if (foundCommandData !== null) {
const [args, registeredCommand, inputArgMap] = foundCommandData;
this._handleCommandData(message, args, registeredCommand, inputArgMap, null);
return [null, null, null];
}
return [null, null, await this._respond(message.chat, 'argMissing')];
}
async _queryForInputArg(message, missingArg, argMap, oldResponses = [], iters = 0) {
const argDef = this._argRegistry.get(missingArg.argType);
const options = argDef.getOptions ? await argDef.getOptions(message.from, argMap) : null;
const [res, exact, queryResponse] = await this._query(message, {
message : await argDef.query(missingArg.name),
allowText : argDef.schemas.find(schema => schema.type === 'text'),
strict : argDef.strict,
options,
});
oldResponses.forEach(async (response) => {
if (response) carelessCall(async () => await chatHelper.message.remove(response));
});
if (res !== null) {
const fullArg = {
arg : res,
commandArg : missingArg,
};
if (exact) return fullArg;
const [handledReply, handleResponse] = await this._callInputArgHandles(message, fullArg);
if (handledReply === null) {
const responses = [queryResponse, handleResponse];
return await this._queryForInputArg(message, missingArg, argMap, responses, iters + 1);
}
return handledReply;
}
return null;
}
async _queryForMatchArg(message, options, oldResponses = [], iters = 0) {
const [res, exact, queryResponse] = await this._query(message, {
message : 'Choose a command',
strict : true,
options,
});
oldResponses.forEach(async (response) => {
if (response) carelessCall(async () => await chatHelper.message.remove(response));
});
if (res === null) return null;
if (!exact) {
const response = await this._respond(message.chat, 'cnf');
return await this._queryForMatchArg(message, options, [response, queryResponse], iters + 1);
}
return res;
}
async _handleArgs(message, args) {
const findRes = this._findRegisteredCommand(args);
return await this._handleCommandData(message, args, ...findRes);
}
async _processInputArg(message, map, argName, arg) {
// Skip if entire input arg is null, not just the arg part, this is intentional
if (arg === null) {
map[argName] = null;
} else if (arg.arg === null) {
// Query to get the arg
const queryRes = await this._queryForInputArg(message, arg.commandArg, map);
// Return if the query was cancelled
if (queryRes === null) throw new Error('cancelled');
// Set arg in map to result
map[argName] = queryRes.arg;
} else {
// Handle the provided arg
const [handledInputArg, handleErrorResponse] = await this._callInputArgHandles(message, arg, map);
// If the arg was handled successfully
if (handledInputArg !== null) {
map[argName] = handledInputArg.arg;
} else {
// Query for a new arg instead
const queryRes = await this._queryForInputArg(message, arg.commandArg, map);
// Remove error message from handling
carelessCall(async () => await chatHelper.message.remove(handleErrorResponse));
// Return if the query was cancelled
if (queryRes === null) throw new Error('cancelled');
// Set arg in map to result
map[argName] = queryRes.arg;
}
}
}
async _handleCommandData(message, args, registeredCommand, inputArgMap, furtherMatches) {
if (furtherMatches) {
const options = furtherMatches.map(([furtherMatchCommand, furtherMatchArg]) => {
return {
label : furtherMatchArg.type === 'text' ? furtherMatchArg.text : furtherMatchArg.title,
val : furtherMatchArg,
desc : furtherMatchCommand.desc,
emoji : furtherMatchCommand.emoji,
};
});
const furtherRes = await this._queryForMatchArg(message, options);
if (furtherRes === null) throw new Error('dropped');
return await this._handleArgs(message, [...args, furtherRes]);
}
if (registeredCommand !== null && inputArgMap !== null) {
const processedInputArgMap = {};
for (const [inputArgName, inputArg] of Object.entries(inputArgMap)) {
try {
await this._processInputArg(message, processedInputArgMap, inputArgName, inputArg);
} catch (err) {
if (err.message === 'cancelled') throw new Error('dropped');
throw err;
}
}
// Create easy public response macro
const respondMacro = async (responseName, ...responseArgs) => {
await this.respond(message.chat, responseName, ...responseArgs);
};
// Create easy DM macro
const dmMacro = async (responseName, ...responseArgs) => {
await this.dm(message.from, responseName, ...responseArgs);
if (message.chat.get('type') !== 'dm') await respondMacro('dmNote');
};
// Create easy call macro
const callMacro = async (...callArgs) => {
return await this._handleArgs(message, callArgs);
};
// Create easy call macro
const queryMacro = async (...queryArgs) => {
return await this._query(message, ...queryArgs);
};
// Support legacy commands (oof)
if (registeredCommand.ver === 1) {
// Call the registered function
return await registeredCommand.fn(respondMacro,
new Proxy(processedInputArgMap, { get(k, v) { return (k[v] || null); } }),
message.from,
callMacro,
queryMacro);
}
return await registeredCommand.fn({
public : respondMacro,
dm : dmMacro,
respond : respondMacro,
args : new Proxy(processedInputArgMap, { get(k, v) { return (k[v] || null); } }),
from : message.from,
call : callMacro,
query : queryMacro,
isDM : message.chat.get('type') === 'dm',
});
}
// Respond with command not found
await this.respond(message.chat, 'cnf');
throw new Error('dropped');
}
_commandMatchArgToGeneric({
name, type, id, tag, text,
}) {
// Return if this is an input arg, not a match arg
if (name !== null && name !== undefined) return null;
if (type === 'tag') return { type, id, tag };
if (type === 'text') return { type, text };
return {}; // UNIMPLEMENTED
}
// Create generic form of arg, will equal to match args
_argToGeneric({
type, id, tag, text,
}) {
if (type === 'tag') return { type, id, tag };
if (type === 'text') return { type, text };
return {}; // UNIMPLEMENTED
}
// Create schema form of arg, will equal to input args/schemas
_argToSchema({ type, tag }) {
if (type === 'tag') return { type, tag };
if (type === 'text') return { type };
return {}; // UNIMPLEMENTED
}
_findLongerRegisteredCommand(args) {
const matching = [];
for (const registeredCommand of this._commandRegistry) {
// Skip unlisted commands
if (registeredCommand.desc === null) continue;
for (const schema of registeredCommand.schemas) {
// Get position of the first input arg, defaulting to the end if not existing
let firstCommandInputArgPosition = schema
.findIndex(commandArg => commandArg.name !== null && commandArg.name !== undefined);
if (firstCommandInputArgPosition === -1) firstCommandInputArgPosition = schema.length;
// Check if there are match args existing after the first input arg
const matchAfterInput = !!schema
.slice(firstCommandInputArgPosition + 1)
.find(commandArg => commandArg.name === null || commandArg.name === undefined);
// Skip if match after inputs found
if (matchAfterInput) continue;
// Shorten the command arguments to the first input arg
const shorterCommandMatchArgs = schema
.slice(0, firstCommandInputArgPosition - 1)
.map(commandArg => this._commandMatchArgToGeneric(commandArg));
// Convert args to generic so they can be used to match
const potentialMatchArgs = args
.map(arg => this._argToGeneric(arg));
// Check if our potential args match the shortened command args
if (equal(shorterCommandMatchArgs, potentialMatchArgs)) {
// Get the part of the command cut off to produce the match
const trailingCommandMatchArg = schema[firstCommandInputArgPosition - 1];
// Add to list of matching
matching.push([registeredCommand, trailingCommandMatchArg]);
// Skip all other schemas for this command
break;
}
}
}
return matching;
}
_findRegisteredCommand(args) {
for (const registeredCommand of this._commandRegistry) {
// Skip if not a real command
if (registeredCommand.fn === null) continue;
for (const schema of registeredCommand.schemas) {
// List of match args for command (remove input args/nulls)
const commandMatchArgs = schema
.map(commandArg => this._commandMatchArgToGeneric(commandArg));
// Get provided args in positions the command's match args are in
const potentialMatchArgs = schema
.map((commandArg, i) => {
if (commandArg.name !== null && commandArg.name !== undefined) return null;
return args[i] ? this._argToGeneric(args[i]) : null;
});
// Check if our match args match up to the command's match args
if (equal(commandMatchArgs, potentialMatchArgs)) {
// Iterate the required args and make a formatted input arg from the input
const inputArgMap = schema
.map((commandArg, i) => {
if (commandArg.name === null || commandArg.name === undefined) return null;
// Check if there are multiple trailing args, and this is the last text arg
if (args.length > (i + 2) && args[i] && args[i].type === 'text' && (i + 1) === schema.length) {
// Check registered info for command to check if last arg can be command
const canBeText = !!this._argRegistry.get(commandArg.argType).schemas
.find(argSchema => argSchema.type === 'text');
// Check that all following tags are also text
const restAreText = !args
.slice(i + 1)
.find(arg => arg.type !== 'text');
// Set the arg to be all remaining args if can be text and rest are text
if (canBeText && restAreText) {
args[i].text = args.slice(i).map(arg => arg.raw + arg.rawSep).join('');
}
}
return { commandArg, arg : args[i] || null };
})
.filter(arg => arg !== null)
.reduce((map, arg) => {
map[arg.commandArg.name] = arg;
return map;
}, {});
// Return the registered command, and the map of input args
return [registeredCommand, inputArgMap];
}
}
}
// Return with longer matching commands if found
const matching = this._findLongerRegisteredCommand(args);
if (matching.length > 0) return [null, null, matching];
return [null, null, null];
}
// go get em jimmy
async _fightForMessage(rawMessage) {
const myId = this.eden.cluster + this.eden.id;
const awaitingReplyData = await this.eden.get(`chatbot.awaitingreply.${rawMessage.from}`);
if (awaitingReplyData && awaitingReplyData === myId) {
// This should be a reply, and its for us
return 2;
} if (awaitingReplyData && awaitingReplyData !== myId) {
// This should be a reply, and its not for us
return 0;
}
const unlockMessage = await this.eden.lock(`chatbot.message.${rawMessage.id}`);
const dist = await this.eden.get('chatbot.distribution.*') || {};
// if (!Object.values(dist).find(chats => chats.length < dist[myId].length)) {
if (!Object.values(dist).find(count => count < dist[myId])) {
// await this.eden.set(`chat.distribution.${myId}`, [...dist[myId], rawMessage.get('_id')]);
// await this.eden.incr(`chat.distribution.${myId}`);
await this.eden.set(`chatbot.distribution.${myId}`, (dist[myId] || 0) + 1);
unlockMessage();
return 1;
}
unlockMessage();
return 0;
}
async _onRawMesage(rawMessage) {
await this.building;
// Return if its empty
if (rawMessage.raw.length === 0) return;
// Return if its from us
if (rawMessage.from === this._botUser.get('_id')) return;
// Fight over the message
const messageFightRes = await this._fightForMessage(rawMessage);
// Return if we did not win the fight
if (messageFightRes === 0) return;
// TODO Add automatic invalidation
const basicChatInfo = await this.eden.get(`chatbot.basicchatinfo.${rawMessage.chat}`, async () => {
const chat = await Chat.findById(rawMessage.chat);
return {
isInChat : !!chat.get().members.find(c => c.id === this._botUser.get('_id')),
isDM : chat.get('type') === 'private',
};
});
// if we're not in the chat somehow, ignore
if (!basicChatInfo.isInChat) return;
// Use pegjs parser to parse message arguments
const { args, leadingSep } = messageArgsParser.parse(rawMessage.raw);
// Detect if message is a command
const isCommand = leadingSep.length <= 0 && config.get('chatbot.commandArgs').find(cmdArg => equal(cmdArg, this._argToGeneric(args[0])));
// If its not a DM or a command its not worth our time, return
if (!isCommand && !basicChatInfo.isDM) return;
// trim the first arg if this is a command (ex: removing .gm8)
if (isCommand) args.shift();
// Check if its a reply to us, or just a normal command
if (messageFightRes === 2) {
// Rebuild text from the remaining args
const text = leadingSep + args.map(arg => arg.raw + arg.rawSep).join('');
this._events.emit(`reply.${rawMessage.from}`, args, text);
} else {
try {
await this._handleArgs({
chat : await Chat.findById(rawMessage.chat),
from : await User.findById(rawMessage.from),
}, args);
} catch (err) {
if (err.message === 'dropped') return;
throw err;
}
}
}
}
module.exports = ChatBot;

View File

@ -0,0 +1,80 @@
const Helper = require('helper');
/**
* extend chat bot helper
*
* @extends {helper}
*/
class ChatBotHelper extends Helper {
async waitReady() {
return await new Promise((resolve) => {
const done = () => {
resolve();
this.eden.off('chatbot.ready', done);
};
this.eden.once('chatbot.ready', done);
this.eden.call('chatbot.isReady', false).then(done);
});
}
async setResponse(name, fn) {
return await this.eden.call('chatbot.setResponse', name, fn, false);
}
async setArg(typeName, opts) {
return await this.eden.call('chatbot.setArg', typeName, opts, false);
}
async addCommand(schemas, fn = null, description = null, emoji = null, ver = 1) {
return await this.eden.call('chatbot.addCommand', schemas, fn, description, emoji, ver, false);
}
async setStatus(name) {
return await this.eden.call('chatbot.setStatus', name, false);
}
async respond(chat, responseName, ...responseArgs) {
return await this.eden.call('chatbot.respond', chat, responseName, ...responseArgs, false);
}
async loadTagArg(tagArg) {
const m = await model(tagArg.tag).findById(tagArg.id);
return {
title : tagArg.title,
model : m,
};
}
unloadTagArg(loadedTag) {
return {
title : loadedTag.title,
tag : loadedTag.model.constructor.name.toLowerCase(),
id : loadedTag.model.get('_id').toString(),
};
}
tagArgToText(tagArg) {
return `<${tagArg.tag}:${tagArg.title}|${tagArg.id}>`;
}
argToText(arg) {
if (arg.type === 'text') {
return arg.text;
}
return this.tagArgToText(arg);
}
loadedTagArgToText(loadedTag) {
return this.tagArgToText(this.unloadTagArg(loadedTag));
}
}
/**
* export built chat bot helper
*
* @type {ChatBotHelper}
*/
module.exports = new ChatBotHelper();

View File

@ -0,0 +1,4 @@
module.exports = function setChatDefaults() {
// This is just a placeholder, so you can overwrite it
};

View File

@ -0,0 +1,52 @@
Value
= leadingSep:[ \t\n\r]* args:(
arg:Arg sep:[ \t\n\r]*
{ return [arg, sep.join('')]; }
)* lastArg:Arg?
{
return {
args: (lastArg !== null ? [...args, [lastArg, '']] : args).map(([arg, sep]) => {
return Object.assign({}, arg, {
rawSep: sep,
});
}),
leadingSep: leadingSep.join(''),
}
}
Arg
= '<' tagChars:TagNameCharacter+ ':' titleChars:TagTitleCharacter+ '|' idChars:TagIdCharacter+ '>' {
return {
type: 'tag',
id: idChars.join(''),
tag: tagChars.join(''),
title: titleChars.join(''),
raw: text(),
};
}
/ textArg:TextArg { return { type: 'text', text: textArg, raw: text(), }; }
TagNameCharacter
= !([ \t\n\r] / ':' / '\\') char:. { return char; }
/ "\\" sequence:(':' / "\\") { return sequence; }
TagTitleCharacter
= !([\t\n\r] / '|' / '\\') char:. { return char; }
/ "\\" sequence:('|' / "\\") { return sequence; }
TagIdCharacter
= !([ \t\n\r] / '>' / '\\') char:. { return char; }
/ "\\" sequence:('"' / ">") { return sequence; }
TextArg
= '"' chars:DoubleStringCharacter+ '"' !([^ \t\n\r]) { return chars.join(''); }
/ chars:TextCharacter+ { return chars.join(''); }
DoubleStringCharacter
= !('"' / "\\") char:. { return char; }
/ "\\" sequence:('"' / "\\") { return sequence; }
TextCharacter
= !([ \t\n\r] / "\\") char:. { return char; }
/ "\\" char:. { return char; }
/ "\\" { return "\\"; }

3
edenconfig.js Normal file
View File

@ -0,0 +1,3 @@
const config = {};
module.exports = config;

781
package-lock.json generated Normal file
View File

@ -0,0 +1,781 @@
{
"name": "@edenup/chatbot",
"version": "1.0.8",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@edenjs/eslint-config-eden": {
"version": "2.0.14",
"resolved": "https://registry.npmjs.org/@edenjs/eslint-config-eden/-/eslint-config-eden-2.0.14.tgz",
"integrity": "sha512-NkKUXO0U118uzsmPrBkPbBAKl4zhLjgyq3qv2AUjaS+Vbz2pa8o4/bi8yqhx16ZDJgfWoSc6ko9FWsXrwDM26g==",
"dev": true
},
"@edenjs/peg": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@edenjs/peg/-/peg-1.0.2.tgz",
"integrity": "sha512-uUNcZ3dJCbuFDlq9cQXD0+zkCs6/seW2BFiW9XHYsokDfKDpP38S8/aWkevTF6hULzdNgfMIgtz/f/8A7uUOtA==",
"requires": {
"gulp-pegjs": "^0.1.0",
"gulp-rename": "^1.4.0"
}
},
"ansi-gray": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz",
"integrity": "sha1-KWLPVOyXksSFEKPetSRDaGHvclE=",
"requires": {
"ansi-wrap": "0.1.0"
}
},
"ansi-wrap": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz",
"integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768="
},
"aria-query": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-3.0.0.tgz",
"integrity": "sha1-ZbP8wcoRVajJrmTW7uKX8V1RM8w=",
"dev": true,
"requires": {
"ast-types-flow": "0.0.7",
"commander": "^2.11.0"
}
},
"array-differ": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz",
"integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE="
},
"array-includes": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz",
"integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=",
"dev": true,
"requires": {
"define-properties": "^1.1.2",
"es-abstract": "^1.7.0"
}
},
"array-uniq": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
"integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY="
},
"ast-types-flow": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz",
"integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=",
"dev": true
},
"axobject-query": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.0.2.tgz",
"integrity": "sha512-MCeek8ZH7hKyO1rWUbKNQBbl4l2eY0ntk7OGi+q0RlafrCnfPxC06WZA+uebCfmYp4mNU9jRBP1AhGyf8+W3ww==",
"dev": true,
"requires": {
"ast-types-flow": "0.0.7"
}
},
"beeper": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz",
"integrity": "sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak="
},
"clone": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
"integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4="
},
"clone-stats": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz",
"integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE="
},
"color-support": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz",
"integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg=="
},
"commander": {
"version": "2.19.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz",
"integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==",
"dev": true
},
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
},
"damerau-levenshtein": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.4.tgz",
"integrity": "sha1-AxkcQyy27qFou3fzpV/9zLiXhRQ=",
"dev": true
},
"dateformat": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/dateformat/-/dateformat-2.2.0.tgz",
"integrity": "sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI="
},
"deep-equal": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz",
"integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU="
},
"define-properties": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
"integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
"dev": true,
"requires": {
"object-keys": "^1.0.12"
}
},
"duplexer2": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz",
"integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=",
"requires": {
"readable-stream": "~1.1.9"
}
},
"emoji-regex": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
"integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
"dev": true
},
"es-abstract": {
"version": "1.13.0",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz",
"integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==",
"dev": true,
"requires": {
"es-to-primitive": "^1.2.0",
"function-bind": "^1.1.1",
"has": "^1.0.3",
"is-callable": "^1.1.4",
"is-regex": "^1.0.4",
"object-keys": "^1.0.12"
}
},
"es-to-primitive": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz",
"integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==",
"dev": true,
"requires": {
"is-callable": "^1.1.4",
"is-date-object": "^1.0.1",
"is-symbol": "^1.0.2"
}
},
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
},
"eslint-config-airbnb": {
"version": "17.1.0",
"resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-17.1.0.tgz",
"integrity": "sha512-R9jw28hFfEQnpPau01NO5K/JWMGLi6aymiF6RsnMURjTk+MqZKllCqGK/0tOvHkPi/NWSSOU2Ced/GX++YxLnw==",
"dev": true,
"requires": {
"eslint-config-airbnb-base": "^13.1.0",
"object.assign": "^4.1.0",
"object.entries": "^1.0.4"
}
},
"eslint-config-airbnb-base": {
"version": "13.1.0",
"resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-13.1.0.tgz",
"integrity": "sha512-XWwQtf3U3zIoKO1BbHh6aUhJZQweOwSt4c2JrPDg9FP3Ltv3+YfEv7jIDB8275tVnO/qOHbfuYg3kzw6Je7uWw==",
"dev": true,
"requires": {
"eslint-restricted-globals": "^0.1.1",
"object.assign": "^4.1.0",
"object.entries": "^1.0.4"
}
},
"eslint-plugin-jsx-a11y": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.2.1.tgz",
"integrity": "sha512-cjN2ObWrRz0TTw7vEcGQrx+YltMvZoOEx4hWU8eEERDnBIU00OTq7Vr+jA7DFKxiwLNv4tTh5Pq2GUNEa8b6+w==",
"dev": true,
"requires": {
"aria-query": "^3.0.0",
"array-includes": "^3.0.3",
"ast-types-flow": "^0.0.7",
"axobject-query": "^2.0.2",
"damerau-levenshtein": "^1.0.4",
"emoji-regex": "^7.0.2",
"has": "^1.0.3",
"jsx-ast-utils": "^2.0.1"
}
},
"eslint-plugin-react": {
"version": "7.12.4",
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.12.4.tgz",
"integrity": "sha512-1puHJkXJY+oS1t467MjbqjvX53uQ05HXwjqDgdbGBqf5j9eeydI54G3KwiJmWciQ0HTBacIKw2jgwSBSH3yfgQ==",
"dev": true,
"requires": {
"array-includes": "^3.0.3",
"doctrine": "^2.1.0",
"has": "^1.0.3",
"jsx-ast-utils": "^2.0.1",
"object.fromentries": "^2.0.0",
"prop-types": "^15.6.2",
"resolve": "^1.9.0"
},
"dependencies": {
"doctrine": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
"integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
"dev": true,
"requires": {
"esutils": "^2.0.2"
}
}
}
},
"eslint-restricted-globals": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/eslint-restricted-globals/-/eslint-restricted-globals-0.1.1.tgz",
"integrity": "sha1-NfDVy8ZMLj7WLpO0saevBbp+1Nc=",
"dev": true
},
"esutils": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
"integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
"dev": true
},
"fancy-log": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz",
"integrity": "sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==",
"requires": {
"ansi-gray": "^0.1.1",
"color-support": "^1.1.3",
"parse-node-version": "^1.0.0",
"time-stamp": "^1.0.0"
}
},
"function-bind": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
"dev": true
},
"glogg": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.2.tgz",
"integrity": "sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA==",
"requires": {
"sparkles": "^1.0.0"
}
},
"gulp-pegjs": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/gulp-pegjs/-/gulp-pegjs-0.1.0.tgz",
"integrity": "sha1-gwFY7q6OcwFx1E3N6xyiDH83FOo=",
"requires": {
"gulp-util": "^3.0.6",
"object-assign": "^4.0.1",
"pegjs": "^0.10.0",
"through2": "^2.0.1"
}
},
"gulp-rename": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/gulp-rename/-/gulp-rename-1.4.0.tgz",
"integrity": "sha512-swzbIGb/arEoFK89tPY58vg3Ok1bw+d35PfUNwWqdo7KM4jkmuGA78JiDNqR+JeZFaeeHnRg9N7aihX3YPmsyg=="
},
"gulp-util": {
"version": "3.0.8",
"resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz",
"integrity": "sha1-AFTh50RQLifATBh8PsxQXdVLu08=",
"requires": {
"array-differ": "^1.0.0",
"array-uniq": "^1.0.2",
"beeper": "^1.0.0",
"chalk": "^1.0.0",
"dateformat": "^2.0.0",
"fancy-log": "^1.1.0",
"gulplog": "^1.0.0",
"has-gulplog": "^0.1.0",
"lodash._reescape": "^3.0.0",
"lodash._reevaluate": "^3.0.0",
"lodash._reinterpolate": "^3.0.0",
"lodash.template": "^3.0.0",
"minimist": "^1.1.0",
"multipipe": "^0.1.2",
"object-assign": "^3.0.0",
"replace-ext": "0.0.1",
"through2": "^2.0.0",
"vinyl": "^0.5.0"
},
"dependencies": {
"ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
},
"ansi-styles": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
"integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4="
},
"chalk": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"requires": {
"ansi-styles": "^2.2.1",
"escape-string-regexp": "^1.0.2",
"has-ansi": "^2.0.0",
"strip-ansi": "^3.0.0",
"supports-color": "^2.0.0"
}
},
"minimist": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
},
"object-assign": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz",
"integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I="
},
"strip-ansi": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"requires": {
"ansi-regex": "^2.0.0"
}
},
"supports-color": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
"integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc="
}
}
},
"gulplog": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz",
"integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=",
"requires": {
"glogg": "^1.0.0"
}
},
"has": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
"dev": true,
"requires": {
"function-bind": "^1.1.1"
}
},
"has-ansi": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
"integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
"requires": {
"ansi-regex": "^2.0.0"
},
"dependencies": {
"ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
}
}
},
"has-gulplog": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz",
"integrity": "sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4=",
"requires": {
"sparkles": "^1.0.0"
}
},
"has-symbols": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz",
"integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=",
"dev": true
},
"inherits": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
},
"is-callable": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz",
"integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==",
"dev": true
},
"is-date-object": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz",
"integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=",
"dev": true
},
"is-regex": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz",
"integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=",
"dev": true,
"requires": {
"has": "^1.0.1"
}
},
"is-symbol": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz",
"integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==",
"dev": true,
"requires": {
"has-symbols": "^1.0.0"
}
},
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
},
"js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
"dev": true
},
"jsx-ast-utils": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.0.1.tgz",
"integrity": "sha1-6AGxs5mF4g//yHtA43SAgOLcrH8=",
"dev": true,
"requires": {
"array-includes": "^3.0.3"
}
},
"lodash._basecopy": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz",
"integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY="
},
"lodash._basetostring": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz",
"integrity": "sha1-0YYdh3+CSlL2aYMtyvPuFVZqB9U="
},
"lodash._basevalues": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz",
"integrity": "sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc="
},
"lodash._getnative": {
"version": "3.9.1",
"resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz",
"integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U="
},
"lodash._isiterateecall": {
"version": "3.0.9",
"resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz",
"integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw="
},
"lodash._reescape": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz",
"integrity": "sha1-Kx1vXf4HyKNVdT5fJ/rH8c3hYWo="
},
"lodash._reevaluate": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz",
"integrity": "sha1-WLx0xAZklTrgsSTYBpltrKQx4u0="
},
"lodash._reinterpolate": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz",
"integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0="
},
"lodash._root": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz",
"integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI="
},
"lodash.escape": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz",
"integrity": "sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg=",
"requires": {
"lodash._root": "^3.0.0"
}
},
"lodash.isarguments": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
"integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo="
},
"lodash.isarray": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz",
"integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U="
},
"lodash.keys": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz",
"integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=",
"requires": {
"lodash._getnative": "^3.0.0",
"lodash.isarguments": "^3.0.0",
"lodash.isarray": "^3.0.0"
}
},
"lodash.restparam": {
"version": "3.6.1",
"resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz",
"integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU="
},
"lodash.template": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz",
"integrity": "sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8=",
"requires": {
"lodash._basecopy": "^3.0.0",
"lodash._basetostring": "^3.0.0",
"lodash._basevalues": "^3.0.0",
"lodash._isiterateecall": "^3.0.0",
"lodash._reinterpolate": "^3.0.0",
"lodash.escape": "^3.0.0",
"lodash.keys": "^3.0.0",
"lodash.restparam": "^3.0.0",
"lodash.templatesettings": "^3.0.0"
}
},
"lodash.templatesettings": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz",
"integrity": "sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU=",
"requires": {
"lodash._reinterpolate": "^3.0.0",
"lodash.escape": "^3.0.0"
}
},
"loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
"dev": true,
"requires": {
"js-tokens": "^3.0.0 || ^4.0.0"
}
},
"multipipe": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz",
"integrity": "sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s=",
"requires": {
"duplexer2": "0.0.2"
}
},
"object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
},
"object-keys": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.0.tgz",
"integrity": "sha512-6OO5X1+2tYkNyNEx6TsCxEqFfRWaqx6EtMiSbGrw8Ob8v9Ne+Hl8rBAgLBZn5wjEz3s/s6U1WXFUFOcxxAwUpg==",
"dev": true
},
"object.assign": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz",
"integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==",
"dev": true,
"requires": {
"define-properties": "^1.1.2",
"function-bind": "^1.1.1",
"has-symbols": "^1.0.0",
"object-keys": "^1.0.11"
}
},
"object.entries": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.0.tgz",
"integrity": "sha512-l+H6EQ8qzGRxbkHOd5I/aHRhHDKoQXQ8g0BYt4uSweQU1/J6dZUOyWh9a2Vky35YCKjzmgxOzta2hH6kf9HuXA==",
"dev": true,
"requires": {
"define-properties": "^1.1.3",
"es-abstract": "^1.12.0",
"function-bind": "^1.1.1",
"has": "^1.0.3"
}
},
"object.fromentries": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.0.tgz",
"integrity": "sha512-9iLiI6H083uiqUuvzyY6qrlmc/Gz8hLQFOcb/Ri/0xXFkSNS3ctV+CbE6yM2+AnkYfOB3dGjdzC0wrMLIhQICA==",
"dev": true,
"requires": {
"define-properties": "^1.1.2",
"es-abstract": "^1.11.0",
"function-bind": "^1.1.1",
"has": "^1.0.1"
}
},
"parse-node-version": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz",
"integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA=="
},
"path-parse": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
"integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
"dev": true
},
"pegjs": {
"version": "0.10.0",
"resolved": "https://registry.npmjs.org/pegjs/-/pegjs-0.10.0.tgz",
"integrity": "sha1-z4uvrm7d/0tafvsYUmnqr0YQ3b0="
},
"process-nextick-args": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw=="
},
"prop-types": {
"version": "15.7.2",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
"integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
"dev": true,
"requires": {
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
"react-is": "^16.8.1"
}
},
"react-is": {
"version": "16.8.4",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.4.tgz",
"integrity": "sha512-PVadd+WaUDOAciICm/J1waJaSvgq+4rHE/K70j0PFqKhkTBsPv/82UGQJNXAngz1fOQLLxI6z1sEDmJDQhCTAA==",
"dev": true
},
"readable-stream": {
"version": "1.1.14",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
"integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.1",
"isarray": "0.0.1",
"string_decoder": "~0.10.x"
},
"dependencies": {
"isarray": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
}
}
},
"replace-ext": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz",
"integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ="
},
"resolve": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz",
"integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==",
"dev": true,
"requires": {
"path-parse": "^1.0.6"
}
},
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"sparkles": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz",
"integrity": "sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw=="
},
"string_decoder": {
"version": "0.10.31",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
},
"through2": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
"integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==",
"requires": {
"readable-stream": "~2.3.6",
"xtend": "~4.0.1"
},
"dependencies": {
"readable-stream": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"requires": {
"safe-buffer": "~5.1.0"
}
}
}
},
"time-stamp": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz",
"integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM="
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
},
"vinyl": {
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz",
"integrity": "sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4=",
"requires": {
"clone": "^1.0.0",
"clone-stats": "^0.0.1",
"replace-ext": "0.0.1"
}
},
"xtend": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
"integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68="
}
}
}

20
package.json Normal file
View File

@ -0,0 +1,20 @@
{
"name": "wizbos-chatbot",
"description": "nothing yet",
"version": "1.0.8",
"dependencies": {
"@edenjs/peg": "^1.0.2",
"deep-equal": "^1.0.1"
},
"engines": {
"node": ">= 8.0.0"
},
"devDependencies": {
"eslint": "^6.0.1",
"@edenjs/eslint-config-eden": "^2.0.14",
"eslint-config-airbnb": "^17.1.1",
"eslint-plugin-import": "^2.18.0",
"eslint-plugin-jsx-a11y": "^6.2.3",
"eslint-plugin-react": "^7.14.2"
}
}