UNPKG

generator-terminus-ui

Version:

A generator for adding new components to the Terminus UI library.

322 lines (281 loc) 9.81 kB
/* eslint-disable no-console */ 'use strict'; const Generator = require('yeoman-generator'); const chalk = require('chalk'); const yosay = require('yosay'); const _startCase = require('lodash.startcase'); const mkdirp = require('mkdirp'); const utilities = require('./../utilities.js'); const LIB_PREFIX = 'Ts'; const COMPONENT_PREFIX = LIB_PREFIX.toLowerCase(); const COMPONENT_SUFFIX = 'Component'; const MODULE_SUFFIX = 'Module'; const MODULE_FILE = 'terminus-ui/src/module.ts'; const INDEX_PATH = 'terminus-ui/src/index.ts'; const DEMO_COMPONENT_PATH = `demo/app/components/`; const DEMO_COMPONENTS_FILE = `${DEMO_COMPONENT_PATH}/components.constant.ts`; const DEMO_MODULE_FILE = `demo/app/app.module.ts`; const CS_CONFIG_FILE = `tooling/cz-config.js`; const QA_PREFIX = 'qa'; /* * Full path for component: * * 1. Generate all files (module, component html|scss|spec|ts) * 2. Import file to terminus-ui/src/module.ts * 3. Add to imports array in terminus-ui/src/module.ts * 4. Add to exports array in terminus-ui/src/module.ts * 5. Export file from terminus-ui/src/index.ts * 6. Create demo component * 7. Add component to components.ts components array * 7. Add component to demo module * 8. Add route for component * 9. Add new scope to `cz-config` */ module.exports = class extends Generator { // Note: arguments and options should be defined in the constructor. constructor(args, opts) { super(args, opts); // Require a component name to be passed in this.argument('name', { type: String, desc: 'The name of the component (`button` or `my-button`)', required: true, }); // Name: `button` // Pretty: `My Button` this.options.prettyName = _startCase(this.options.name); // Pascal: `MyButton` this.options.pascalName = this.options.prettyName.replace(/ +/g, ''); // Module name: `TsMyButtonModule` this.options.moduleName = `${LIB_PREFIX}${this.options.pascalName}${MODULE_SUFFIX}`; // Component name: `TsMyButtonComponent` this.options.componentName = `${LIB_PREFIX}${this.options.pascalName}${COMPONENT_SUFFIX}`; // Component selector: `ts-my-button` this.options.componentSelector = `${COMPONENT_PREFIX}-${this.options.name}`; // Lowercased first character component name: `myButton` this.options.camelCaseName = this.options.pascalName.charAt(0).toLowerCase() + this.options.pascalName.slice(1); // QA flag name: `qa-my-button` this.options.qaFlagName = `${QA_PREFIX}-${this.options.name}`; } /** * Create the new UI component */ createComponentFiles() { this.log(yosay( `Generating ${chalk.red(this.options.name)} component.` )); this.log('Generating files.'); const destinationDir = this.destinationPath(`terminus-ui/src/${this.options.name}/`); mkdirp(destinationDir, (err) => { if (err) { console.error(err); } else { // Create the component module this.fs.copyTpl( this.templatePath('module.ts'), this.destinationPath(`${destinationDir}/${this.options.name}.module.ts`), { kebabName: this.options.name, moduleName: this.options.moduleName, componentName: this.options.componentName, pascalName: this.options.pascalName, } ); // Create the component TS this.fs.copyTpl( this.templatePath('component.ts'), this.destinationPath(`${destinationDir}/${this.options.name}.component.ts`), { kebabName: this.options.name, componentName: this.options.componentName, } ); // Create the component SCSS this.fs.copyTpl( this.templatePath('component.scss'), this.destinationPath(`${destinationDir}/${this.options.name}.component.scss`), { kebabName: this.options.name, prettyName: this.options.prettyName, } ); // Create the component HTML this.fs.copyTpl( this.templatePath('component.html'), this.destinationPath(`${destinationDir}/${this.options.name}.component.html`), { pascalName: this.options.pascalName, qaFlagName: this.options.qaFlagName, } ); // Create the component spec this.fs.copyTpl( this.templatePath('component.spec.ts'), this.destinationPath(`${destinationDir}/${this.options.name}.component.spec.ts`), { kebabName: this.options.name, componentName: this.options.componentName, camelCaseComponentName: this.options.camelCaseName, } ); // Create the component MD this.fs.copyTpl( this.templatePath('component.md'), this.destinationPath(`${destinationDir}/${this.options.name}.component.md`), { kebabName: this.options.name, } ); } }); } /** * Inject the new component into the UI module */ injectComponentInLibrary() { this.log( `Injecting the new ${chalk.red(this.options.prettyName)} component to the UI library.` ); // Import to the module file utilities.addToFile( MODULE_FILE, `import { ${this.options.moduleName} } from './${this.options.name}/${this.options.name}.module';`, utilities.MARKERS.importUiComponentToUiModule ); // Add to imports array utilities.addToFile( MODULE_FILE, `${this.options.moduleName},`, utilities.MARKERS.addUiComponentToUiModuleImportArray ); // Add to exports array utilities.addToFile( MODULE_FILE, `${this.options.moduleName},`, utilities.MARKERS.addUiComponentToUiModuleExports ); // Export from the primary index file utilities.addToFile( INDEX_PATH, `export * from './${this.options.name}/${this.options.name}.module';`, utilities.MARKERS.addUiComponentIndexExport ); } /** * Create the demo component */ addDemoComponent() { this.log( `Creating the new ${chalk.red(this.options.prettyName)} component in the demo project.` ); const destinationDir = this.destinationPath(`${DEMO_COMPONENT_PATH}/${this.options.name}`); mkdirp(destinationDir, err => { if (err) { console.error('Error adding demo files: ', err); } else { // Create the demo component this.fs.copyTpl( this.templatePath('demo.ts'), this.destinationPath(`${destinationDir}/${this.options.name}.component.ts`), { kebabName: this.options.name, pascalName: this.options.pascalName, selector: this.options.componentSelector, } ); } }); } /** * Create the demo component */ addDemoHtml() { this.log( `Creating the new ${chalk.red(this.options.prettyName)} component HTML in the demo project.` ); const destinationDir = this.destinationPath(`${DEMO_COMPONENT_PATH}/${this.options.name}`); mkdirp(destinationDir, err => { if (err) { console.error('Error adding demo files: ', err); } else { // Create the demo component this.fs.copyTpl( this.templatePath('demo.html'), this.destinationPath(`${destinationDir}/${this.options.name}.component.html`), { kebabName: this.options.name, pascalName: this.options.pascalName, selector: this.options.componentSelector, } ); } }); } /** * Inject the demo component into the demo app */ injectDemoComponent() { this.log( `Injecting the new ${chalk.red(this.options.prettyName)} component into the demo project.` ); // NOTE: This indentation is 'off' by design. This will generate the correct indentation when // injected. const route = `{ path: '${this.options.name}', component: ${this.options.pascalName}Component, data: { name: '${this.options.prettyName}', }, },`; // Import the demo component utilities.addToFile( DEMO_COMPONENTS_FILE, `import { ${this.options.pascalName}Component } from './${this.options.name}/${this.options.name}.component';`, utilities.MARKERS.addDemoComponentImportToConstants ); // Add the demo route utilities.addToFile( DEMO_COMPONENTS_FILE, route, utilities.MARKERS.addRouteForDemoComponent ); // Import the new UI component from the library utilities.addToFile( DEMO_MODULE_FILE, `${this.options.moduleName},`, utilities.MARKERS.addUiComponentToDemoImports ); // Add the UI module to the demo module imports array utilities.addToFile( DEMO_MODULE_FILE, `${this.options.moduleName},`, utilities.MARKERS.addUiComponentToUiImports ); // Import the demo component file utilities.addToFile( DEMO_MODULE_FILE, `import { ${this.options.pascalName}Component } from './components/${this.options.name}/${this.options.name}.component';`, utilities.MARKERS.importDemoComponentToDemoModule ); // Add the demo component to the declarations array utilities.addToFile( DEMO_MODULE_FILE, `${this.options.pascalName}Component,`, utilities.MARKERS.addDemoComponentToDeclarations ); } /** * Add the new component as an available scope in commitizen */ addCommitizenScope() { this.log( `Adding a new commit scope for ${chalk.red(this.options.pascalName)}.` ); utilities.addToFile( CS_CONFIG_FILE, `{name: '${this.options.pascalName}'},`, utilities.MARKERS.addUiComponentAsCommitizenScope ); } };