UNPKG

@google/dscc-gen

Version:

Create component & connector projects with sane defaults.

219 lines 7.81 kB
"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