From 9a90793e7f33e0b717e1b1a7a5da3c71c9a1d5c6 Mon Sep 17 00:00:00 2001 From: German Attanasio Date: Mon, 6 May 2019 12:33:11 -0400 Subject: [PATCH] feat: add lib folder and address review --- .gitignore | 1 - README.md | 18 +- examples/simple-bot/package.json | 2 +- lib/index.d.ts | 67 +++ lib/index.js | 153 +++++ lib/index.js.map | 1 + lib/utils.d.ts | 25 + lib/utils.js | 78 +++ lib/utils.js.map | 1 + package-lock.json | 757 ++++++++++++++++++++++++- package.json | 24 +- src/index.ts | 34 +- src/utils.ts | 10 +- test/context-store.test.ts | 36 +- test/middleware-receive.test.ts | 52 +- test/middleware-send-to-watson.test.ts | 60 +- test/post-message.test.ts | 34 +- 17 files changed, 1225 insertions(+), 128 deletions(-) create mode 100644 lib/index.d.ts create mode 100644 lib/index.js create mode 100644 lib/index.js.map create mode 100644 lib/utils.d.ts create mode 100644 lib/utils.js create mode 100644 lib/utils.js.map diff --git a/.gitignore b/.gitignore index 77759ad..be679af 100644 --- a/.gitignore +++ b/.gitignore @@ -35,4 +35,3 @@ node_modules # Optional REPL history .node_repl_history -lib/ \ No newline at end of file diff --git a/README.md b/README.md index 8fd0682..e04bee0 100644 --- a/README.md +++ b/README.md @@ -228,13 +228,13 @@ A common scenario of processing actions is: Using sendToWatson to update context simplifies the bot code compared to solution using updateContext below. ```js -const checkBalance = (context) => new Promise((resolve, reject) => { +const checkBalance = async (context) => { //do something real here const contextDelta = { validAccount: true, accountBalance: 95.33 }; - resolve(context); + await Promise.resolve(context); }); const processWatsonResponse = async (bot, message) => { @@ -267,7 +267,7 @@ controller.on('message_received', processWatsonResponse); Events are messages having type different than `message`. -[Example](https://github.com/howdyai/botkit/blob/master/examples/facebook_bot.js) of handler: +[Example](https://github.com/howdyai/botkit/blob/master/packages/docs/reference/facebook.md#facebookeventtypemiddleware) of handler: ```js controller.on('facebook_postback', async (bot, message) => { @@ -326,16 +326,16 @@ The _before_ and _after_ async calls can be used to perform some tasks _before_ They can be customized as follows: ```js -middleware.before = (message, assistantPayload) => new Promise((resolve, reject) => { - // Code here gets executed before making the call to Assistant. - resolve(assistantPayload); -}); +middleware.before = (message, assistantPayload) => async () => { + // Code here gets executed before making the call to Assistant. + return await Promise.resolve(assistantPayload); +} ``` ```js -middleware.after = (message, assistantResponse) => new Promise((resolve, reject) => { +middleware.after = (message, assistantResponse) => async () => { // Code here gets executed after the call to Assistant. - resolve(assistantResponse); + return await Promise.resolve(assistantResponse); }); ``` diff --git a/examples/simple-bot/package.json b/examples/simple-bot/package.json index 4dcc2dc..799e74e 100644 --- a/examples/simple-bot/package.json +++ b/examples/simple-bot/package.json @@ -10,7 +10,7 @@ "dependencies": { "botbuilder-adapter-slack": "^1.0.1", "botkit": "^4.0.1", - "botkit-middleware-watson": "file:../../botkit-middleware-watson-2.0.0.tgz", + "botkit-middleware-watson": "^2.0.0", "dotenv": "^8.0.0", "express": "^4.16.3" } diff --git a/lib/index.d.ts b/lib/index.d.ts new file mode 100644 index 0000000..fd7ff10 --- /dev/null +++ b/lib/index.d.ts @@ -0,0 +1,67 @@ +/** + * Copyright 2016-2019 IBM Corp. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import Botkit = require('botkit'); +import AssistantV1 = require('ibm-watson/assistant/v1'); +import { BotkitMessage } from 'botkit'; +export interface WatsonMiddlewareConfig { + version: string; + workspace_id: string; + url?: string; + token?: string; + headers?: { + [index: string]: string; + }; + use_unauthenticated?: boolean; + username?: string; + password?: string; + iam_apikey?: string; + iam_url?: string; + minimum_confidence?: number; +} +export interface Payload extends AssistantV1.MessageRequest { + workspace_id: string; +} +export interface Context { + conversation_id: string; + system: any; + [index: string]: any; +} +export declare type BotkitWatsonMessage = BotkitMessage & { + watsonData?: Payload; + watsonError?: string; +}; +export interface ContextDelta { + [index: string]: any; +} +export declare type ErrorCallback = (err: null | Error) => null; +export declare class WatsonMiddleware { + private config; + private conversation; + private storage; + private minimumConfidence; + private readonly ignoreType; + constructor(config: WatsonMiddlewareConfig); + hear(patterns: string[], message: Botkit.BotkitMessage): boolean; + before(message: Botkit.BotkitMessage, payload: Payload): Promise; + after(message: Botkit.BotkitMessage, response: any): Promise; + sendToWatson(bot: any, message: Botkit.BotkitMessage, contextDelta: ContextDelta): Promise; + receive(bot: Botkit.BotWorker, message: Botkit.BotkitMessage): Promise; + interpret(bot: Botkit.BotWorker, message: Botkit.BotkitMessage): Promise; + readContext(user: string): Promise; + updateContext(user: string, contextDelta: ContextDelta): Promise<{ + context: Context | ContextDelta; + }>; +} diff --git a/lib/index.js b/lib/index.js new file mode 100644 index 0000000..bb88dd7 --- /dev/null +++ b/lib/index.js @@ -0,0 +1,153 @@ +"use strict"; +/* eslint-disable @typescript-eslint/no-explicit-any */ +/** + * Copyright 2016-2019 IBM Corp. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const debug = require('debug')('watson-middleware:index'); +const AssistantV1 = require("ibm-watson/assistant/v1"); +const utils_1 = require("./utils"); +const deepMerge = require("deepmerge"); +class WatsonMiddleware { + constructor(config) { + this.minimumConfidence = 0.75; + // These are initiated by Slack itself and not from the end-user. Won't send these to WCS. + this.ignoreType = ['presence_change', 'reconnect_url']; + this.config = config; + if (config.minimum_confidence) { + this.minimumConfidence = config.minimum_confidence; + } + } + hear(patterns, message) { + if (message.watsonData && message.watsonData.intents) { + for (let p = 0; p < patterns.length; p++) { + for (let i = 0; i < message.watsonData.intents.length; i++) { + if (message.watsonData.intents[i].intent === patterns[p] && + message.watsonData.intents[i].confidence >= this.minimumConfidence) { + return true; + } + } + } + } + return false; + } + before(message, payload) { + return Promise.resolve(payload); + } + after(message, response) { + return Promise.resolve(response); + } + sendToWatson(bot, message, contextDelta) { + return __awaiter(this, void 0, void 0, function* () { + if (!this.conversation) { + debug('Creating Assistant object with parameters: ' + + JSON.stringify(this.config, null, 2)); + this.conversation = new AssistantV1(this.config); + } + if ((!message.text && message.type !== 'welcome') || + this.ignoreType.indexOf(message.type) !== -1 || + message.reply_to || + message.bot_id) { + // Ignore messages initiated by Slack. Reply with dummy output object + message.watsonData = { + output: { + text: [], + }, + }; + return; + } + this.storage = bot.controller.storage; + try { + const userContext = yield utils_1.readContext(message.user, this.storage); + const payload = { + // eslint-disable-next-line @typescript-eslint/camelcase + workspace_id: this.config.workspace_id, + }; + if (message.text) { + // text can not contain the following characters: tab, new line, carriage return. + const sanitizedText = message.text.replace(/[\r\n\t]/g, ' '); + payload.input = { + text: sanitizedText, + }; + } + if (userContext) { + payload.context = userContext; + } + if (contextDelta) { + if (!userContext) { + //nothing to merge, this is the first context + payload.context = contextDelta; + } + else { + payload.context = deepMerge(payload.context, contextDelta); + } + } + if (payload.context && + payload.context.workspace_id && + payload.context.workspace_id.length === 36) { + // eslint-disable-next-line @typescript-eslint/camelcase + payload.workspace_id = payload.context.workspace_id; + } + const watsonRequest = yield this.before(message, payload); + let watsonResponse = yield utils_1.postMessage(this.conversation, watsonRequest); + watsonResponse = yield this.after(message, watsonResponse); + message.watsonData = watsonResponse; + yield utils_1.updateContext(message.user, this.storage, watsonResponse); + } + catch (error) { + message.watsonError = error; + debug('Error: %s', JSON.stringify(error, Object.getOwnPropertyNames(error), 2)); + } + }); + } + receive(bot, message) { + return __awaiter(this, void 0, void 0, function* () { + return this.sendToWatson(bot, message, null); + }); + } + interpret(bot, message) { + return __awaiter(this, void 0, void 0, function* () { + return this.sendToWatson(bot, message, null); + }); + } + readContext(user) { + return __awaiter(this, void 0, void 0, function* () { + if (!this.storage) { + throw new Error('readContext is called before the first this.receive call'); + } + return utils_1.readContext(user, this.storage); + }); + } + updateContext(user, contextDelta) { + return __awaiter(this, void 0, void 0, function* () { + if (!this.storage) { + throw new Error('updateContext is called before the first this.receive call'); + } + return utils_1.updateContext(user, this.storage, { + context: contextDelta, + }); + }); + } +} +exports.WatsonMiddleware = WatsonMiddleware; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/lib/index.js.map b/lib/index.js.map new file mode 100644 index 0000000..c3c79f3 --- /dev/null +++ b/lib/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/utils.d.ts b/lib/utils.d.ts new file mode 100644 index 0000000..8bdc953 --- /dev/null +++ b/lib/utils.d.ts @@ -0,0 +1,25 @@ +/** + * Copyright 2016-2019 IBM Corp. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { Storage } from 'botbuilder'; +import AssistantV1 = require('ibm-watson/assistant/v1'); +import { Payload, Context, ContextDelta } from './index'; +export declare function readContext(userId: string, storage: Storage): Promise; +export declare function updateContext(userId: string, storage: Storage, watsonResponse: { + context: Context | ContextDelta; +}): Promise<{ + context: Context | ContextDelta; +}>; +export declare function postMessage(conversation: AssistantV1, payload: Payload): Promise; diff --git a/lib/utils.js b/lib/utils.js new file mode 100644 index 0000000..a1594ed --- /dev/null +++ b/lib/utils.js @@ -0,0 +1,78 @@ +"use strict"; +/* eslint-disable @typescript-eslint/no-explicit-any */ +/** + * Copyright 2016-2019 IBM Corp. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const debug = require('debug')('watson-middleware:utils'); +const storagePrefix = 'user.'; +function readContext(userId, storage) { + return __awaiter(this, void 0, void 0, function* () { + const itemId = storagePrefix + userId; + try { + const result = yield storage.read([itemId]); + if (typeof result[itemId] !== 'undefined' && result[itemId].context) { + debug('User: %s, Context: %s', userId, JSON.stringify(result[itemId].context, null, 2)); + return result[itemId].context; + } + } + catch (err) { + debug('User: %s, read context error: %s', userId, err); + } + return null; + }); +} +exports.readContext = readContext; +function updateContext(userId, storage, watsonResponse) { + return __awaiter(this, void 0, void 0, function* () { + const itemId = storagePrefix + userId; + let userData = {}; + try { + const result = yield storage.read([itemId]); + if (typeof result[itemId] !== 'undefined') { + debug('User: %s, Data: %s', userId, JSON.stringify(result[itemId], null, 2)); + userData = result[itemId]; + } + } + catch (err) { + debug('User: %s, read context error: %s', userId, err); + } + userData.id = userId; + userData.context = watsonResponse.context; + let changes = {}; + changes[itemId] = userData; + yield storage.write(changes); + return watsonResponse; + }); +} +exports.updateContext = updateContext; +function postMessage(conversation, payload) { + return __awaiter(this, void 0, void 0, function* () { + debug('Assistant Request: %s', JSON.stringify(payload, null, 2)); + const response = yield conversation.message(payload); + debug('Assistant Response: %s', JSON.stringify(response, null, 2)); + return response; + }); +} +exports.postMessage = postMessage; +//# sourceMappingURL=utils.js.map \ No newline at end of file diff --git a/lib/utils.js.map b/lib/utils.js.map new file mode 100644 index 0000000..418dc26 --- /dev/null +++ b/lib/utils.js.map @@ -0,0 +1 @@ +{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":";AAAA,uDAAuD;AACvD;;;;;;;;;;;;;;GAcG;;;;;;;;;;AAEH,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,yBAAyB,CAAC,CAAC;AAK1D,MAAM,aAAa,GAAG,OAAO,CAAC;AAE9B,SAAsB,WAAW,CAC/B,MAAc,EACd,OAAgB;;QAEhB,MAAM,MAAM,GAAG,aAAa,GAAG,MAAM,CAAC;QAEtC,IAAI;YACF,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;YAC5C,IAAI,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,WAAW,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE;gBACnE,KAAK,CACH,uBAAuB,EACvB,MAAM,EACN,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAChD,CAAC;gBACF,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;aAC/B;SACF;QAAC,OAAO,GAAG,EAAE;YACZ,KAAK,CAAC,kCAAkC,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC;SACxD;QACD,OAAO,IAAI,CAAC;IACd,CAAC;CAAA;AApBD,kCAoBC;AAED,SAAsB,aAAa,CACjC,MAAc,EACd,OAAgB,EAChB,cAAmD;;QAEnD,MAAM,MAAM,GAAG,aAAa,GAAG,MAAM,CAAC;QAEtC,IAAI,QAAQ,GAAQ,EAAE,CAAC;QACvB,IAAI;YACF,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;YAC5C,IAAI,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,WAAW,EAAE;gBACzC,KAAK,CACH,oBAAoB,EACpB,MAAM,EACN,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CACxC,CAAC;gBACF,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;aAC3B;SACF;QAAC,OAAO,GAAG,EAAE;YACZ,KAAK,CAAC,kCAAkC,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC;SACxD;QAED,QAAQ,CAAC,EAAE,GAAG,MAAM,CAAC;QACrB,QAAQ,CAAC,OAAO,GAAG,cAAc,CAAC,OAAO,CAAC;QAC1C,IAAI,OAAO,GAAG,EAAE,CAAC;QACjB,OAAO,CAAC,MAAM,CAAC,GAAG,QAAQ,CAAC;QAC3B,MAAM,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAE7B,OAAO,cAAc,CAAC;IACxB,CAAC;CAAA;AA7BD,sCA6BC;AAED,SAAsB,WAAW,CAC/B,YAAyB,EACzB,OAAgB;;QAEhB,KAAK,CAAC,uBAAuB,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QACjE,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACrD,KAAK,CAAC,wBAAwB,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QACnE,OAAO,QAAQ,CAAC;IAClB,CAAC;CAAA;AARD,kCAQC"} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 98443e9..d4855d6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -150,6 +150,15 @@ "@babel/helper-plugin-utils": "^7.0.0" } }, + "@babel/runtime": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.4.4.tgz", + "integrity": "sha512-w0+uT71b6Yi7i5SE0co4NioIpSYS6lLiXvCzWzGSKvpK5vdQtCbICHMj+gbAKAOtxiV6HsVh/MBdaF9EQ6faSg==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.13.2" + } + }, "@babel/template": { "version": "7.4.4", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.4.4.tgz", @@ -467,6 +476,15 @@ "@microsoft/recognizers-text-sequence": "~1.1.2" } }, + "@samverschueren/stream-to-observable": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz", + "integrity": "sha512-MI4Xx6LHs4Webyvi6EbspgyAb4D2Q2VtnCQ1blOJcoLS6mVa8lNN2rkIy1CVxfTUpoyIbCTkXES1rLXztFD1lg==", + "dev": true, + "requires": { + "any-observable": "^0.3.0" + } + }, "@sinonjs/commons": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.4.0.tgz", @@ -645,6 +663,12 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-10.14.6.tgz", "integrity": "sha512-Fvm24+u85lGmV4hT5G++aht2C5I4Z4dYlWZIh62FAfFO/TfzXtPpoLI6I7AuBWkIFqZCnhFOoTT7RjjaIL5Fjg==" }, + "@types/normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==", + "dev": true + }, "@types/sinon": { "version": "7.0.11", "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-7.0.11.tgz", @@ -792,6 +816,12 @@ "color-convert": "^1.9.0" } }, + "any-observable": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/any-observable/-/any-observable-0.3.0.tgz", + "integrity": "sha512-/FQM1EDkTsf63Ub2C6O7GuYFDsSXUwsaZDurV0np41ocwq0jthUAYCmhBX9f+KwlaCgIuWyr/4WlUQUBfKfZog==", + "dev": true + }, "anymatch": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", @@ -861,12 +891,33 @@ "integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=", "dev": true }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "requires": { + "array-uniq": "^1.0.1" + } + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true + }, "array-unique": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", "dev": true }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, "asn1": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", @@ -1342,6 +1393,32 @@ "unset-value": "^1.0.0" } }, + "caller-callsite": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", + "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", + "dev": true, + "requires": { + "callsites": "^2.0.0" + }, + "dependencies": { + "callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", + "dev": true + } + } + }, + "caller-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", + "dev": true, + "requires": { + "caller-callsite": "^2.0.0" + } + }, "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -1444,6 +1521,59 @@ "restore-cursor": "^2.0.0" } }, + "cli-truncate": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-0.2.1.tgz", + "integrity": "sha1-nxXPuwcFAFNpIWxiasfQWrkN1XQ=", + "dev": true, + "requires": { + "slice-ansi": "0.0.4", + "string-width": "^1.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "slice-ansi": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", + "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", + "dev": true + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, "cli-width": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", @@ -1546,8 +1676,7 @@ "version": "2.20.0", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", - "dev": true, - "optional": true + "dev": true }, "component-emitter": { "version": "1.3.0", @@ -1606,6 +1735,36 @@ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true }, + "cosmiconfig": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.0.tgz", + "integrity": "sha512-nxt+Nfc3JAqf4WIWd0jXLjTJZmsPLrA9DDc4nRw2KFJQJK7DNooqSXrNI7tzLG50CF8axczly5UV929tBmh/7g==", + "dev": true, + "requires": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.0", + "parse-json": "^4.0.0" + }, + "dependencies": { + "import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", + "dev": true, + "requires": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + } + }, + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + } + } + }, "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", @@ -1667,6 +1826,12 @@ } } }, + "date-fns": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz", + "integrity": "sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==", + "dev": true + }, "debug": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", @@ -1694,6 +1859,12 @@ "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", "dev": true }, + "dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", + "dev": true + }, "deep-eql": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", @@ -1778,6 +1949,20 @@ } } }, + "del": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/del/-/del-3.0.0.tgz", + "integrity": "sha1-U+z2mf/LyzljdpGrE7rxYIGXZuU=", + "dev": true, + "requires": { + "globby": "^6.1.0", + "is-path-cwd": "^1.0.0", + "is-path-in-cwd": "^1.0.0", + "p-map": "^1.1.1", + "pify": "^3.0.0", + "rimraf": "^2.2.8" + } + }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -1861,6 +2046,12 @@ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", "dev": true }, + "elegant-spinner": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/elegant-spinner/-/elegant-spinner-1.0.1.tgz", + "integrity": "sha1-2wQ1IcldfjA/2PNFvtwzSc+wcp4=", + "dev": true + }, "emoji-regex": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", @@ -2570,6 +2761,12 @@ } } }, + "find-parent-dir": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/find-parent-dir/-/find-parent-dir-0.3.0.tgz", + "integrity": "sha1-M8RLQpqysvBkYpnF+fcY83b/jVQ=", + "dev": true + }, "find-up": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", @@ -2596,6 +2793,12 @@ "integrity": "sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg==", "dev": true }, + "fn-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fn-name/-/fn-name-2.0.1.tgz", + "integrity": "sha1-UhTXU3pNBqSjAcDMJi/rhBiAAuc=", + "dev": true + }, "follow-redirects": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.7.0.tgz", @@ -3311,6 +3514,17 @@ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, + "g-status": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/g-status/-/g-status-2.0.2.tgz", + "integrity": "sha512-kQoE9qH+T1AHKgSSD0Hkv98bobE90ILQcXAF4wvGgsr7uFqNvwmh8j+Lq3l0RVt3E3HjSbv2B9biEGcEtpHLCA==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "matcher": "^1.0.0", + "simple-git": "^1.85.0" + } + }, "get-caller-file": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", @@ -3323,6 +3537,12 @@ "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", "dev": true }, + "get-own-enumerable-property-symbols": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.0.tgz", + "integrity": "sha512-CIJYJC4GGF06TakLg8z4GQKvDsx9EMspVxOYih7LerEL/WosUnFIww45CGfxfeKHqlg3twgUrYRT1O3WQqjGCg==", + "dev": true + }, "get-stdin": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", @@ -3373,6 +3593,27 @@ "integrity": "sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw==", "dev": true }, + "globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, "graceful-fs": { "version": "4.1.15", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", @@ -3428,6 +3669,23 @@ "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=", + "dev": true, + "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=", + "dev": true + } + } + }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -3548,6 +3806,53 @@ } } }, + "husky": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/husky/-/husky-2.2.0.tgz", + "integrity": "sha512-lG33E7zq6v//H/DQIojPEi1ZL9ebPFt3MxUMD8MR0lrS2ljEPiuUUxlziKIs/o9EafF0chL7bAtLQkcPvXmdnA==", + "dev": true, + "requires": { + "cosmiconfig": "^5.2.0", + "execa": "^1.0.0", + "find-up": "^3.0.0", + "get-stdin": "^7.0.0", + "is-ci": "^2.0.0", + "pkg-dir": "^4.1.0", + "please-upgrade-node": "^3.1.1", + "read-pkg": "^5.0.0", + "run-node": "^1.0.0", + "slash": "^2.0.0" + }, + "dependencies": { + "get-stdin": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-7.0.0.tgz", + "integrity": "sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ==", + "dev": true + }, + "pkg-dir": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.1.0.tgz", + "integrity": "sha512-55k9QN4saZ8q518lE6EFgYiu95u3BWkSajCifhdQjvLvmr8IpnRbhI+UGpWJQfa0KzDguHeeWT1ccO1PmkOi3A==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + }, + "read-pkg": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.1.1.tgz", + "integrity": "sha512-dFcTLQi6BZ+aFUaICg7er+/usEoqFdQxiEBsEMNGoipenihtxxtdrQuBXvyANCEI8VuUIVYFgeHGx9sLLvim4w==", + "dev": true, + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^4.0.0", + "type-fest": "^0.4.1" + } + } + } + }, "ibm-cloud-sdk-core": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ibm-cloud-sdk-core/-/ibm-cloud-sdk-core-0.1.2.tgz", @@ -3671,6 +3976,12 @@ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, + "indent-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", + "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", + "dev": true + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -3820,6 +4131,12 @@ } } }, + "is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", + "dev": true + }, "is-extendable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", @@ -3828,6 +4145,12 @@ "is-plain-object": "^2.0.4" } }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", @@ -3840,6 +4163,15 @@ "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", "dev": true }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, "is-number": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", @@ -3860,6 +4192,45 @@ } } }, + "is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", + "dev": true + }, + "is-observable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-observable/-/is-observable-1.1.0.tgz", + "integrity": "sha512-NqCa4Sa2d+u7BWc6CukaObG3Fh+CU9bvixbpcXYhy2VvYS7vVGIdAgnIS5Ks3A/cqk4rebLJ9s8zBstT2aKnIA==", + "dev": true, + "requires": { + "symbol-observable": "^1.1.0" + } + }, + "is-path-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", + "dev": true + }, + "is-path-in-cwd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", + "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", + "dev": true, + "requires": { + "is-path-inside": "^1.0.0" + } + }, + "is-path-inside": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", + "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", + "dev": true, + "requires": { + "path-is-inside": "^1.0.1" + } + }, "is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", @@ -3883,6 +4254,12 @@ "has": "^1.0.1" } }, + "is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=", + "dev": true + }, "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", @@ -4683,6 +5060,176 @@ "type-check": "~0.3.2" } }, + "lint-staged": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-8.1.6.tgz", + "integrity": "sha512-QT13AniHN6swAtTjsrzxOfE4TVCiQ39xESwLmjGVNCMMZ/PK5aopwvbxLrzw+Zf9OxM3cQG6WCx9lceLzETOnQ==", + "dev": true, + "requires": { + "chalk": "^2.3.1", + "commander": "^2.14.1", + "cosmiconfig": "^5.0.2", + "debug": "^3.1.0", + "dedent": "^0.7.0", + "del": "^3.0.0", + "execa": "^1.0.0", + "find-parent-dir": "^0.3.0", + "g-status": "^2.0.2", + "is-glob": "^4.0.0", + "is-windows": "^1.0.2", + "listr": "^0.14.2", + "listr-update-renderer": "^0.5.0", + "lodash": "^4.17.11", + "log-symbols": "^2.2.0", + "micromatch": "^3.1.8", + "npm-which": "^3.0.1", + "p-map": "^1.1.1", + "path-is-inside": "^1.0.2", + "pify": "^3.0.0", + "please-upgrade-node": "^3.0.2", + "staged-git-files": "1.1.2", + "string-argv": "^0.0.2", + "stringify-object": "^3.2.2", + "yup": "^0.27.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + } + } + }, + "listr": { + "version": "0.14.3", + "resolved": "https://registry.npmjs.org/listr/-/listr-0.14.3.tgz", + "integrity": "sha512-RmAl7su35BFd/xoMamRjpIE4j3v+L28o8CT5YhAXQJm1fD+1l9ngXY8JAQRJ+tFK2i5njvi0iRUKV09vPwA0iA==", + "dev": true, + "requires": { + "@samverschueren/stream-to-observable": "^0.3.0", + "is-observable": "^1.1.0", + "is-promise": "^2.1.0", + "is-stream": "^1.1.0", + "listr-silent-renderer": "^1.1.1", + "listr-update-renderer": "^0.5.0", + "listr-verbose-renderer": "^0.5.0", + "p-map": "^2.0.0", + "rxjs": "^6.3.3" + }, + "dependencies": { + "p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "dev": true + } + } + }, + "listr-silent-renderer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz", + "integrity": "sha1-kktaN1cVN3C/Go4/v3S4u/P5JC4=", + "dev": true + }, + "listr-update-renderer": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/listr-update-renderer/-/listr-update-renderer-0.5.0.tgz", + "integrity": "sha512-tKRsZpKz8GSGqoI/+caPmfrypiaq+OQCbd+CovEC24uk1h952lVj5sC7SqyFUm+OaJ5HN/a1YLt5cit2FMNsFA==", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "cli-truncate": "^0.2.1", + "elegant-spinner": "^1.0.1", + "figures": "^1.7.0", + "indent-string": "^3.0.0", + "log-symbols": "^1.0.2", + "log-update": "^2.3.0", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "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" + } + }, + "figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5", + "object-assign": "^4.1.0" + } + }, + "log-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", + "integrity": "sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=", + "dev": true, + "requires": { + "chalk": "^1.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "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=", + "dev": true + } + } + }, + "listr-verbose-renderer": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/listr-verbose-renderer/-/listr-verbose-renderer-0.5.0.tgz", + "integrity": "sha512-04PDPqSlsqIOaaaGZ+41vq5FejI9auqTInicFRndCBgE3bXG8D6W1I+mWhk+1nqbHmyhla/6BUrd5OSiHwKRXw==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "cli-cursor": "^2.1.0", + "date-fns": "^1.27.2", + "figures": "^2.0.0" + } + }, "load-json-file": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", @@ -4800,6 +5347,53 @@ "integrity": "sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw=", "dev": true }, + "log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "dev": true, + "requires": { + "chalk": "^2.0.1" + } + }, + "log-update": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-2.3.0.tgz", + "integrity": "sha1-iDKP19HOeTiykoN0bwsbwSayRwg=", + "dev": true, + "requires": { + "ansi-escapes": "^3.0.0", + "cli-cursor": "^2.0.0", + "wrap-ansi": "^3.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "wrap-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-3.0.1.tgz", + "integrity": "sha1-KIoE2H7aXChuBg3+jxNc6NAH+Lo=", + "dev": true, + "requires": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0" + } + } + } + }, "lolex": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/lolex/-/lolex-4.0.1.tgz", @@ -4872,6 +5466,15 @@ "object-visit": "^1.0.0" } }, + "matcher": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/matcher/-/matcher-1.1.1.tgz", + "integrity": "sha512-+BmqxWIubKTRKNWx/ahnCkk3mG8m7OturVlqq6HiojGJTd5hVYbgZm6WzcYPCoB+KBT4Vd6R7WSRG2OADNaCjg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.4" + } + }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -5162,6 +5765,15 @@ "remove-trailing-separator": "^1.0.1" } }, + "npm-path": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/npm-path/-/npm-path-2.0.4.tgz", + "integrity": "sha512-IFsj0R9C7ZdR5cP+ET342q77uSRdtWOlWpih5eC+lu29tIDbNEgDbzgVJ5UFvYHWhxDZ5TFkJafFioO0pPQjCw==", + "dev": true, + "requires": { + "which": "^1.2.10" + } + }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", @@ -5171,6 +5783,17 @@ "path-key": "^2.0.0" } }, + "npm-which": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-which/-/npm-which-3.0.1.tgz", + "integrity": "sha1-kiXybsOihcIJyuZ8OxGmtKtxQKo=", + "dev": true, + "requires": { + "commander": "^2.9.0", + "npm-path": "^2.0.2", + "which": "^1.2.10" + } + }, "number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", @@ -5189,6 +5812,12 @@ "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", "dev": true }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, "object-copy": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", @@ -5382,6 +6011,12 @@ "p-limit": "^2.0.0" } }, + "p-map": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz", + "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==", + "dev": true + }, "p-reduce": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-1.0.0.tgz", @@ -5504,6 +6139,21 @@ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", "dev": true }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "^2.0.0" + } + }, "pirates": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", @@ -5522,6 +6172,15 @@ "find-up": "^3.0.0" } }, + "please-upgrade-node": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.1.1.tgz", + "integrity": "sha512-KY1uHnQ2NlQHqIJQpnh/i54rKkuxCEBx+voJIS/Mvb+L2iYd2NMotwduhKTMjfC1uKoX3VXOxLjIYG66dfJTVQ==", + "dev": true, + "requires": { + "semver-compare": "^1.0.0" + } + }, "pn": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", @@ -5601,6 +6260,12 @@ "integrity": "sha1-AMLa7t2iDofjeCs0Stuhzd1q1wk=", "dev": true }, + "property-expr": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-1.5.1.tgz", + "integrity": "sha512-CGuc0VUTGthpJXL36ydB6jnbyOf/rAHFvmVrJlH+Rg0DqqLFQGAP6hIaxD/G0OAmBJPhXDHuEJigrp0e0wFV6g==", + "dev": true + }, "proxy-addr": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz", @@ -5722,6 +6387,12 @@ "util.promisify": "^1.0.0" } }, + "regenerator-runtime": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz", + "integrity": "sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA==", + "dev": true + }, "regex-not": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", @@ -5930,6 +6601,12 @@ "is-promise": "^2.1.0" } }, + "run-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/run-node/-/run-node-1.0.0.tgz", + "integrity": "sha512-kc120TBlQ3mih1LSzdAJXo4xn/GWS2ec0l3S+syHDXP9uRr0JAT8Qd3mdMuyjqCzeZktgP3try92cEgf9Nks8A==", + "dev": true + }, "rxjs": { "version": "6.5.1", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.1.tgz", @@ -5996,6 +6673,12 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" }, + "semver-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", + "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", + "dev": true + }, "send": { "version": "0.16.2", "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", @@ -6132,6 +6815,15 @@ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true }, + "simple-git": { + "version": "1.112.0", + "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-1.112.0.tgz", + "integrity": "sha512-3vY0SW+RkO+ElWH07n/PQuKmuNLZSz3VAkxKMr3UMm/QnaSnYFjg3nqT8V6a0QCcUFpkyAWVsruQt4oSIIzPXw==", + "dev": true, + "requires": { + "debug": "^4.0.1" + } + }, "sinon": { "version": "7.3.2", "resolved": "https://registry.npmjs.org/sinon/-/sinon-7.3.2.tgz", @@ -6397,6 +7089,12 @@ "integrity": "sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA==", "dev": true }, + "staged-git-files": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/staged-git-files/-/staged-git-files-1.1.2.tgz", + "integrity": "sha512-0Eyrk6uXW6tg9PYkhi/V/J4zHp33aNyi2hOCmhFLqLTIhbgqWn5jlSzI+IU0VqrZq6+DbHcabQl/WP6P3BG0QA==", + "dev": true + }, "static-extend": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", @@ -6430,6 +7128,12 @@ "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", "dev": true }, + "string-argv": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.0.2.tgz", + "integrity": "sha1-2sMECGkMIfPDYwo/86BYd73L1zY=", + "dev": true + }, "string-length": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz", @@ -6493,6 +7197,17 @@ "safe-buffer": "~5.1.0" } }, + "stringify-object": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", + "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", + "dev": true, + "requires": { + "get-own-enumerable-property-symbols": "^3.0.0", + "is-obj": "^1.0.1", + "is-regexp": "^1.0.0" + } + }, "strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", @@ -6538,12 +7253,24 @@ "has-flag": "^3.0.0" } }, + "symbol-observable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", + "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", + "dev": true + }, "symbol-tree": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz", "integrity": "sha1-rifbOPZgp64uHDt9G8KQgZuFGeY=", "dev": true }, + "synchronous-promise": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/synchronous-promise/-/synchronous-promise-2.0.7.tgz", + "integrity": "sha512-16GbgwTmFMYFyQMLvtQjvNWh30dsFe1cAW5Fg1wm5+dg84L9Pe36mftsIRU95/W2YsISxsz/xq4VB23sqpgb/A==", + "dev": true + }, "table": { "version": "5.2.3", "resolved": "https://registry.npmjs.org/table/-/table-5.2.3.tgz", @@ -6679,6 +7406,12 @@ "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", "dev": true }, + "toposort": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz", + "integrity": "sha1-riF2gXXRVZ1IvvNUILL0li8JwzA=", + "dev": true + }, "tough-cookie": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", @@ -6792,6 +7525,12 @@ "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "dev": true }, + "type-fest": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.4.1.tgz", + "integrity": "sha512-IwzA/LSfD2vC1/YDYMv/zHP4rDF1usCwllsDpbolT3D4fUepIO7f9K70jjmUewU/LmGUKJcwcVtDCpnKk4BPMw==", + "dev": true + }, "type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -7325,6 +8064,20 @@ "camelcase": "^5.0.0", "decamelize": "^1.2.0" } + }, + "yup": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/yup/-/yup-0.27.0.tgz", + "integrity": "sha512-v1yFnE4+u9za42gG/b/081E7uNW9mUj3qtkmelLbW5YPROZzSH/KUUyJu9Wt8vxFJcT9otL/eZopS0YK1L5yPQ==", + "dev": true, + "requires": { + "@babel/runtime": "^7.0.0", + "fn-name": "~2.0.1", + "lodash": "^4.17.11", + "property-expr": "^1.5.0", + "synchronous-promise": "^2.0.6", + "toposort": "^2.0.2" + } } } } diff --git a/package.json b/package.json index 4dc17b2..b461111 100644 --- a/package.json +++ b/package.json @@ -8,8 +8,9 @@ "build": "node ./node_modules/typescript/bin/tsc", "pretest": "npm run build", "test": "jest test --coverage --forceExit", - "lint": "tsc --noEmit && eslint '*/**/*.{js,ts,tsx}' --quiet --fix", - "fix": "eslint '*/**/*.{js,ts,tsx}' --quiet --fix ." + "lint": "npm run build && eslint '*/**/*.ts' --quiet --fix", + "version": "npm run build && git add -A lib", + "precommit": "lint-staged" }, "repository": { "type": "git", @@ -38,16 +39,35 @@ "eslint": "^5.16.0", "eslint-config-prettier": "^4.2.0", "eslint-plugin-prettier": "^3.0.1", + "husky": "^2.2.0", "jest": "^24.8.0", + "lint-staged": "^8.1.5", "nock": "^10.0.6", "prettier": "^1.17.0", "sinon": "^7.3.2", "ts-jest": "^24.0.2", "typescript": "^3.4.5" }, + "prettier": { + "printWidth": 80, + "singleQuote": true, + "trailingComma": "all" + }, "dependencies": { "debug": "^4.1.1", "deepmerge": "^3.2.0", "ibm-watson": "^4.1.0" + }, + "lint-staged": { + "src/**/*.ts": [ + "npm run build", + "npm run lint", + "git add" + ] + }, + "husky": { + "hooks": { + "pre-commit": "lint-staged" + } } } diff --git a/src/index.ts b/src/index.ts index a96005c..3e1cda3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -23,7 +23,7 @@ import { readContext, updateContext, postMessage } from './utils'; import deepMerge = require('deepmerge'); import { BotkitMessage } from 'botkit'; -export interface MiddlewareConfig { +export interface WatsonMiddlewareConfig { version: string; workspace_id: string; url?: string; @@ -61,14 +61,14 @@ export interface ContextDelta { export type ErrorCallback = (err: null | Error) => null; export class WatsonMiddleware { - private config: MiddlewareConfig; + private config: WatsonMiddlewareConfig; private conversation: AssistantV1; private storage: Storage; private minimumConfidence: number = 0.75; // These are initiated by Slack itself and not from the end-user. Won't send these to WCS. private readonly ignoreType = ['presence_change', 'reconnect_url']; - public constructor(config: MiddlewareConfig) { + public constructor(config: WatsonMiddlewareConfig) { this.config = config; if (config.minimum_confidence) { this.minimumConfidence = config.minimum_confidence; @@ -93,7 +93,7 @@ export class WatsonMiddleware { public before( message: Botkit.BotkitMessage, - payload: Payload + payload: Payload, ): Promise { return Promise.resolve(payload); } @@ -105,12 +105,12 @@ export class WatsonMiddleware { public async sendToWatson( bot, message: Botkit.BotkitMessage, - contextDelta: ContextDelta + contextDelta: ContextDelta, ): Promise { if (!this.conversation) { debug( 'Creating Assistant object with parameters: ' + - JSON.stringify(this.config, null, 2) + JSON.stringify(this.config, null, 2), ); this.conversation = new AssistantV1(this.config); } @@ -124,8 +124,8 @@ export class WatsonMiddleware { // Ignore messages initiated by Slack. Reply with dummy output object message.watsonData = { output: { - text: [] - } + text: [], + }, }; return; } @@ -137,13 +137,13 @@ export class WatsonMiddleware { const payload: Payload = { // eslint-disable-next-line @typescript-eslint/camelcase - workspace_id: this.config.workspace_id + workspace_id: this.config.workspace_id, }; if (message.text) { // text can not contain the following characters: tab, new line, carriage return. const sanitizedText = message.text.replace(/[\r\n\t]/g, ' '); payload.input = { - text: sanitizedText + text: sanitizedText, }; } if (userContext) { @@ -176,21 +176,21 @@ export class WatsonMiddleware { message.watsonError = error; debug( 'Error: %s', - JSON.stringify(error, Object.getOwnPropertyNames(error), 2) + JSON.stringify(error, Object.getOwnPropertyNames(error), 2), ); } } public async receive( bot: Botkit.BotWorker, - message: Botkit.BotkitMessage + message: Botkit.BotkitMessage, ): Promise { return this.sendToWatson(bot, message, null); } public async interpret( bot: Botkit.BotWorker, - message: Botkit.BotkitMessage + message: Botkit.BotkitMessage, ): Promise { return this.sendToWatson(bot, message, null); } @@ -198,7 +198,7 @@ export class WatsonMiddleware { public async readContext(user: string): Promise { if (!this.storage) { throw new Error( - 'readContext is called before the first this.receive call' + 'readContext is called before the first this.receive call', ); } return readContext(user, this.storage); @@ -206,15 +206,15 @@ export class WatsonMiddleware { public async updateContext( user: string, - contextDelta: ContextDelta + contextDelta: ContextDelta, ): Promise<{ context: Context | ContextDelta }> { if (!this.storage) { throw new Error( - 'updateContext is called before the first this.receive call' + 'updateContext is called before the first this.receive call', ); } return updateContext(user, this.storage, { - context: contextDelta + context: contextDelta, }); } } diff --git a/src/utils.ts b/src/utils.ts index 886736b..9e63d23 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -24,7 +24,7 @@ const storagePrefix = 'user.'; export async function readContext( userId: string, - storage: Storage + storage: Storage, ): Promise { const itemId = storagePrefix + userId; @@ -34,7 +34,7 @@ export async function readContext( debug( 'User: %s, Context: %s', userId, - JSON.stringify(result[itemId].context, null, 2) + JSON.stringify(result[itemId].context, null, 2), ); return result[itemId].context; } @@ -47,7 +47,7 @@ export async function readContext( export async function updateContext( userId: string, storage: Storage, - watsonResponse: { context: Context | ContextDelta } + watsonResponse: { context: Context | ContextDelta }, ): Promise<{ context: Context | ContextDelta }> { const itemId = storagePrefix + userId; @@ -58,7 +58,7 @@ export async function updateContext( debug( 'User: %s, Data: %s', userId, - JSON.stringify(result[itemId], null, 2) + JSON.stringify(result[itemId], null, 2), ); userData = result[itemId]; } @@ -77,7 +77,7 @@ export async function updateContext( export async function postMessage( conversation: AssistantV1, - payload: Payload + payload: Payload, ): Promise { debug('Assistant Request: %s', JSON.stringify(payload, null, 2)); const response = await conversation.message(payload); diff --git a/test/context-store.test.ts b/test/context-store.test.ts index 56d91f4..88a483c 100644 --- a/test/context-store.test.ts +++ b/test/context-store.test.ts @@ -28,38 +28,38 @@ const message: BotkitMessage = { ts: '1475776074.000004', team: 'T2BM5DPJ6', incoming_message: null, - reference: null + reference: null, }; const conversation_response = { intents: [], entities: [], input: { - text: 'Hello there!' + text: 'Hello there!', }, output: { log_messages: [], text: [ - 'Hi. It looks like a nice drive today. What would you like me to do? ' + 'Hi. It looks like a nice drive today. What would you like me to do? ', ], - nodes_visited: ['node_1_1467221909631'] + nodes_visited: ['node_1_1467221909631'], }, context: { conversation_id: '8a79f4db-382c-4d56-bb88-1b320edf9eae', system: { dialog_stack: ['root'], dialog_turn_counter: 1, - dialog_request_counter: 1 + dialog_request_counter: 1, }, - default_counter: 0 - } + default_counter: 0, + }, }; const adapter = new WebAdapter({ noServer: true }); const controller = new Botkit({ adapter: adapter, storage: new MemoryStorage(), //specifying storage explicitly eliminates 3 lines of warning output - disable_webserver: true + disable_webserver: true, }); const storage = controller.storage; @@ -102,8 +102,8 @@ test('should ignore storage error on read when user is not saved yet', function( const watsonResponse = { context: { - a: 1 - } + a: 1, + }, }; return updateContext('NEWUSER3', storage, watsonResponse) .then(function(response) { @@ -133,20 +133,20 @@ test('should return storage error on write', function() { test('should update existing context', function() { const firstContext = { a: 1, - b: 2 + b: 2, }; const secondContext = { c: 3, - d: 4 + d: 4, }; //first update return updateContext(message.user, storage, { - context: firstContext + context: firstContext, }) .then(function() { //second update return updateContext(message.user, storage, { - context: secondContext + context: secondContext, }); }) .then(function() { @@ -162,13 +162,13 @@ test('should preserve other data in storage', function() { id: 'U2BLZSKFX', profile: { age: 23, - sex: 'male' - } + sex: 'male', + }, }; const newContext = { a: 1, - b: 2 + b: 2, }; const itemId = 'user.' + user.id; @@ -180,7 +180,7 @@ test('should preserve other data in storage', function() { .write(existingData) .then(function() { return updateContext(user.id, storage, { - context: newContext + context: newContext, }); }) .then(function() { diff --git a/test/middleware-receive.test.ts b/test/middleware-receive.test.ts index edb68a4..507f677 100644 --- a/test/middleware-receive.test.ts +++ b/test/middleware-receive.test.ts @@ -25,7 +25,7 @@ const service = { username: 'batman', password: 'bruce-wayne', url: 'http://ibm.com:80', - version: '2018-07-10' + version: '2018-07-10', }; const workspaceId = 'zyxwv-54321'; const path = `/v1/workspaces/${workspaceId}/message`; @@ -38,19 +38,19 @@ const message: BotkitMessage = { ts: '1475776074.000004', team: 'T2BM5DPJ6', reference: null, - incoming_message: null + incoming_message: null, }; const adapter = new WebAdapter({ noServer: true }); const controller = new Botkit({ adapter: adapter, storage: new MemoryStorage(), //specifying storage explicitly eliminates 3 lines of warning output - disable_webserver: true + disable_webserver: true, }); const middleware = new WatsonMiddleware({ ...service, - workspace_id: workspaceId + workspace_id: workspaceId, }); let bot = null; @@ -71,21 +71,21 @@ test('should make first call to Assistant', async () => { intents: [], entities: [], input: { - text: 'hi' + text: 'hi', }, output: { log_messages: [], text: ['Hello from Watson Assistant!'], - nodes_visited: ['node_1_1467221909631'] + nodes_visited: ['node_1_1467221909631'], }, context: { conversation_id: '8a79f4db-382c-4d56-bb88-1b320edf9eae', system: { dialog_stack: ['root'], dialog_turn_counter: 1, - dialog_request_counter: 1 - } - } + dialog_request_counter: 1, + }, + }, }; nock(service.url) .post(pathWithQuery) @@ -99,28 +99,28 @@ test('should make first call to Assistant', async () => { test('should make second call to Assistant', async () => { const receivedMessage: BotkitWatsonMessage = { ...message, - text: 'What can you do?' + text: 'What can you do?', }; const expectedWatsonData = { intents: [], entities: [], input: { - text: 'What can you do?' + text: 'What can you do?', }, output: { log_messages: [], text: ['I can tell you about myself. I have a charming personality!'], - nodes_visited: ['node_3_1467221909631'] + nodes_visited: ['node_3_1467221909631'], }, context: { conversation_id: '8a79f4db-382c-4d56-bb88-1b320edf9eae', system: { dialog_stack: ['root'], dialog_turn_counter: 2, - dialog_request_counter: 2 - } - } + dialog_request_counter: 2, + }, + }, }; nock(service.url) @@ -136,21 +136,21 @@ test('should pass empty welcome message to Assistant', async () => { intents: [], entities: [], input: { - text: 'hi' + text: 'hi', }, output: { log_messages: [], text: ['Hello from Watson Assistant!'], - nodes_visited: ['node_1_1467221909631'] + nodes_visited: ['node_1_1467221909631'], }, context: { conversation_id: '8a79f4db-382c-4d56-bb88-1b320edf9eae', system: { dialog_stack: ['root'], dialog_turn_counter: 1, - dialog_request_counter: 1 - } - } + dialog_request_counter: 1, + }, + }, }; nock(service.url) .post(pathWithQuery) @@ -166,7 +166,7 @@ test('should replace not-permitted characters in message text', async () => { // text can not contain the following characters: tab, new line, carriage return. const receivedMessage: BotkitWatsonMessage = { ...message, - text: 'What\tcan\tyou\r\ndo?' + text: 'What\tcan\tyou\r\ndo?', }; const expectedMessage = 'What can you do?'; @@ -174,21 +174,21 @@ test('should replace not-permitted characters in message text', async () => { intents: [], entities: [], input: { - text: expectedMessage + text: expectedMessage, }, output: { log_messages: [], text: ['I can tell you about myself. I have a charming personality!'], - nodes_visited: ['node_3_1467221909631'] + nodes_visited: ['node_3_1467221909631'], }, context: { conversation_id: '8a79f4db-382c-4d56-bb88-1b320edf9eae', system: { dialog_stack: ['root'], dialog_turn_counter: 2, - dialog_request_counter: 2 - } - } + dialog_request_counter: 2, + }, + }, }; nock(service.url) diff --git a/test/middleware-send-to-watson.test.ts b/test/middleware-send-to-watson.test.ts index 3eec921..91c4bd4 100644 --- a/test/middleware-send-to-watson.test.ts +++ b/test/middleware-send-to-watson.test.ts @@ -27,7 +27,7 @@ const service = { username: 'batman', password: 'bruce-wayne', url: 'http://ibm.com:80', - version: '2018-07-10' + version: '2018-07-10', }; const workspaceId = 'zyxwv-54321'; const path = `/v1/workspaces/${workspaceId}/message`; @@ -40,18 +40,18 @@ const message = { ts: '1475776074.000004', team: 'T2BM5DPJ6', reference: null, - incoming_message: null + incoming_message: null, }; const adapter = new WebAdapter({ noServer: true }); const controller = new Botkit({ adapter: adapter, storage: new MemoryStorage(), //specifying storage explicitly eliminates 3 lines of warning output - disable_webserver: true + disable_webserver: true, }); const middleware = new WatsonMiddleware({ ...service, - workspace_id: workspaceId + workspace_id: workspaceId, }); let bot; @@ -77,9 +77,9 @@ test('should update context if contextDelta is provided', async () => { e: 3, f: { g: 4, - h: 5 - } - } + h: 5, + }, + }, }; const contextDelta = { b: null, @@ -87,9 +87,9 @@ test('should update context if contextDelta is provided', async () => { c: { f: { g: 5, - i: 6 - } - } + i: 6, + }, + }, }; const expectedContextInRequest = { a: 1, @@ -100,10 +100,10 @@ test('should update context if contextDelta is provided', async () => { f: { g: 5, h: 5, - i: 6 - } + i: 6, + }, }, - j: 'new string' + j: 'new string', }; const expectedContextInResponse: Context = { ...clonePrototype(expectedContextInRequest), @@ -111,29 +111,29 @@ test('should update context if contextDelta is provided', async () => { system: { dialog_stack: ['root'], dialog_turn_counter: 1, - dialog_request_counter: 1 - } + dialog_request_counter: 1, + }, }; const messageToSend: BotkitWatsonMessage = { ...message }; const expectedRequest = { input: { - text: messageToSend.text + text: messageToSend.text, }, - context: expectedContextInRequest + context: expectedContextInRequest, }; const mockedWatsonResponse = { intents: [], entities: [], input: { - text: 'hi' + text: 'hi', }, output: { log_messages: [], text: ['Hello from Watson Assistant!'], - nodes_visited: ['node_1_1467221909631'] + nodes_visited: ['node_1_1467221909631'], }, - context: expectedContextInResponse + context: expectedContextInResponse, }; //verify request and return mocked response @@ -142,7 +142,7 @@ test('should update context if contextDelta is provided', async () => { .reply(200, mockedWatsonResponse); await updateContext(messageToSend.user, controller.storage, { - context: storedContext + context: storedContext, }); await middleware.sendToWatson(bot, messageToSend, contextDelta); expect(messageToSend.watsonData.context).toEqual(expectedContextInResponse); @@ -152,7 +152,7 @@ test('should make request to different workspace, if workspace_id is set in cont const newWorkspaceId = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'; const expectedPath = `/v1/workspaces/${newWorkspaceId}/message`; const storedContext = { - workspace_id: newWorkspaceId + workspace_id: newWorkspaceId, }; const messageToSend: BotkitWatsonMessage = { ...message }; const expectedContextInResponse: Context = { @@ -161,29 +161,29 @@ test('should make request to different workspace, if workspace_id is set in cont system: { dialog_stack: ['root'], dialog_turn_counter: 1, - dialog_request_counter: 1 - } + dialog_request_counter: 1, + }, }; const expectedRequest = { input: { - text: messageToSend.text + text: messageToSend.text, }, - context: storedContext + context: storedContext, }; const mockedWatsonResponse = { intents: [], entities: [], input: { - text: 'hi' + text: 'hi', }, output: { log_messages: [], text: ['Hello from Watson Assistant!'], - nodes_visited: ['node_1_1467221909631'] + nodes_visited: ['node_1_1467221909631'], }, - context: expectedContextInResponse + context: expectedContextInResponse, }; //verify request and return mocked response @@ -193,7 +193,7 @@ test('should make request to different workspace, if workspace_id is set in cont try { await updateContext(messageToSend.user, controller.storage, { - context: storedContext + context: storedContext, }); await middleware.sendToWatson(bot, messageToSend, {}); expect(messageToSend.watsonError).toBeUndefined(); diff --git a/test/post-message.test.ts b/test/post-message.test.ts index 92f8bbb..bb3ec87 100644 --- a/test/post-message.test.ts +++ b/test/post-message.test.ts @@ -23,7 +23,7 @@ const service = { username: 'batman', password: 'bruce-wayne', url: 'http://ibm.com:80', - version: '2018-07-10' + version: '2018-07-10', }; const workspaceId = 'zyxwv-54321'; const path = `/v1/workspaces/${workspaceId}/message`; @@ -43,21 +43,21 @@ it('should initiate a conversation', function() { intents: [], entities: [], input: { - text: 'hi' + text: 'hi', }, output: { log_messages: [], text: ['Hello from Watson Assistant!'], - nodes_visited: ['node_1_1467221909631'] + nodes_visited: ['node_1_1467221909631'], }, context: { conversation_id: '8a79f4db-382c-4d56-bb88-1b320edf9eae', system: { dialog_stack: ['root'], dialog_turn_counter: 1, - dialog_request_counter: 1 - } - } + dialog_request_counter: 1, + }, + }, }; nock(service.url) @@ -68,8 +68,8 @@ it('should initiate a conversation', function() { .postMessage(conversation, { workspace_id: workspaceId, input: { - text: 'hi' - } + text: 'hi', + }, }) .then(function(response) { expect(response).toEqual(expected); @@ -81,21 +81,21 @@ it('should continue a conversation', async () => { intents: [], entities: [], input: { - text: 'What can you do?' + text: 'What can you do?', }, output: { log_messages: [], text: ['I can tell you about myself. I have a charming personality!'], - nodes_visited: ['node_3_1467221909631'] + nodes_visited: ['node_3_1467221909631'], }, context: { conversation_id: '8a79f4db-382c-4d56-bb88-1b320edf9eae', system: { dialog_stack: ['root'], dialog_turn_counter: 2, - dialog_request_counter: 2 - } - } + dialog_request_counter: 2, + }, + }, }; nock(service.url) @@ -105,16 +105,16 @@ it('should continue a conversation', async () => { const response = await utils.postMessage(conversation, { workspace_id: workspaceId, input: { - text: 'What can you do?' + text: 'What can you do?', }, context: { conversation_id: '8a79f4db-382c-4d56-bb88-1b320edf9eae', system: { dialog_stack: ['root'], dialog_turn_counter: 1, - dialog_request_counter: 1 - } - } + dialog_request_counter: 1, + }, + }, }); expect(response).toEqual(expected); });