generator-loopback
Version:
Yeoman generator for LoopBack
365 lines (319 loc) • 10.4 kB
JavaScript
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: generator-loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var path = require('path');
var g = require('../lib/globalize');
var yeoman = require('yeoman-generator');
var chalk = require('chalk');
var workspace = require('loopback-workspace');
var Workspace = workspace.models.Workspace;
var fs = require('fs');
var helpers = require('../lib/helpers');
var helpText = require('../lib/help');
var validateAppName = helpers.validateAppName;
var pkg = require('../package.json');
var ActionsMixin = require('../lib/actions');
var BluemixMixin = require('../bluemix/helpers');
var debug = require('debug')('loopback:generator:app');
var util = require('util');
module.exports = class AppGenerator extends ActionsMixin(yeoman) {
constructor(args, opts) {
super(args, opts);
this.argument(g.f('name'), {
desc: g.f('Name of the application to scaffold.'),
required: false,
type: String,
});
// For the options coming from Yeoman,
// overwrite the description because they do not get translated.
this._options['help'].desc = g.f('Print the command\'s options and usage');
this._options['skip-cache'].desc = g.f('Do not remember prompt answers');
this._options['skip-install'].desc = g.f('Do not install npm dependencies');
this.option('skip-next-steps', {
desc: g.f('Do not print "next steps" info'),
type: Boolean,
});
this.option('explorer', {
desc: g.f('Add {{Loopback Explorer}} to the project ({{true}} ' +
'by default)'),
type: Boolean,
});
this.option('template', {
desc: g.f('Set up the LoopBack application template'),
type: String,
});
this.option('bluemix', {
desc: g.f('Set up as a Bluemix app'),
type: Boolean,
});
if (helpers.getCommandName() === 'loopback-cli') {
this.option('version', {
desc: g.f('Display version information'),
type: Boolean,
default: false,
});
}
}
help() {
var msgs = [helpText.customHelp(this, 'loopback_app_usage.txt')];
var list = Object.keys(this.options.env.getGeneratorsMeta())
.filter(function(name) {
return name.indexOf('loopback:') !== -1;
});
if (helpers.getCommandName() === 'loopback-cli') {
list = list.map(name => name.replace(/^loopback:/, 'lb '));
msgs.push(g.f('\nAvailable commands:\n\n'));
} else {
msgs.push(g.f('\nAvailable generators:\n\n'));
}
msgs.push(list.map(it => ' ' + it).join('\n'));
return msgs.join('') + '\n';
}
injectWorkspaceCopyRecursive() {
var originalMethod = Workspace.copyRecursive;
Workspace.copyRecursive = function(src, dest, cb) {
var isDir = fs.statSync(src).isDirectory();
if (isDir) {
this.directory(src, dest);
} else {
this.copy(src, dest);
}
return cb && process.nextTick(cb);
}.bind(this);
// Restore the original method when done
this.on('end', function() {
Workspace.copyRecursive = originalMethod;
});
}
loadTemplates() {
var done = this.async();
Workspace.describeAvailableTemplates(function(err, list) {
if (err) return done(err);
this.templates = list.map(function(t) {
return {
name: g.f('%s (%s)', t.name, t.description),
value: t.name,
supportedLBVersions: t.supportedLBVersions,
};
});
if (this.options.template) {
this.defaultTemplate = this.wsTemplate = this.options.template;
} else {
// TODO(bajtos) generator-loopback should not be coupled with APIC
// See also https://github.com/strongloop/generator-loopback/issues/139
if (helpers.getCommandName() === 'apic') {
this.defaultTemplate = 'hello-world';
this.templates = this.templates.filter(function(t) {
return t.value !== 'api-server';
});
} else {
this.defaultTemplate = 'api-server';
}
}
done();
}.bind(this));
}
askForProjectName() {
if (this.arguments && this.arguments.length >= 1) {
debug('app name is provided as %s', this.arguments[0]);
this.appname = this.arguments[0];
return;
}
// https://github.com/strongloop/generator-loopback/issues/38
// yeoman-generator normalize the appname with ' '
this.appname =
path.basename(process.cwd()).replace(/[\/@\s\+%:\.]+?/g, '-');
var name = this.name || this.dir || this.appname;
var prompts = [
{
name: 'appname',
message: g.f('What\'s the name of your application?'),
default: name,
validate: validateAppName,
},
];
return this.prompt(prompts).then(function(props) {
this.appname = props.appname || this.appname;
}.bind(this));
}
configureDestinationDirForApp() {
this.configureDestinationDir();
}
fetchLoopBackVersions() {
var done = this.async();
var self = this;
Workspace.getAvailableLBVersions(function(err, versionsMap) {
if (err) return done(err);
var versionNames = Object.keys(versionsMap);
self.availableLBVersions = versionNames.map(function(version) {
return {
name: version + ' (' + versionsMap[version].description + ')',
value: version,
};
});
done();
});
}
askForLBVersion() {
var LBVersion = this.options.loopbackVersion;
if (LBVersion) {
var lbVersions = this.availableLBVersions.map(
function(v) { return v.value; }
);
if (lbVersions.indexOf(LBVersion) === -1) {
throw new Error('Invalid LoopBack version: ' +
LBVersion + '. Available versions are ' +
lbVersions.join(', ') + '.');
}
return;
}
var prompts = [{
name: 'loopbackVersion',
message: g.f('Which version of {{LoopBack}} would you like to use?'),
type: 'list',
default: '3.x',
choices: this.availableLBVersions,
}];
var self = this;
return this.prompt(prompts).then(function(answers) {
self.options.loopbackVersion = answers.loopbackVersion;
}.bind(this));
}
applyFilterOnTemplate() {
var LBVersion = this.options.loopbackVersion;
var templates = this.templates;
this.templates = templates.filter(function(t) {
return t.supportedLBVersions.indexOf(LBVersion) !== -1;
});
}
askForTemplate() {
if (this.wsTemplate) {
var templates = this.templates.map(function(t) { return t.value; });
if (templates.indexOf(this.wsTemplate) === -1) {
throw new Error('Invalid template: ' + this.wsTemplate +
'. Available templates for ' + this.options.loopbackVersion +
' are ' + templates.join(', '));
} else {
return;
}
}
var prompts = [{
name: 'wsTemplate',
message: g.f('What kind of application do you have in mind?'),
type: 'list',
default: this.defaultTemplate,
choices: this.templates,
}];
var self = this;
return this.prompt(prompts).then(function(answers) {
// Do NOT use name template as it's a method in the base class
self.wsTemplate = answers.wsTemplate;
}.bind(this));
}
initWorkspace() {
this.initWorkspaceForGenerator();
}
detectExistingProject() {
var cb = this.async();
Workspace.isValidDir(function(err) {
if (err) {
cb();
} else {
cb(new Error(
g.f('The generator must be run in an empty directory.')
));
}
});
}
project() {
var done = this.async();
Workspace.createFromTemplate(
this.wsTemplate,
this.appname,
{
'loopbackVersion': this.options.loopbackVersion,
'loopback-component-explorer': this.options.explorer !== false,
},
done
);
}
copyFiles() {
this.directory('.', '.');
}
// call `this.fs.commit` to finish moving the template files
// from memory to destination folder.
commit() {
var done = this.async();
this.fs.commit(done);
}
generateYoRc() {
if (!this.options.initBluemix) {
this.log(g.f('Generating {{.yo-rc.json}}'));
this.config.save();
}
}
installing() {
if (!this.options.initBluemix) {
this.installDeps.call(this);
}
}
bluemix() {
if (this.options.bluemix) {
this.log(g.f('\nBluemix configuration:'));
this.composeWith(require.resolve('../bluemix'), this.options);
}
}
printNextSteps() {
if (this.options.initBluemix || this.options.skipNextSteps) return;
var cmd = helpers.getCommandName();
if (!this._skipInstall) {
this.log();
this.log();
}
this.log(g.f('Next steps:'));
this.log();
if (this.dir && this.dir !== '.') {
this.log(g.f(' Change directory to your app'));
this.log(chalk.green(' $ cd ' + this.dir));
this.log();
}
if (cmd === 'apic') {
this.log(g.f(' Run {{API Designer}} to create, test, ' +
' and publish your application'));
this.log(chalk.green(' $ apic edit'));
this.log();
} else {
this.log(g.f(' Create a model in your app'));
if (cmd === 'loopback-cli')
this.log(chalk.green(' $ lb model'));
else
this.log(chalk.green(' $ ' + cmd + ' loopback:model'));
this.log();
this.log(g.f(' Run the app'));
this.log(chalk.green(' $ node .'));
this.log();
}
}
promotion() {
var cmd = helpers.getCommandName();
if (cmd !== 'loopback-cli') return;
if (this.options.skipNextSteps) {
this.log();
}
this.log(chalk.blue(g.f(
'The API Connect team at IBM happily continues to develop,\n' +
'support and maintain LoopBack, which is at the core of\n' +
'API Connect. When your APIs need robust management and\n' +
'security options, please check out %s',
'http://ibm.biz/tryAPIC'
)));
this.log();
}
};
// Export it for strong-cli to use
module.exports._package = pkg.name + ': ' + pkg.version;
module.exports._yeomanEnv = require('yeoman-environment');
module.exports.workspaceVersion =
require('loopback-workspace/package.json').version;