UNPKG

@google/dscc-gen

Version:

Create component & connector projects with sane defaults.

184 lines (161 loc) 5.01 kB
/** * @license * Copyright 2018 Google LLC * * 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 * * https://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 * as path from 'path'; import {PWD} from './index'; import * as util from './util'; import {Question} from 'inquirer'; import * as files from './files'; import * as argparse from 'argparse'; import * as vizQuestions from './viz/questions'; import * as connectorQuestions from './connector/questions'; import {VizAnswers} from './viz/questions'; import {ConnectorAnswers} from './connector/questions'; import {prompt} from './prompt'; export interface State { projectPath: string; templatePath: string; } export type Answers = ConnectorAnswers & VizAnswers & CommonAnswers & Args; export interface Args { yarn: boolean; npm: boolean; scriptId?: string; } export interface CommonAnswers { projectChoice: ProjectChoice; projectName: string; basePath: string; } export enum ProjectChoice { VIZ = 'community-viz', CONNECTOR = 'community-connector', } const templateOptions: ProjectChoice[] = [ ProjectChoice.VIZ, ProjectChoice.CONNECTOR, ]; interface QuestionName { cmdName: string; inquirerName: string; } const PROJECT_CHOICE: QuestionName = { cmdName: '--project_choice', inquirerName: 'projectChoice', }; const PROJECT_NAME: QuestionName = { cmdName: '--project_name', inquirerName: 'projectName', }; const projectNameRegEx = /^([-_A-Za-z\d])+$/; const projectNameValidator = async (input: string) => { if (!projectNameRegEx.test(input)) { return 'Name may only include letters, numbers, dashes, and underscores.'; } const projectPath = path.join(PWD, input); if (await util.fileExists(projectPath)) { return `The directory ${input} already exists.`; } return true; }; export const COMMON_QUESTIONS: Array<Question<CommonAnswers>> = [ { name: PROJECT_CHOICE.inquirerName, type: 'list', message: 'What project template would you like to use?', choices: templateOptions, }, { name: PROJECT_NAME.inquirerName, type: 'input', message: 'Project name', validate: projectNameValidator, }, ]; const getArgs = async (baseDir: string): Promise<Args> => { const parser = new argparse.ArgumentParser({ version: (await files.getPackageJson(baseDir)).version, addHelp: true, description: 'Template-based project generator for Data Studio developer features', }); parser.addArgument(['--yarn'], { dest: 'yarn', action: 'storeTrue', help: 'Use yarn as the build tool.', }); parser.addArgument(['--npm'], { dest: 'npm', action: 'storeTrue', help: 'Use npm as the build tool.', }); parser.addArgument([PROJECT_CHOICE.cmdName], { dest: PROJECT_CHOICE.inquirerName, choices: templateOptions, help: 'Which template to use.', }); parser.addArgument([PROJECT_NAME.cmdName], { dest: PROJECT_NAME.inquirerName, help: 'The name of your project', }); parser.addArgument(['--script_id'], { dest: 'scriptId', help: 'Community Connector: Use this scriptId instead of creating a new script.', }); const args = parser.parseArgs(); Object.keys(args).forEach((key) => { if (args[key] === null) { delete args[key]; } }); return args; }; const questionsWithArgs = async <T>( args: Args, questions: Array<Question<T>> ): Promise<Array<Question<T>>> => { await Promise.all( questions.map(async (question) => { const argValue = (args as any)[question.name!]; if (argValue && question.validate) { const isValid = await question.validate(argValue); if (isValid !== true) { throw new Error( `Invalid response for ${question.name}: "${argValue}". ${isValid}` ); } } }) ); return questions.filter((question) => { return (args as any)[question.name!] === undefined; }); }; export const getAnswers = async (baseDir: string): Promise<Answers> => { const args: Args = await getArgs(baseDir); const questions = await questionsWithArgs(args, COMMON_QUESTIONS); const promptAnswers: CommonAnswers = await prompt(questions); const commonAnswers = Object.assign({}, promptAnswers, args); switch (commonAnswers.projectChoice) { case ProjectChoice.VIZ: return vizQuestions.getAnswers(args, commonAnswers); case ProjectChoice.CONNECTOR: return connectorQuestions.getAnswers(args, commonAnswers); default: throw new Error(`${commonAnswers.projectChoice} is not supported.`); } };