import inquirer = require('inquirer'); import * as path from 'path'; import * as jsonfile from 'jsonfile'; import * as _ from 'lodash'; import * as async from 'async'; import * as fs from 'fs'; import * as shelljs from 'shelljs'; import * as ejs from 'ejs'; import {default as chalk} from 'chalk'; let simpleGit = require('simple-git/promise'); export class ExtLB { logo: string = chalk.green(` ( ) )\\ ) ( ( ) ( /((()/( ( )\\ )\\ ( /( )\\())/(_)))((_) ((_) )\\())(_))/(_)) ((_)_ | __|((_)\\ | |_ | | | _ ) | _| \\ \\ / | _|| |__ | _ \\ |___|/_\\_\\ \\__||____||___/ `); versions: string[] = ['v1']; authentication: object[] = [{name: 'User', value: 'users'},{name: 'Accounts', value: 'accounts'}]; platforms: object[] = [{name:'desktop', checked: true}, {name:'phone'}]; features: object[] = [ new inquirer.Separator('ExtLoop Features'), { name: 'Browserify', value: 'browserify', checked: true }, { name: 'Socket.IO', value: 'socketio', checked: true }, { name: 'Authentication', value: 'auth', checked: true }, { name: 'Queues', value: 'queues' }, new inquirer.Separator('ExtLoop Perspectives'), { name: 'Admin', value: 'perspective-admin', checked: true }, { name: 'Auth', value: 'perspective-auth', checked: true }, { name: 'Error', value: 'perspective-error', checked: true }, { name: 'Main', value: 'perspective-main', checked: true } ]; models: object[] = [ {name: 'Model', value: 'Model'}, {name: 'PersistedModel', value: 'PersistedModel'}, {name: 'ACL', value: 'ACL'}, {name: 'AccessToken', value: 'AccessToken'}, {name: 'Application', value: 'Application'}, {name: 'Change', value: 'Change'}, {name: 'Checkpoint', value: 'Checkpoint'}, {name: 'Email', value: 'Email'}, {name: 'KeyValueModel', value: 'KeyValueModel'}, {name: 'Role', value: 'Role'}, {name: 'RoleMapping', value: 'RoleMapping'}, {name: 'Scope', value: 'Scope'}, {name: 'User', value: 'User'}, {name: '(custom)', value: 'custom'} ]; constructor() { } static checkAvailable(dir: string): boolean { return !shelljs.test('-e', path.join(dir, 'package.json')); } createApp(options: { name: string, camelName: string, snakeName: string, capitalName: string, description: string, version: string, authType: string, platforms: [string], features: [string]}) { console.log('Creating Application', options); if (ExtLB.checkAvailable(process.cwd())) { process.stdout.write(chalk.keyword('limegreen')('Retrieving application template ')); simpleGit().clone('https://gitlab.com/ExtLB/app-template.git', '.').then(() => { process.stdout.write(chalk.keyword('limegreen')(' done!\n')); shelljs.rm('-fr', '.git'); if (!_.includes(options.platforms, 'desktop')) { shelljs.rm('-fr', ['config/client/desktop.json', 'resources/moderndesktop', 'app/desktop']); } if (!_.includes(options.platforms, 'phone')) { shelljs.rm('-fr', ['config/client/phone.json', 'resources/modernphone', 'app/phone']); } let modifications: any = {}; _.filter(shelljs.ls(`${__dirname}${path.sep}app${path.sep}*.ts`), (file) => { return !_.endsWith(file, '.d.ts'); }).map((file) => { return file.substr(0, file.length - 3); }).forEach((changer) => { modifications[changer] = require(`${changer}`).default; }); let modifiers: any = {}; _.each(modifications, (files) => { _.each(files, (changes, file) => { if (_.isUndefined(modifiers[file])) { modifiers[file] = []; } modifiers[file].push(changes); }); }); process.stdout.write(chalk.keyword('limegreen')(`Modifying ${_.keys(modifiers).length} files `)); let files = _.keys(modifiers); _.each(files, (file) => { let content: any = null; if (_.endsWith(file, '.json')) { content = jsonfile.readFileSync(file); } else { content = fs.readFileSync(file, {encoding: 'utf8'}); } modifiers[file].forEach((modifier: (options: object, content: any) => object) => { content = modifier(options, content); }); process.stdout.write('.'); if (_.isNull(content)) { shelljs.rm(file); } else { if (_.endsWith(file, '.json')) { jsonfile.writeFileSync(file, content, {spaces: 2}); } else { fs.writeFileSync(file, content, {encoding: 'utf8'}); } } }); process.stdout.write(chalk.keyword('limegreen')(' done!\n')); console.log(chalk.keyword('limegreen')('Installing/Building Modules (npm install)')); shelljs.exec('npm install', {silent:false}, () => { console.log(chalk.keyword('limegreen')('Modules Installed!')); if ( _.includes(options.features, 'perspective-admin') || _.includes(options.features, 'perspective-auth') || _.includes(options.features, 'perspective-error') || _.includes(options.features, 'perspective-main') || _.includes(options.features, 'auth') ) { let perspectives = _.filter(options.features, (feature) => { return _.startsWith(feature, 'perspective-'); }).map((feature) => { return `@extlb/${feature}`; }); let installs: async.Dictionary> = {}; // let installs: {perspectives?: Function, authentication?: Function} = {}; if (perspectives.length !== 0) { installs.perspectives = (cb: (err?: {}, result?: {}) => void) => { process.stdout.write(chalk.keyword('limegreen')(`Installing ${perspectives.length} Perspectives `)); shelljs.exec(`npm install ${perspectives.join(' ')} -S`, {silent:true}, (err) => { if (err) { console.error(err); cb(err); } else { process.stdout.write(chalk.keyword('limegreen')(' done!\n')); cb(); } }); }; } if (_.includes(options.features, 'auth')) { if (options.authType === 'users') { installs.authentication = (cb: (err?: {}, result?: {}) => void) => { process.stdout.write(chalk.keyword('limegreen')('Installing Authentication Module ')); shelljs.exec('npm install @extlb/auth -S', {silent: true}, (err) => { if (err) { console.error(err); cb(err); } else { process.stdout.write(chalk.keyword('limegreen')(' done!\n')); cb(); } }); }; } else if (options.authType === 'accounts') { installs.authentication = (cb: (err?: {}, result?: {}) => void) => { process.stdout.write(chalk.keyword('limegreen')('Installing Accounts Module ')); shelljs.exec('npm install @extlb/module-admin-accounts -S', {silent: true}, (err) => { if (err) { console.error(err); cb(err); } else { process.stdout.write(chalk.keyword('limegreen')(' done!\n')); cb(); } }); }; } } installs.grunt = (cb: (err?: {}, result?: {}) => void) => { process.stdout.write(chalk.keyword('limegreen')('Building application ')); shelljs.exec('grunt "Build Testing Desktop"', {silent:true}, (err) => { if (err) { console.error(err); cb(err); } else { process.stdout.write(chalk.keyword('limegreen')(' done!\n')); cb(); } }); }; async.series(installs, (err) => { if (err) { console.log(err); } else { console.log(chalk.keyword('limegreen')('Install Completed!')); } }); } }); }).catch((err: any) => { console.error(err); }); } else { console.log(chalk.red('package.json already exists!\n')); } // console.log(modifiers); } createModule(options: { name: string, camelName: string, snakeName: string, capitalName: string, server: boolean, client: boolean}) { console.log('Creating Module', options); if (ExtLB.checkAvailable(process.cwd())) { process.stdout.write(chalk.keyword('limegreen')('Retrieving module template ')); simpleGit().clone('https://gitlab.com/ExtLB/module-template.git', '.').then(() => { process.stdout.write(chalk.keyword('limegreen')(' done!\n')); shelljs.rm('-fr', '.git'); let modifications: any = {}; _.filter(shelljs.ls(`${__dirname}${path.sep}module${path.sep}*.ts`), (file) => { return !_.endsWith(file, '.d.ts'); }).map((file) => { return file.substr(0, file.length - 3); }).forEach((changer) => { modifications[changer] = require(`${changer}`).default; }); let modifiers: any = {}; _.each(modifications, (files) => { _.each(files, (changes, file) => { if (_.isUndefined(modifiers[file])) { modifiers[file] = []; } modifiers[file].push(changes); }); }); process.stdout.write(chalk.keyword('limegreen')(`Modifying ${_.keys(modifiers).length} files `)); let files = _.keys(modifiers); _.each(files, (file) => { let content: any = null; if (_.endsWith(file, '.json')) { content = jsonfile.readFileSync(file); } else { content = fs.readFileSync(file, {encoding: 'utf8'}); } modifiers[file].forEach((modifier: (options: object, content: any) => object) => { content = modifier(options, content); }); process.stdout.write('.'); if (_.isNull(content)) { shelljs.rm(file); } else { if (_.endsWith(file, '.json')) { jsonfile.writeFileSync(file, content, {spaces: 2}); } else { fs.writeFileSync(file, content, {encoding: 'utf8'}); } } }); process.stdout.write(chalk.keyword('limegreen')(' done!\n')); process.stdout.write(chalk.keyword('limegreen')('Relocating 2 paths ')); shelljs.mv(`app${path.sep}desktop${path.sep}src${path.sep}view${path.sep}template`, `app${path.sep}desktop${path.sep}src${path.sep}view${path.sep}${options.name}`); process.stdout.write('.'); shelljs.mv(`locales${path.sep}en-US${path.sep}mod-template.json`, `locales${path.sep}en-US${path.sep}mod-${options.name}.json`); process.stdout.write('.'); process.stdout.write(chalk.keyword('limegreen')(' done!\n')); console.log(chalk.keyword('limegreen')('Installing/Building Modules (npm install)')); shelljs.exec('npm install', {silent:false}, () => { console.log(chalk.keyword('limegreen')('Modules Installed!')); }); }).catch((err: any) => { console.error(err); }); } else { console.log(chalk.red('package.json already exists!\n')); } } createPerspective(options: { name: string, camelName: string, snakeName: string, capitalName: string, server: boolean, client: boolean}) { console.log('Creating Perspective', options); if (ExtLB.checkAvailable(process.cwd())) { process.stdout.write(chalk.keyword('limegreen')('Retrieving perspective template ')); simpleGit().clone('https://gitlab.com/ExtLB/perspective-template.git', '.').then(() => { process.stdout.write(chalk.keyword('limegreen')(' done!\n')); shelljs.rm('-fr', '.git'); let modifications: any = {}; _.filter(shelljs.ls(`${__dirname}${path.sep}perspective${path.sep}*.ts`), (file) => { return !_.endsWith(file, '.d.ts'); }).map((file) => { return file.substr(0, file.length - 3); }).forEach((changer) => { modifications[changer] = require(`${changer}`).default; }); let modifiers: any = {}; _.each(modifications, (files) => { _.each(files, (changes, file) => { if (_.isUndefined(modifiers[file])) { modifiers[file] = []; } modifiers[file].push(changes); }); }); process.stdout.write(chalk.keyword('limegreen')(`Modifying ${_.keys(modifiers).length} files `)); let files = _.keys(modifiers); _.each(files, (file) => { let content: any = null; if (_.endsWith(file, '.json')) { content = jsonfile.readFileSync(file); } else { content = fs.readFileSync(file, {encoding: 'utf8'}); } modifiers[file].forEach((modifier: (options: object, content: any) => object) => { content = modifier(options, content); }); process.stdout.write('.'); if (_.isNull(content)) { shelljs.rm(file); } else { if (_.endsWith(file, '.json')) { jsonfile.writeFileSync(file, content, {spaces: 2}); } else { fs.writeFileSync(file, content, {encoding: 'utf8'}); } } }); process.stdout.write(chalk.keyword('limegreen')(' done!\n')); process.stdout.write(chalk.keyword('limegreen')('Relocating 7 paths ')); shelljs.mv(`app${path.sep}desktop${path.sep}src${path.sep}model${path.sep}perspective${path.sep}template`, `app${path.sep}desktop${path.sep}src${path.sep}model${path.sep}perspective${path.sep}${options.name}`); process.stdout.write('.'); shelljs.mv(`app${path.sep}desktop${path.sep}src${path.sep}view${path.sep}perspective${path.sep}template`, `app${path.sep}desktop${path.sep}src${path.sep}view${path.sep}perspective${path.sep}${options.name}`); process.stdout.write('.'); shelljs.mv(`locales${path.sep}en-US${path.sep}per-template.json`, `locales${path.sep}en-US${path.sep}per-${options.name}.json`); process.stdout.write('.'); shelljs.mv(`server${path.sep}models${path.sep}template-navigation.js`, `server${path.sep}models${path.sep}${options.name}-navigation.js`); process.stdout.write('.'); shelljs.mv(`server${path.sep}models${path.sep}template-navigation.json`, `server${path.sep}models${path.sep}${options.name}-navigation.json`); process.stdout.write('.'); shelljs.mv(`server${path.sep}models${path.sep}template-notification.ts`, `server${path.sep}models${path.sep}${options.name}-notification.ts`); process.stdout.write('.'); shelljs.mv(`server${path.sep}models${path.sep}template-notification.json`, `server${path.sep}models${path.sep}${options.name}-notification.json`); process.stdout.write(chalk.keyword('limegreen')(' done!\n')); console.log(chalk.keyword('limegreen')('Installing/Building Modules (npm install)')); shelljs.exec('npm install', {silent:false}, () => { console.log(chalk.keyword('limegreen')('Modules Installed!')); }); }).catch((err: any) => { console.error(err); }); } else { console.log(chalk.red('package.json already exists!\n')); } } createModel(options: { name: string, camelName: string, snakeName: string, capitalName: string, pluralName: string, dataSource: string, baseClass: string, public: boolean, type: string}) { console.log('Creating Model', options); if (!ExtLB.checkAvailable(process.cwd())) { let modelDir = `${process.cwd()}${path.sep}${options.type}${path.sep}models${path.sep}`; if (!shelljs.test('-d', modelDir)) { shelljs.mkdir('-p', modelDir); } let modelConfigFile = `${modelDir}${options.snakeName}.json`; let modelConfig = jsonfile.readFileSync(`${__dirname}${path.sep}model${path.sep}config.json`); modelConfig.name = options.name; modelConfig.plural = options.pluralName; modelConfig.base = options.baseClass; jsonfile.writeFileSync(modelConfigFile, modelConfig, {spaces: 2}); let modelCodeFile = `${modelDir}${options.snakeName}.ts`; let modelCode = fs.readFileSync(`${__dirname}${path.sep}model${path.sep}code.ejs`, {encoding: 'utf8'}); modelCode = ejs.render(modelCode, {options: options}); fs.writeFileSync(modelCodeFile, modelCode); if (shelljs.test('-e', `${process.cwd()}${path.sep}config${path.sep}server${path.sep}model-config.json`)) { let modelsFile = `${process.cwd()}${path.sep}config${path.sep}server${path.sep}model-config.json`; let modelsContent = jsonfile.readFileSync(modelsFile); modelsContent[options.name] = {dataSource: options.dataSource, public: options.public}; jsonfile.writeFileSync(modelsFile, modelsContent, {spaces: 2}); } else if (shelljs.test('-e', `${process.cwd()}${path.sep}server${path.sep}model-config.json`)) { let modelsFile = `${process.cwd()}${path.sep}server${path.sep}model-config.json`; let models = jsonfile.readFileSync(modelsFile); if (!_.isObject(models)) { models.models = {}; } models.models[options.name] = {dataSource: options.dataSource, public: options.public}; jsonfile.writeFileSync(modelsFile, models, {spaces: 2}); } else { console.log(chalk.red('model-config.json missing')); } } else { console.log(chalk.red('package.json missing!\n')); } } createView(options: { name: string, camelName: string, snakeName: string, capitalName: string}) { console.log('Creating View', options); } } let extLoop = new ExtLB(); export default extLoop;