src/commands/init.ts
/*
* Copyright (c) 2018 Rain Agency <contact@rain.agency>
* Author: Rain Agency <contact@rain.agency>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/* tslint:disable:no-submodule-imports no-console */
import colors from "colors";
import fs from "fs-extra";
import inquirer from "inquirer";
import _ from "lodash";
import pad from "pad";
import path from "path";
import { Observable } from "rxjs";
import { DEFAULT_INTERACTION_OPTIONS } from "../InteractionBuilder";
export const name = "init";
export const alias = "";
export const description = "create a new interaction.json";
const ALLOWED_ATTRIBUTES = [
"platforms",
"spreadsheets",
"dialogflowSpreadsheets",
"alexaSpreadsheets",
"speechPath",
"content",
"contentPath",
"viewsPath"
];
export async function action() {
const interactionFile = path.join(process.cwd(), "interaction.json");
let hasAnInteractionFile = false;
try {
// a path we KNOW is totally bogus and not a module
hasAnInteractionFile = require(interactionFile);
} catch (e) {
if (e.code === "MODULE_NOT_FOUND") {
hasAnInteractionFile = false;
}
}
const observe = Observable.create((obs: any) => {
const override = (answers: any) => {
return answers.interactionFile;
};
const onlyCommaAnswer = (input: string) => {
return _.chain(input)
.split(",")
.map(_.trim)
.compact()
.value();
};
const noEmptyAnswer = (input: string) => !_.isEmpty(input);
const mustBeSpreadsheetURLOrLength30 = async (input: string) => {
let result: any = _.chain(input)
.split(",")
.map(_.trim)
.compact()
.map((i: string) => {
if (i.includes("docs.google.com/spreadsheets")) {
const matched = i.match(/docs\.google\.com\/spreadsheets\/d\/(.*)\/.*/);
return matched && _.isString(matched[1]) && matched[1].length > 30;
}
if (i.includes(".sharepoint.com") && i.length > 30) {
return true;
}
const customPath = i.indexOf("/") === 0 ? i : path.join(process.cwd(), i);
return fs.pathExists(customPath);
})
.value();
result = await Promise.all(result);
result = result.every((r: boolean) => r);
return noEmptyAnswer(input) && result
? true
: "Insert a proper google spreadsheet url, Office 365 sharepoint url, local file or local folder path. e.g. https://docs.google.com/spreadsheets/d/XXXXXXX/edit#gid=0, https://XXXXXX.sharepoint.com/:x:/g/personal/YYYYYY/ZZZZZZZ, /Users/local/file.xlsx or /Users/local/sheets/";
};
const questions = [
{
type: "confirm",
name: "interactionFile",
message: `Do you want to override ${interactionFile}?`,
when: () => hasAnInteractionFile,
default: true
},
{
type: "checkbox",
name: "platforms",
message: "Choose platforms",
choices: ["alexa", "dialogflow"],
when: override
},
{
type: "input",
name: "spreadsheets",
message: "Specify all spreadsheets separated by comma (*)",
validate: mustBeSpreadsheetURLOrLength30,
filter: onlyCommaAnswer,
when: override
},
{
type: "input",
name: "speechPath",
message: "Specify folder path to save interaction model and manifest",
default: DEFAULT_INTERACTION_OPTIONS.speechPath,
when: override
},
{
type: "input",
name: "contentPath",
message: "Specify folder path to save all downloable content",
when: override,
default: DEFAULT_INTERACTION_OPTIONS.contentPath
},
{
type: "input",
name: "viewsPath",
message: "Specify folder path to save views file",
default: DEFAULT_INTERACTION_OPTIONS.viewsPath,
when: override
},
{
type: "confirm",
name: "isCorrect",
message: `is Correct?`,
when: (answers: any) => {
if (override(answers)) {
printVariables(_.cloneDeep(answers));
}
return override(answers);
},
default: true
}
];
questions.map(q => obs.next(q));
obs.complete();
});
function printVariables(answers: any) {
return _.chain(answers)
.toPairs()
.filter(item => !!ALLOWED_ATTRIBUTES.find(i => i === item[0]))
.map(item => {
const key = item[0];
const value = item[1];
console.log(pad(colors.blue(key), 20), colors.grey(value));
return item;
})
.compact()
.fromPairs()
.value();
}
async function executePrompt(): Promise<any> {
return inquirer.prompt(observe).then((answers: any) => {
if (answers.interactionFile && !answers.isCorrect) {
return executePrompt();
}
if (hasAnInteractionFile && !answers.interactionFile) {
answers = hasAnInteractionFile;
}
if (!answers.interactionFile && !answers.isCorrect) {
printVariables(answers);
}
answers = _.pick(answers, ALLOWED_ATTRIBUTES);
return fs.outputFile(
path.join(process.cwd(), "interaction.json"),
JSON.stringify(answers, null, 2),
{ flag: "w" }
);
});
}
await executePrompt();
}