@google/dscc-gen
Version:
Create component & connector projects with sane defaults.
219 lines • 7.81 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getConfig = void 0;
const argparse = require("argparse");
const inquirer = require("inquirer");
const path = require("path");
const constants = require("./constants");
const types_1 = require("./types");
const util_1 = require("./util");
const util = require("./util");
const validation_1 = require("./viz/validation");
const addVizParser = (subparser) => {
const vizParser = subparser.addParser(types_1.ProjectChoice.VIZ, {
addHelp: true,
description: 'Creates a project using a Community Viz template.',
});
vizParser.addArgument(['--devDirectory', '-d'], {
dest: 'devBucket',
help: 'The dev directory',
});
vizParser.addArgument(['--prodDirectory', '-p'], {
dest: 'prodBucket',
help: 'The prod directory',
});
vizParser.addArgument(['--ts', '--typescript'], {
dest: 'ts',
help: 'Use typescript for template.',
action: 'storeTrue',
});
return vizParser;
};
const addConnectorParser = (subparser) => {
const connectorParser = subparser.addParser(types_1.ProjectChoice.CONNECTOR, {
addHelp: true,
description: 'Creates a project using a Community Connector template.',
});
connectorParser.addArgument(['--script_id', '-s'], {
dest: 'scriptId',
help: 'The id of the script to clone.',
});
connectorParser.addArgument(['--auth_type'], {
dest: 'authType',
help: 'The authorization type for the connector.',
choices: Object.values(types_1.AuthType),
});
connectorParser.addArgument(['--ts', '--typescript'], {
dest: 'ts',
help: 'Use typescript for connector.',
action: 'storeTrue',
});
return connectorParser;
};
const projectNameRegEx = /^([-_A-Za-z\d])+$/;
const projectNameValidator = async (input) => {
if (!projectNameRegEx.test(input)) {
return 'Name may only include letters, numbers, dashes, and underscores.';
}
const projectPath = path.join(constants.PWD, input);
if (await util.fileExists(projectPath)) {
return `The directory ${input} already exists.`;
}
return true;
};
const commonQuestions = [
{
name: 'projectName',
type: 'input',
message: 'Project name',
validate: projectNameValidator,
},
];
const vizQuestions = commonQuestions.concat([
{
name: 'devBucket',
type: 'input',
message: 'What is your "dev" directory?',
transformer: validation_1.addBucketPrefix,
validate: async (a) => validation_1.hasBucketPermissions(validation_1.addBucketPrefix(a)),
},
{
name: 'prodBucket',
type: 'input',
message: 'What is your GCS prod directory?',
transformer: validation_1.addBucketPrefix,
validate: async (a) => validation_1.hasBucketPermissions(validation_1.addBucketPrefix(a)),
},
]);
const getAuthHelpText = (authType) => {
switch (authType) {
case types_1.AuthType.NONE:
return 'No authentication required.';
case types_1.AuthType.KEY:
return 'Key or Token';
case types_1.AuthType.OAUTH2:
return 'Standard OAUTH2';
case types_1.AuthType.USER_PASS:
return 'Username & Password';
case types_1.AuthType.USER_TOKEN:
return 'Username & Token';
case types_1.AuthType.PATH_USER_PASS:
return 'Path & Username & Password';
default:
return util_1.assertNever(authType);
}
};
const longestAuthType = Object.values(types_1.AuthType)
.map((a) => a.length)
.reduce((a, b) => Math.max(a, b), 0);
const connectorQuestions = commonQuestions.concat([
{
name: 'authType',
type: 'list',
when: (answers) => answers.scriptId === undefined || answers.ts === true,
message: 'How will users authenticate to your service?',
choices: Object.values(types_1.AuthType).map((auth) => ({
name: `${auth.padEnd(longestAuthType)} - ${getAuthHelpText(auth)}`,
value: auth,
})),
},
]);
const getParser = () => {
const parser = new argparse.ArgumentParser({
version: constants.packageJSON.version,
addHelp: true,
description: 'Tool for generating Data Studio Developer feature projects.',
});
const subParser = parser.addSubparsers({
title: 'Project Type',
dest: 'projectChoice',
});
const vizParser = addVizParser(subParser);
const connectorParser = addConnectorParser(subParser);
[vizParser, connectorParser].forEach((p) => {
p.addArgument(['--name', '-n'], {
help: 'The name of the project you want to create.',
dest: 'projectName',
});
p.addArgument(['--yarn'], {
dest: 'yarn',
action: 'storeTrue',
help: 'Use yarn as the build tool.',
});
});
return parser;
};
const getMissing = async (args, questions, defaults) => {
// Since args is coming from argparse, they are null if not provided. Since
// we're cheating a bit and saying that the type that argparse returns is T,
// we need to remove null values so optional values are undefined instead of
// null.
const nonNullArgs = Object.keys(args).reduce((acc, a) => {
if (acc[a] === null) {
delete acc[a];
}
return acc;
}, Object.assign({}, args));
const providedKeys = Object.keys(nonNullArgs);
const validations = Object.keys(nonNullArgs).map(async (a) => {
const value = args[a];
if (value !== undefined) {
const question = questions.find((q) => q.name === a);
if (question !== undefined && question.type === 'input') {
const { validate } = question;
if (validate !== undefined) {
return validate(value);
}
}
}
});
await Promise.all(validations);
const remainingQuestions = questions
.filter((q) => providedKeys.find((key) => q.name === key) === undefined)
.filter((q) => {
if (q.when !== undefined && typeof q.when === 'function') {
return q.when(nonNullArgs);
}
else {
return true;
}
});
const answers = await inquirer.prompt(remainingQuestions);
return Object.assign(defaults, args, answers);
};
const withMissing = async (args) => {
const projectChoice = args.projectChoice;
switch (projectChoice) {
case types_1.ProjectChoice.CONNECTOR:
const connectorDefaults = {
manifestLogoUrl: 'logoUrl',
manifestCompany: 'manifestCompany',
manifestCompanyUrl: 'companyUrl',
manifestAddonUrl: 'addonUrl',
manifestSupportUrl: 'supportUrl',
manifestDescription: 'description',
manifestSources: '',
authType: types_1.AuthType.NONE,
};
return getMissing(args, connectorQuestions, connectorDefaults);
case types_1.ProjectChoice.VIZ:
validation_1.checkGsutilInstalled();
const vizDefaults = { ts: false };
return getMissing(args, vizQuestions, vizDefaults);
default:
return util_1.assertNever(projectChoice);
}
};
exports.getConfig = async () => {
const parser = getParser();
const args = parser.parseArgs();
const config = await withMissing(args);
Object.keys(config).forEach((key) => {
const val = config[key];
if (val === null) {
delete config[key];
}
});
return config;
};
//# sourceMappingURL=config.js.map