/* Copyright IBM Corp. 2017 */ import { escapeRegExp } from 'lodash'; import { resolve } from 'path'; import { combineLatest, concat, defer, Observable } from 'rxjs'; import { map, mergeMap, shareReplay, toArray } from 'rxjs/operators'; import { isString } from 'util'; import { arrayOf, firstOf } from '../utils/file.utils'; import { CMD_CREATE, OPTION_DATA, OPTION_EDITABLE, OPTION_FLAT, OPTION_NAME, OPTION_SCSS, OPTION_SOURCE, OPTION_TYPE, OPTION_VERBOSE, } from './../constants'; import { LayoutNameMapper, Options, optNormalizeDir } from './../options'; import { assertNotNull, assertParameter } from './../utils/assert'; import { camelCase } from './../utils/transliteration'; import { AbstractCommand } from './abstract.command'; import { Command } from './command'; import { CreateVueCommand } from './create.vue.command'; import { CreateLayoutsCommand } from './create.layouts.command'; import { HELP_COMPONENT_SOURCE, HELP_DATA_DIRECTORY, HELP_EDITABLE, HELP_FLAT, HELP_LAYOUT_NAME, HELP_LAYOUT_TYPE, HELP_SCSS, HELP_VERBOSE, } from './help'; function _createLayoutNameMapper(aLayoutName: string): LayoutNameMapper { return (aNumber: number, aTotal: number, aTypeName: string) => camelCase(aLayoutName); } /** * create layout --data --src --type [--name ] [--verbose] [--flat] [--scss] */ export class CreateLayoutCommand extends AbstractCommand implements Command { static readonly TYPE = 'layout'; static readonly COMMAND = CMD_CREATE; constructor(private options: Options) { super(options); } printHelp(): void { // log the command line console.log(CreateLayoutCommand.COMMAND, CreateLayoutCommand.TYPE, `--${OPTION_SOURCE} `, `--${OPTION_DATA} `, `--${OPTION_TYPE} `, `[--${OPTION_NAME} ]`, `[--${OPTION_FLAT}]`, `[--${OPTION_SCSS}]`, `[--${OPTION_EDITABLE}]`, `[--${OPTION_VERBOSE}]`); // log the parameters console.log(`--${OPTION_SOURCE} `, ':', HELP_COMPONENT_SOURCE); console.log(`--${OPTION_DATA} `, ':', HELP_DATA_DIRECTORY); console.log(`--${OPTION_TYPE} `, ':', HELP_LAYOUT_TYPE); console.log(`--${OPTION_NAME} `, ':', HELP_LAYOUT_NAME); console.log(`--${OPTION_FLAT}`, ':', HELP_FLAT); console.log(`--${OPTION_SCSS}`, ':', HELP_SCSS); console.log(`--${OPTION_EDITABLE}`, ':', HELP_EDITABLE); console.log(`--${OPTION_VERBOSE}`, ':', HELP_VERBOSE); } process(): Observable { // defer return defer(() => { // current options const opts = this.options; // the directories const dataDirOpt = this.getDataDir(); const srcDirOpt = resolve(firstOf(opts.src) || this.getAppDir()); // fallback source directories const srcDirs = (arrayOf(opts.src) || [srcDirOpt]).map(optNormalizeDir); // construct the directories const rxDataDir = this.rxMkdirp(dataDirOpt); const rxSrcDir = this.rxMkdirp(srcDirOpt).pipe( shareReplay(1)); const rxSrcDirs = concat(...srcDirs.map(dir => this.rxMkdirp(dir))).pipe( toArray(), shareReplay(1) ); // logger const logger = this.getLogger(); // validate the existence of the type attribute assertParameter(opts.type, OPTION_TYPE); assertNotNull(dataDirOpt, OPTION_DATA); assertNotNull(srcDirOpt, OPTION_SOURCE); // type pattern const includePattern = `^${escapeRegExp(opts.type)}$`; // name of the layout const mapper: LayoutNameMapper | undefined = isString(opts.name) ? _createLayoutNameMapper(opts.name) : undefined; // log the name logger.next(`Data dir [${dataDirOpt}], source dir [${srcDirOpt}], type [${opts.type}], name [${opts.name}].`); // log the pattern logger.next(`Using regular expression [${includePattern}].`); // create the mappings const createLayoutsOpts: Observable = rxDataDir.pipe(map(aDataDir => ({ command: CreateLayoutsCommand.COMMAND, commandType: CreateLayoutsCommand.TYPE, data: aDataDir, verbose: opts.verbose, flat: opts.flat, module: opts.module, modules: opts.modules, include: includePattern, count: 1, layoutNameMapper: mapper, allArgs: opts.allArgs }))); // create the components const CreateVueOpts: Observable = combineLatest([rxDataDir, rxSrcDirs]).pipe(map(([aDataDir, aSrcDirs]) => ({ command: CreateVueCommand.COMMAND, commandType: CreateVueCommand.TYPE, data: aDataDir, include: includePattern, src: aSrcDirs, scss: opts.scss, flat: opts.flat, module: opts.module, modules: opts.modules, skipRegistration: opts.skipRegistration, layoutHtmlTemplate: opts.layoutHtmlTemplate, editable: opts.editable, verbose: opts.verbose, allArgs: opts.allArgs }))); // construct the layouts const rxLayouts = createLayoutsOpts.pipe(map(o => new CreateLayoutsCommand(o)), mergeMap(cmd => cmd.process())); // construct the components const rxComponents = CreateVueOpts.pipe(map(o => new CreateVueCommand(o)), mergeMap(cmd => cmd.process())); // chain return concat(rxLayouts, rxComponents); }); } }