@loopback/cli
Version:
Yeoman generator for LoopBack 4
177 lines (157 loc) • 5.64 kB
JavaScript
// Copyright IBM Corp. and LoopBack contributors 2018,2020. All Rights Reserved.
// Node module: @loopback/cli
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
;
const BaseGenerator = require('../../lib/base-generator');
const chalk = require('chalk');
const downloadAndExtractExample = require('./downloader');
const path = require('path');
const fs = require('fs-extra');
const g = require('../../lib/globalize');
const EXAMPLES = {
todo: g.f('Tutorial example on how to build an application with LoopBack 4.'),
'todo-list': g.f(
'Continuation of the todo example using relations in LoopBack 4.',
),
'hello-world': g.f('A simple hello-world application using LoopBack 4.'),
'log-extension': g.f('An example extension project for LoopBack 4.'),
'rpc-server': g.f('A basic RPC server using a made-up protocol.'),
'soap-calculator': g.f('An example on how to integrate SOAP web services.'),
'express-composition': g.f(
'A simple Express application that uses LoopBack 4 REST API.',
),
context: g.f('Standalone examples showing how to use @loopback/context.'),
'greeter-extension': g.f(
'An example showing how to implement the extension point/extension pattern.',
),
'greeting-app': g.f(
'An example showing how to compose an application from component and ' +
'controllers, interceptors, and observers.',
),
'lb3-application': g.f(
'An example LoopBack 3 application mounted in a LoopBack 4 project.',
),
'rest-crud': g.f(
'A simplified version of the Todo example that only requires a model and ' +
'a datasource.',
),
'file-transfer': g.f(
'An example showing how to expose APIs to upload/download files.',
),
'access-control-migration': g.f(
'An access control example migrated from the LoopBack 3 repository ' +
'loopback-example-access-control.',
),
'metrics-prometheus': g.f(
'An example illustrating metrics using Prometheus.',
),
'validation-app': g.f('An example demonstrating how to add validations.'),
'multi-tenancy': g.f(
'An example application to demonstrate how to implement multi-tenancy with LoopBack 4.',
),
'passport-login': g.f(
'An example implmenting authentication in a LoopBack application using Passport modules.',
),
'todo-jwt': g.f('A modified Todo application with JWT authentication.'),
webpack: g.f('An example to bundle @loopback/core using webpack.'),
graphql: g.f('An example to demonstrate GraphQL integration.'),
socketio: g.f('A basic implementation of Socket.IO'),
};
Object.freeze(EXAMPLES);
module.exports = class extends BaseGenerator {
static getAllExamples() {
return EXAMPLES;
}
// Note: arguments and options should be defined in the constructor.
constructor(args, opts) {
super(args, opts);
}
_setupGenerator() {
this.projectType = 'example';
this.argument('example-name', {
type: String,
description: g.f('Name of the example to clone'),
required: false,
});
return super._setupGenerator();
}
setOptions() {
return super.setOptions();
}
help() {
const examplesHelp = Object.keys(EXAMPLES)
.map(name => ` ${name}: ${EXAMPLES[name]}`)
.join('\n');
return super.help() + `\nAvailable examples:\n${examplesHelp}\n`;
}
_describeExamples() {}
promptExampleName() {
if (this.shouldExit()) return;
if (this.options['example-name']) {
this.exampleName = this.options['example-name'];
return;
}
const choices = Object.keys(EXAMPLES).map(k => {
return {
name: `${k}: ${EXAMPLES[k]}`,
value: `${k}`,
short: `${k}`,
};
});
const prompts = [
{
name: 'name',
message: g.f('What example would you like to clone?'),
type: 'list',
choices,
},
];
return this.prompt(prompts).then(
answers => (this.exampleName = answers.name),
);
}
validateExampleName() {
if (this.shouldExit()) return;
if (this.exampleName in EXAMPLES) return;
this.exit(
g.f(
'Invalid example name: %s\n' +
'Run "lb4 example --help" to print the list of available example names.',
this.exampleName,
),
);
}
async downloadAndExtract() {
if (this.shouldExit()) return false;
const cwd = process.cwd();
const absOutDir = await downloadAndExtractExample(this.exampleName, cwd);
this.outDir = path.relative(cwd, absOutDir);
const tsconfig = path.join(absOutDir, 'tsconfig.json');
// Support older versions of examples that are using `tsconfig.build.json`
const tsBuildConfig = path.join(absOutDir, 'tsconfig.build.json');
const exists = await fs.pathExists(tsconfig);
if (!exists) {
return fs.rename(tsBuildConfig, tsconfig);
}
// Recent versions of examples are using project references inside monorepo,
// see https://github.com/loopbackio/loopback-next/pull/5155
// We must switch to standalone mode (no project references) when the code
// was checked out outside of our monorepo.
const tsconfigContent = await fs.readJson(tsconfig);
delete tsconfigContent.references;
tsconfigContent.compilerOptions.composite = false;
await fs.writeJson(tsconfig, tsconfigContent);
}
install() {
if (this.shouldExit()) return false;
this.destinationRoot(this.outDir);
return super.install();
}
async end() {
await super.end();
this.log();
this.log(g.f('The example was cloned to %s.', chalk.green(this.outDir)));
this.log();
}
};