@qbyco/tjs-cli
Version:
TrafaletJS CLI Tool
570 lines (445 loc) • 15.8 kB
JavaScript
const fs = require("fs");
const path = require("path");
const mkdirp = require('mkdirp');
const gulp = require('gulp');
const gulpweb = require('gulp-webserver');
const rename = require('gulp-rename');
const insert = require('gulp-insert');
const concat = require('gulp-concat');
const uglify = require('gulp-uglify');
const babel = require('gulp-babel');
const pump = require('pump');
const del = require('del');
const es2015 = require('babel-preset-es2015');
const CLICommand = require("../../lib/cli/Command/CLICommand");
const Stub = require("../../lib/stub/stub");
/**
* @module tasks/commands/App
*/
class App extends CLICommand {
/**
* @constructor
* @param lib
*/
constructor(lib) {
super("app");
this.lib = lib;
this.options = {
path: this.lib.cwd,
tjsVersion: 'latest',
tjsPath: './vendor',
appPath: './app',
uiPath: './interface',
statePath: './state',
storagePath: './storage'
};
this.paused = false;
this.configPath = path.join(this.lib.cwd, 'trafaletjs.json');
this.lib.events.on('app:finishCommand', (params) => {
if(this.paused) {
this.finishCommand.apply(this, params);
} else {
console.log(this.lib.chalk.green(' - Setup complete!'));
console.log(this.lib.chalk.yellow('Please open trafaletjs.json and update appPath and uiPath\n'));
}
});
}
/**
* @method createAction
* @param {String} name
* @param {Object} options
*/
createAction(name, options) {
console.log(this.lib.chalk.white('\nTrafaletJS CLI ----------------\n'));
this.paused = true;
if ("object" === typeof name) {
throw new Error("Name must be supplied");
}
// Override properties
Object.assign(this.options, options);
console.log(this.lib.chalk.green(' - Testing app environment'));
this.setAppName(name);
this.setHomePath(path.join(this.options.path, this.getAppName()));
if(fs.existsSync(this.getHomePath())) {
console.log(this.lib.chalk.red.bold(' - A directory with the name ' + name + ' already exist. Process closed'));
process.exit();
}
// Create directory structure
console.log(this.lib.chalk.green(' - Setup directory structure'));
this.createDirectoryStructure();
// Create JSON config file
console.log(this.lib.chalk.green(' - Setup config file'));
this.createJSONConfig();
// Get latest TJS distribution
console.log(this.lib.chalk.green(' - Downloading Trafalet JS distribution'));
this.getLatestTJS();
}
/**
* @method createAction
* @description Set current application as tjs app root
* @param {String} name
* @param {Object} options
*/
initAction (name, options) {
if ("object" === typeof name) {
throw new Error("Name must be supplied");
}
// Override properties
Object.assign(this.options, options);
console.log(this.lib.chalk.green(' - Setup app environment'));
this.setAppName(name);
this.setHomePath(path.join(this.options.path, './'));
// Create JSON config file
console.log(this.lib.chalk.green(' - Setup config file'));
this.createJSONConfig(true);
// Get latest TJS distribution
console.log(this.lib.chalk.green(' - Downloading Trafalet JS distribution'));
this.getLatestTJS();
}
/**
* @method buildAction
* @param {Object} options
*/
buildAction (options) {
console.log(this.lib.chalk.white('\nTrafaletJS CLI ----------------\n'));
if(!fs.existsSync(this.configPath)) {
console.log(this.lib.chalk.red('Config file trafaletjs,json not found in path: ' + this.lib.cwd));
return false;
}
let
config = require (this.configPath),
version = config.version,
distPath = path.join(this.lib.cwd, './dist'),
compress = false,
fileName = '',
build = 'dev-build';
if(undefined !== options['version']) {
version = options['version'];
}
if(undefined !== options['path']) {
distPath = path.join(options['path']);
}
if(undefined !== options['compress']) {
compress = true;
}
const dist = {
es6: config.name + '-' + version + '.es6.js',
es5: config.name + '-' + version + '.es5.js',
dist: config.name + '-' + version + '.dist.js',
dev: config.name + '-' + version + '.dev-build.js'
};
if(!fs.existsSync(distPath)) {
mkdirp.sync(distPath);
}
gulp.task('es6', () => {
return gulp.src([
path.join(this.lib.cwd, 'app.js'),
path.join(this.lib.cwd, './' + config.statePath + '/**/*.*'),
path.join(this.lib.cwd, './' + config.storagePath + '/**/*.*'),
path.join(this.lib.cwd, './' + config.appPath + '/**/*.*'),
path.join(this.lib.cwd, 'boot.js')
])
.pipe(concat(dist.es6))
.pipe(insert.prepend('/** DIST:' + config.name + '-' + version + '**/\n\n'))
.pipe(gulp.dest(distPath));
});
gulp.task('es5', ['es6'], () => {
return gulp.src(path.join(distPath, dist.es6))
.pipe(babel({
presets: [es2015]
}))
.pipe(concat(dist.es5))
.pipe(gulp.dest(distPath));
});
gulp.task('dev-build', ['es5'], () => {
return gulp
.src(path.join(distPath, dist.es5))
.pipe(rename(dist.dev))
.pipe(gulp.dest(distPath));
});
gulp.task('dist', ['es5'], () => {
return gulp.src(path.join(distPath, dist.es5))
.pipe(uglify())
.pipe(rename(dist.dist))
.pipe(gulp.dest(distPath))
});
if(compress) {
console.log(this.lib.chalk.green(' - Build stable version: ' + version));
fileName = dist.dist;
gulp.task ('clean', ['dist'], () => {
fs.unlinkSync(path.join(distPath, dist.es6));
fs.unlinkSync(path.join(distPath, dist.es5));
});
} else {
console.log(this.lib.chalk.green(' - Build dev version: ' + version));
fileName = dist.dev;
gulp.task ('clean', ['dev-build'], () => {
fs.unlinkSync(path.join(distPath, dist.es6));
fs.unlinkSync(path.join(distPath, dist.es5));
});
}
gulp.start.apply(gulp, ['clean']);
if(version !== config.version) {
console.log(this.lib.chalk.green(' - Update app version: ' + config.version + '->' + version));
config.version = version;
fs.writeFileSync(this.configPath, JSON.stringify(config, null, ' '));
}
console.log(this.lib.chalk.green(' - Build complete!'));
console.log(this.lib.chalk.yellow(' Append [' + fileName + '] to your index file to test it out'));
}
/**
* @method watchAction
* @param options
*/
watchAction (options) {
console.log(this.lib.chalk.white('\nTrafaletJS CLI ----------------\n'));
if(!fs.existsSync(this.configPath)) {
console.log(this.lib.chalk.red('Config file trafaletjs,json not found in path: ' + this.lib.cwd));
return false;
}
let port = 9999;
let host = 'localhost';
if(undefined !== options['port']) {
port = parseInt(options['port']);
}
if(undefined !== options['host']) {
host = options['host'];
}
gulp.task('web', () => {
console.log(this.lib.chalk.cyan(' TrafaletJS watch started'));
gulp
.src(this.lib.cwd)
.pipe(gulpweb({
livereload: true,
directoryListing: false,
open: false,
host: host,
port: port
}));
});
gulp.start.apply(gulp, ['web']);
}
/**
* @method getHomePath
* @returns {String|*}
*/
getHomePath() {
return this.homePath;
}
/**
* @method setHomePath
* @param {String} path
*/
setHomePath(path) {
this.homePath = path;
}
/**
* @method getAppName
* @returns {String|*}
*/
getAppName () {
return this.appName;
}
/**
* @method setAppName
* @param {String} name
*/
setAppName (name) {
this.appName = name;
}
/**
* @method finishCommand
*/
finishCommand () {
// Create Hello World App
if(true === this.options.withBoilerplate) {
console.log(this.lib.chalk.green(' - Setup boilerplate application'));
this.copyHelloWorldStructure();
} else {
this.copySimpleStructure();
console.log(this.lib.chalk.yellow(' - Skip boilerplate application'));
}
console.log(this.lib.chalk.green(' - Setup index.html'));
// Create index.html
this.createIndexPage();
console.log(this.lib.chalk.green(' - Setup complete!\n'));
}
/**
* @method createDirectoryEvenIfExists
* @param {String} path
* @returns {App}
*/
createDirectoryEvenIfExists(path) {
if(!fs.existsSync(path)) {
fs.mkdirSync(path);
}
return this;
}
/**
* @method createJSONConfig
* @param empty
* @return {App}
*/
createJSONConfig (empty = false) {
let
jsonTemplate = new Stub('app/tjs.json'),
output = 'trafaletjs.json';
jsonTemplate.parse('name', this.getAppName());
if(empty) {
this.createJSONForExistingProject(jsonTemplate);
} else {
this.createJSONForNewProject(jsonTemplate);
}
const tmpCfgJSON = JSON.parse(jsonTemplate.getStubContent());
// Update project paths
Object.assign(this.options, {
appPath: tmpCfgJSON.appPath,
uiPath: tmpCfgJSON.uiPath,
statePath: tmpCfgJSON.statePath,
storagePath: tmpCfgJSON.storagePath,
rootPath: this.getHomePath()
});
fs.writeFileSync(path.join(this.getHomePath(), output), jsonTemplate.getStubContent());
return this;
}
/**
* @method getLatestTJS
* @description Download trafaletjs
*/
getLatestTJS () {
this.lib.events.emit('manager:install', [
this.options.tjsVersion,
{
path: this.options.tjsPath,
cwd: this.getHomePath()
}
]);
}
copySimpleStructure () {
const appConfigStub = new Stub('components/app.js');
const bootConfigStub = new Stub('components/boot.js');
appConfigStub.parse('name', this.getAppName().capitalizeFirstLetter());
appConfigStub.parse('uiPath', this.options.uiPath);
bootConfigStub.parse('name', this.getAppName().capitalizeFirstLetter());
// Copy app and boot files
fs.writeFileSync(path.join(this.options.rootPath, 'boot.js'), bootConfigStub.getStubContent());
fs.writeFileSync(path.join(this.options.rootPath, 'app.js'), appConfigStub.getStubContent());
return this;
}
/**
* @method copyHelloWorldStructure
* @description Create an app boilerplate using helloworld structure
* @return {App}
*/
copyHelloWorldStructure () {
let
appPath = path.join(this.options.rootPath, this.options.appPath),
uiPath = path.join(this.options.rootPath, this.options.uiPath);
const appConfigStub = new Stub('components/app.js');
const bootConfigStub = new Stub('components/boot.js');
const logicStub = new Stub('app/logic-sample.js');
appConfigStub.parse('name', this.getAppName().capitalizeFirstLetter());
appConfigStub.parse('uiPath', this.options.uiPath);
bootConfigStub.parse('name', this.getAppName().capitalizeFirstLetter());
logicStub.parse('name', this.getAppName().capitalizeFirstLetter());
// Copy logic file
fs.writeFileSync(path.join(appPath, 'app.js'), logicStub.getStubContent());
// Copy module files
mkdirp.sync(path.join(uiPath, 'helloworld/components'));
// Copy module sources
fs.createReadStream(path.join(__dirname, '../../resources/samples/module.js')).pipe(fs.createWriteStream(path.join(uiPath, 'helloworld', 'module.js')));
fs.createReadStream(path.join(__dirname, '../../resources/samples/module.html')).pipe(fs.createWriteStream(path.join(uiPath, 'helloworld','module.html')));
fs.createReadStream(path.join(__dirname, '../../resources/samples/component.js')).pipe(fs.createWriteStream(path.join(uiPath, 'helloworld/components', 'HelloWorld.js')));
// Copy app and boot files
fs.writeFileSync(path.join(this.options.rootPath, 'boot.js'), bootConfigStub.getStubContent());
fs.writeFileSync(path.join(this.options.rootPath, 'app.js'), appConfigStub.getStubContent());
return this;
}
/**
* @method createIndexPage
* @return {App}
*/
createIndexPage () {
let
indexTemplate = new Stub('app/index.html'),
config = require(path.join(this.options.rootPath, 'trafaletjs'));
indexTemplate.parse('name', config.name);
indexTemplate.parse('tjs-path', path.join(this.options.tjsPath, 'trafaletjs-' + config.tjs.version + '.js'));
indexTemplate.parse('app-path', 'app.js');
indexTemplate.parse('boot-path','boot.js');
indexTemplate.parse('default-entry-path', path.join(this.options.appPath, 'app.js'));
fs.writeFileSync(path.join(this.getHomePath(), 'index.html'), indexTemplate.getStubContent());
return this;
}
/**
* @method createJSONForNewProject
* @param {Stub} jsonTemplate
*/
createJSONForNewProject (jsonTemplate) {
jsonTemplate.parse('description', "");
jsonTemplate.parse('appPath', this.options.appPath);
jsonTemplate.parse('uiPath', this.options.uiPath);
jsonTemplate.parse('statePath', this.options.statePath);
jsonTemplate.parse('storagePath', this.options.storagePath);
jsonTemplate.parse('tjs-version', "");
jsonTemplate.parse('tjs-path', "");
}
/**
* @method createJSONForExistingProject
* @param {Stub} jsonTemplate
*/
createJSONForExistingProject (jsonTemplate) {
jsonTemplate.parse('description', "");
jsonTemplate.parse('appPath', "");
jsonTemplate.parse('uiPath', "");
jsonTemplate.parse('statePath', "");
jsonTemplate.parse('storagePath', "");
jsonTemplate.parse('tjs-version', "");
jsonTemplate.parse('tjs-path', "");
}
/**
* @method createDirectoryStructure
*/
createDirectoryStructure() {
this.createDirectoryEvenIfExists(this.getHomePath());
let dirs = require("../../resources/stubs/app/directories.json");
dirs.forEach((directory) => {
if('app' === directory || 'ui' === directory || 'state' === directory || 'storage' === directory) {
if (this.options[directory + 'Path']) {
this.createDirectoryEvenIfExists(path.join(this.getHomePath(), this.options[directory + 'Path']));
} else {
this.createDirectoryEvenIfExists(path.join(this.getHomePath(), directory));
}
} else {
this.createDirectoryEvenIfExists(path.join(this.getHomePath(), directory));
}
});
//State folder sub-dirs
if (this.options['statePath']) {
mkdirp.sync(path.join(this.getHomePath(), this.options['statePath'], 'contracts'));
mkdirp.sync(path.join(this.getHomePath(), this.options['statePath'], 'definitions'));
} else {
mkdirp.sync(path.join(this.getHomePath(), 'state/contracts'));
mkdirp.sync(path.join(this.getHomePath(), 'state/definitions'));
}
}
/**
* @method help
* @returns {Map}
*/
help () {
const help = new Map();
help.set("create [name] [--path, --appPath, --uiPath, --statePath, --storagePath, --tjsVersion, --withBoilerplate]", "Create a new application");
help.set("init [name] [--path, --tjsVersion, --appPath, --uiPath]", "Init an app on current location");
help.set("watch [--port, --host]", "App server watcher");
help.set("build [--path, --version, --compress]", "Build app for production");
return help;
}
}
module.exports = {
init: function (lib) {
lib.cli.getRepository().addCommand(new App(lib));
},
run: function (lib) {
}
};