UNPKG

@optro/create-trello-powerup

Version:

Easily create Trello Power-Ups from the Command Line

263 lines (262 loc) 14.3 kB
"use strict"; const tslib_1 = require("tslib"); const command_1 = require("@oclif/command"); const inquirer = tslib_1.__importStar(require("inquirer")); const string_1 = require("./utility/string"); const path_1 = tslib_1.__importDefault(require("path")); const child_process_1 = require("child_process"); const shell = tslib_1.__importStar(require("shelljs")); const replace = tslib_1.__importStar(require("replace-in-file")); const filenamify_1 = tslib_1.__importDefault(require("filenamify")); const constants_1 = require("./utility/constants"); const fs_1 = require("./utility/fs"); class CreateTrelloPowerup extends command_1.Command { async run() { // Read Arguments const { args, flags } = this.parse(CreateTrelloPowerup); this.debug(args, flags); // Startup Text this.log(); this.log('┌' + '─'.repeat(27) + '┐'); this.log('│ Create Trello Power-Up 🚀 │'); this.log('└' + '─'.repeat(27) + '┘'); this.log(); this.log('Generate a new Trello Power-Up in minutes.\n'); this.log('Find more information in our step-by-step guide:'); this.log('» https://vendor.optro.cloud/build-trello-powerup'); this.log('\n'); if (!shell.which('git')) { shell.echo('Missing Required Package: git'); shell.exit(1); } // Get Information from User const parameters = await inquirer.prompt([ { name: 'name', message: '1. What is the Power-Up Name?', type: 'input', default: 'my-powerup', when: (_answers => !args.powerupName), validate: input => { const folder = filenamify_1.default(input).replace(' ', '-'); if (fs_1.doesFolderExist(folder)) { return 'This folder already exists - Try another name'; } return true; }, }, { name: 'capabilities', message: `${args.powerupName ? '1' : '2'}. What Capabilities should be enabled?`, type: 'checkbox', choices: [ { name: 'Attachment Section', value: 'attachment-section' }, { name: 'Attachment Thumbnail', value: 'attachment-thumbnail' }, { name: 'Authorization Status', value: 'authorization-status' }, { name: 'Board Button', value: 'board-buttons', checked: true }, { name: 'Card Back Section', value: 'card-back-section', checked: true }, { name: 'Card Badges', value: 'card-badges', checked: true }, { name: 'Card Button', value: 'card-buttons', checked: true, disabled: 'Mandatory' }, { name: 'Card Detail Badge', value: 'card-detail-badges', checked: true }, { name: 'Card From URL', value: 'card-from-url' }, { name: 'Format URL', value: 'format-url' }, { name: 'List Action', value: 'list-actions', checked: true }, { name: 'List Sorter', value: 'list-sorters', checked: true }, { name: 'On Enable', value: 'on-enable', checked: true }, { name: 'On Disable', value: 'on-disable', checked: true }, { name: 'Remove Data', value: 'remove-data' }, { name: 'Save Attachment', value: 'save-attachment' }, { name: 'Show Authorization', value: 'show-authorization' }, { name: 'Show Settings', value: 'show-settings', checked: true }, ], filter: input => { return [...input, 'card-buttons']; }, }, { name: 'confirm', message: `${args.powerupName ? '2' : '3'}. Confirm Power-Up generation?`, type: 'confirm', default: true, }, ]); if (!parameters.confirm) { this.error('User Cancelled Project Generation'); this.exit(0); } const folderName = (args.powerupName || filenamify_1.default(parameters.name)).toLowerCase().replace(/\s/gi, '-'); // Check if Directory Exists if (fs_1.doesFolderExist(folderName)) { this.error('The project folder specified already exists! Exiting.'); this.exit(1); } // 1. Clone the Template Repo this.log('[1/4] Cloning Template...'); try { await fs_1.downloadRepo(constants_1.TEMPLATE_REPO, path_1.default.join(process.cwd(), folderName)); fs_1.deleteFolder(path_1.default.join(process.cwd(), folderName, '.git')); } catch (error) { this.error('A fatal error occurred during cloning template', error); this.exit(1); } // 2. Delete Unused Folders this.log('[2/4] Deleting Unused Resources...'); try { const capabilitiesToRemove = constants_1.ALL_CAPABILITIES.filter(capability => !parameters.capabilities.includes(capability)); for (const capability of capabilitiesToRemove) { fs_1.deleteFolder(path_1.default.join(process.cwd(), folderName, 'src', capability)); } fs_1.deleteFolder(path_1.default.join(process.cwd(), folderName, '.github', 'ISSUE_TEMPLATE')); fs_1.deleteFile(path_1.default.join(process.cwd(), 'webpack.config.ts')); fs_1.deleteFile(path_1.default.join(process.cwd(), 'src', 'router.tsx')); fs_1.deleteFile(path_1.default.join(process.cwd(), 'src', 'capabilities.ts')); } catch (error) { this.error('A fatal error occurred while deleting unused resources', error); this.exit(2); } // 3. Configure Dynamic Files this.log('[3/4] Configuring Dynamic Files...'); try { fs_1.copyFile(path_1.default.join(__dirname, '..', 'templates', 'webpack.config.ts'), path_1.default.join(process.cwd(), folderName, 'webpack.config.ts')); fs_1.copyFile(path_1.default.join(__dirname, '..', 'templates', 'router.tsx'), path_1.default.join(process.cwd(), folderName, 'src', 'router.tsx')); fs_1.copyFile(path_1.default.join(__dirname, '..', 'templates', 'capabilities.ts'), path_1.default.join(process.cwd(), folderName, 'src', 'capabilities.ts')); const applicableCapabilities = constants_1.ALL_HTML_BACKED_CAPABILITIES.filter(c => parameters.capabilities.includes(c)); for (const capability of applicableCapabilities.reverse()) { // 3.1 - Webpack Config File replace.replaceInFileSync({ files: path_1.default.join(process.cwd(), folderName, 'webpack.config.ts'), from: constants_1.WEBPACK_REPLACEMENT_STRING, to: string_1.getWebpackHtmlPlugin(capability), }); // 3.2 React Router File replace.replaceInFileSync({ files: path_1.default.join(process.cwd(), folderName, 'src', 'router.tsx'), from: constants_1.REACT_ROUTER_MODULE_REPLACEMENT_STRING, to: string_1.getReactRouterRoute(capability), }); replace.replaceInFileSync({ files: path_1.default.join(process.cwd(), folderName, 'src', 'router.tsx'), from: constants_1.REACT_ROUTER_LOADER_REPLACEMENT_STRING, to: string_1.getReactRouterLoader(capability), }); } for (const capability of parameters.capabilities) { // 3.3 Capabilities File replace.replaceInFileSync({ files: path_1.default.join(process.cwd(), folderName, 'src', 'capabilities.ts'), from: constants_1.CAPABILITIES_IMPORT_REPLACEMENT_STRING, to: string_1.getCapabilityImport(capability), }); replace.replaceInFileSync({ files: path_1.default.join(process.cwd(), folderName, 'src', 'capabilities.ts'), from: constants_1.CAPABILITIES_REPLACEMENT_STRING, to: string_1.getCapabilityModule(capability), }); } // 3.4 Environmental Variables File const powerupId = args.powerupId ? args.powerupId : 'UNSPECIFIED'; const apiKey = args.apiKey ? args.apiKey : 'UNSPECIFIED'; const licenseType = args.licenseType ? args.licenseType : 'UNSPECIFIED'; fs_1.writeToFile(path_1.default.join(process.cwd(), folderName, '.env'), string_1.getEnv(powerupId, folderName, apiKey, licenseType)); // 3.6 Monetization // 3.6.1 Add Dependency for the Optro API Client fs_1.addDependency(path_1.default.join(process.cwd(), folderName, 'package.json'), '@optro/api-client', '^1.0.3'); // 3.6.2 Add License Provider to Router replace.replaceInFileSync({ files: path_1.default.join(process.cwd(), folderName, 'src', 'router.tsx'), from: constants_1.REACT_ROUTER_IMPORT_REPLACEMENT_STRING, to: string_1.getReactRouterMonetizationImport(), }); replace.replaceInFileSync({ files: path_1.default.join(process.cwd(), folderName, 'src', 'router.tsx'), from: constants_1.REACT_ROUTER_CLIENT_REPLACEMENT_STRING, to: string_1.getReactRouterMonetizationClient(), }); replace.replaceInFileSync({ files: path_1.default.join(process.cwd(), folderName, 'src', 'router.tsx'), from: constants_1.REACT_ROUTER_CLIENT_PROVIDER_REPLACEMENT_STRING, to: string_1.getReactRouterMonetizationProvider(), }); replace.replaceInFileSync({ files: path_1.default.join(process.cwd(), folderName, 'src', 'router.tsx'), from: constants_1.REACT_ROUTER_CLIENT_PROVIDER_CLOSE_REPLACEMENT_STRING, to: string_1.getReactRouterMonetizationProviderClose(), }); // 3.6.2 Add Example Licensed Feature (Colorized Cards) if (parameters.capabilities.includes('card-buttons')) { // 3.6.3 Add import for LicenseConditional to the Card Button component replace.replaceInFileSync({ files: path_1.default.join(process.cwd(), folderName, 'src', 'card-button', 'CardButton.tsx'), from: constants_1.CARD_BUTTON_CONDITIONAL_IMPORT_REPLACEMENT_STRING, to: string_1.getCardButtonMonetizationImport(), }); // 3.6.4 Add LicenseConditional to the Render Code replace.replaceInFileSync({ files: path_1.default.join(process.cwd(), folderName, 'src', 'card-button', 'CardButton.tsx'), from: constants_1.CARD_BUTTON_CONDITIONAL_START_REPLACEMENT_STRING, to: string_1.getCardButtonMonetizationStartTag(), }); replace.replaceInFileSync({ files: path_1.default.join(process.cwd(), folderName, 'src', 'card-button', 'CardButton.tsx'), from: constants_1.CARD_BUTTON_CONDITIONAL_END_REPLACEMENT_STRING, to: string_1.getCardButtonMonetizationEndTag(), }); // 3.6.5 Add License Status Display replace.replaceInFileSync({ files: path_1.default.join(process.cwd(), folderName, 'src', 'card-button', 'CardButton.tsx'), from: constants_1.CARD_BUTTON_STATUS_REPLACEMENT_STRING, to: string_1.getLicenseStatusTag(), }); } // 3.5 Cleanup Unused Dependencies if (!parameters.capabilities.includes('card-back-section')) { fs_1.deleteDependency(path_1.default.join(process.cwd(), folderName, 'package.json'), 'lottie-react'); } if (!parameters.capabilities.includes('attachment-thumbnail')) { fs_1.deleteDependency(path_1.default.join(process.cwd(), folderName, 'package.json'), 'unique-names-generator'); } if (!parameters.capabilities.includes('card-buttons')) { fs_1.deleteDependency(path_1.default.join(process.cwd(), folderName, 'package.json'), 'react-color'); } } catch (error) { this.error('A fatal error occurred during configuring dynamic files', error); this.exit(3); } // 4. Install Dependencies this.log('[4/4] Installing Dependencies...'); try { child_process_1.execSync(`yarn --cwd "${path_1.default.join(process.cwd(), folderName)}" install --silent`, { stdio: 'inherit' }); } catch (error) { this.error('A fatal error occurred during installing dependencies', error); this.exit(4); } // Build complete this.log(); this.log('┌' + '─'.repeat(29) + '┐'); this.log('│ Finished building Power-Up! │'); this.log('└' + '─'.repeat(29) + '┘'); this.log(); const doneParameters = await inquirer.prompt([ { name: 'start', message: 'Start the Power-Up in Development Mode (yarn watch)?', type: 'confirm', default: true, }, ]); if (doneParameters.start) { child_process_1.execSync(`yarn --cwd "${path_1.default.join(process.cwd(), folderName)}" watch`, { stdio: 'inherit' }); } } } CreateTrelloPowerup.description = 'Easily create Trello Power-Ups from the Command Line'; CreateTrelloPowerup.flags = { version: command_1.flags.version({ char: 'v' }), help: command_1.flags.help({ char: 'h' }), }; CreateTrelloPowerup.args = constants_1.INPUT_ARGUMENTS; module.exports = CreateTrelloPowerup;