@loopback/cli 4.0.0-alpha.8 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.yo-rc.json +1719 -0
- package/{generators/project/templates/LICENSE → LICENSE} +2 -1
- package/README.md +44 -43
- package/bin/cli-main.js +61 -0
- package/generators/app/index.js +109 -15
- package/generators/app/templates/.dockerignore +5 -0
- package/generators/app/templates/Dockerfile +28 -0
- package/generators/app/templates/README.md.ejs +130 -0
- package/generators/app/templates/public/index.html.ejs +88 -0
- package/generators/app/templates/{test → src/__tests__}/README.md +0 -1
- package/generators/app/templates/src/__tests__/acceptance/home-page.acceptance.ts.ejs +31 -0
- package/generators/app/templates/src/__tests__/acceptance/ping.controller.acceptance.ts.ejs +21 -0
- package/generators/app/templates/src/__tests__/acceptance/test-helper.ts.ejs +32 -0
- package/generators/app/templates/src/application.ts.ejs +70 -0
- package/generators/app/templates/src/controllers/README.md +6 -0
- package/generators/app/templates/src/controllers/index.ts.ejs +1 -0
- package/generators/app/templates/src/controllers/ping.controller.ts.ejs +55 -0
- package/generators/app/templates/src/datasources/README.md +3 -0
- package/generators/app/templates/src/index.ts.ejs +39 -0
- package/generators/app/templates/src/migrate.ts.ejs +20 -0
- package/generators/app/templates/src/models/README.md +3 -0
- package/generators/app/templates/src/openapi-spec.ts.ejs +23 -0
- package/generators/app/templates/src/sequence.ts.ejs +3 -0
- package/generators/controller/index.js +240 -23
- package/generators/controller/templates/src/controllers/controller-rest-template.ts.ejs +150 -0
- package/generators/controller/templates/src/controllers/{controller-template.ts → controller-template.ts.ejs} +2 -2
- package/generators/copyright/fs.js +46 -0
- package/generators/copyright/git.js +78 -0
- package/generators/copyright/header.js +306 -0
- package/generators/copyright/index.js +230 -0
- package/generators/copyright/license.js +105 -0
- package/generators/datasource/index.js +341 -0
- package/generators/datasource/templates/datasource.ts.ejs +22 -0
- package/generators/discover/import-discovered-model.js +70 -0
- package/generators/discover/index.js +411 -0
- package/generators/example/downloader.js +16 -0
- package/generators/example/index.js +176 -0
- package/generators/extension/index.js +34 -5
- package/generators/extension/templates/README.md.ejs +32 -0
- package/generators/extension/templates/{test → src/__tests__}/acceptance/README.md +0 -0
- package/generators/extension/templates/{test → src/__tests__}/integration/README.md +0 -0
- package/generators/extension/templates/{test → src/__tests__}/unit/README.md +0 -0
- package/generators/extension/templates/src/component.ts.ejs +22 -0
- package/generators/extension/templates/src/controllers/README.md +3 -2
- package/generators/extension/templates/src/decorators/README.md +10 -4
- package/generators/extension/templates/src/index.ts.ejs +3 -0
- package/generators/extension/templates/src/keys.ts.ejs +11 -0
- package/generators/extension/templates/src/mixins/README.md +77 -21
- package/generators/extension/templates/src/providers/README.md +51 -25
- package/generators/extension/templates/src/repositories/README.md +1 -1
- package/generators/extension/templates/src/types.ts.ejs +15 -0
- package/generators/import-lb3-models/index.js +197 -0
- package/generators/import-lb3-models/lb3app-loader.js +31 -0
- package/generators/import-lb3-models/migrate-model.js +249 -0
- package/generators/import-lb3-models/model-names.js +32 -0
- package/generators/interceptor/index.js +178 -0
- package/generators/interceptor/templates/interceptor-template.ts.ejs +62 -0
- package/generators/model/index.js +536 -0
- package/generators/model/property-definition.js +85 -0
- package/generators/model/templates/model.ts.ejs +49 -0
- package/generators/observer/index.js +132 -0
- package/generators/observer/templates/observer-template.ts.ejs +40 -0
- package/generators/openapi/README.md +211 -0
- package/generators/openapi/index.js +535 -0
- package/generators/openapi/schema-helper.js +447 -0
- package/generators/openapi/spec-helper.js +484 -0
- package/generators/openapi/spec-loader.js +75 -0
- package/generators/openapi/templates/src/controllers/controller-template.ts.ejs +43 -0
- package/generators/openapi/templates/src/datasources/datasource.ts.ejs +42 -0
- package/generators/openapi/templates/src/models/model-template.ts.ejs +71 -0
- package/generators/openapi/templates/src/models/type-template.ts.ejs +13 -0
- package/generators/openapi/templates/src/services/service-proxy-template.ts.ejs +55 -0
- package/generators/openapi/utils.js +322 -0
- package/generators/project/templates/.eslintignore +4 -0
- package/generators/project/templates/.eslintrc.js.ejs +3 -0
- package/generators/project/templates/.mocharc.json +5 -0
- package/generators/project/templates/.prettierignore +0 -2
- package/generators/project/templates/.prettierrc +2 -1
- package/generators/project/templates/.vscode/launch.json +38 -0
- package/generators/project/templates/.vscode/settings.json +32 -0
- package/generators/project/templates/.vscode/tasks.json +29 -0
- package/generators/project/templates/DEVELOPING.md +36 -0
- package/generators/project/templates/_.gitignore +3 -5
- package/generators/project/templates/package.json.ejs +175 -0
- package/generators/project/templates/package.plain.json.ejs +176 -0
- package/generators/project/templates/tsconfig.json.ejs +39 -0
- package/generators/relation/base-relation.generator.js +220 -0
- package/generators/relation/belongs-to-relation.generator.js +196 -0
- package/generators/relation/has-many-relation.generator.js +200 -0
- package/generators/relation/has-many-through-relation.generator.js +331 -0
- package/generators/relation/has-one-relation.generator.js +200 -0
- package/generators/relation/index.js +795 -0
- package/generators/relation/references-many-relation.generator.js +142 -0
- package/generators/relation/templates/controller-relation-template-belongs-to.ts.ejs +38 -0
- package/generators/relation/templates/controller-relation-template-has-many-through.ts.ejs +110 -0
- package/generators/relation/templates/controller-relation-template-has-many.ts.ejs +110 -0
- package/generators/relation/templates/controller-relation-template-has-one.ts.ejs +110 -0
- package/generators/relation/utils.generator.js +260 -0
- package/generators/repository/index.js +576 -0
- package/generators/repository/templates/src/repositories/repository-crud-default-template.ts.ejs +21 -0
- package/generators/repository/templates/src/repositories/repository-kv-template.ts.ejs +19 -0
- package/generators/rest-crud/crud-rest-component.js +63 -0
- package/generators/rest-crud/index.js +423 -0
- package/generators/rest-crud/templates/src/model-endpoints/model.rest-config-template.ts.ejs +11 -0
- package/generators/service/index.js +351 -0
- package/generators/service/templates/local-service-class-template.ts.ejs +10 -0
- package/generators/service/templates/local-service-provider-template.ts.ejs +19 -0
- package/generators/service/templates/remote-service-proxy-template.ts.ejs +21 -0
- package/generators/update/index.js +55 -0
- package/intl/cs/messages.json +204 -0
- package/intl/de/messages.json +204 -0
- package/intl/en/messages.json +204 -0
- package/intl/es/messages.json +204 -0
- package/intl/fr/messages.json +204 -0
- package/intl/it/messages.json +204 -0
- package/intl/ja/messages.json +204 -0
- package/intl/ko/messages.json +204 -0
- package/intl/nl/messages.json +204 -0
- package/intl/pl/messages.json +204 -0
- package/intl/pt/messages.json +204 -0
- package/intl/ru/messages.json +204 -0
- package/intl/tr/messages.json +204 -0
- package/intl/zh-Hans/messages.json +204 -0
- package/intl/zh-Hant/messages.json +204 -0
- package/lib/artifact-generator.js +137 -39
- package/lib/ast-helper.js +214 -0
- package/lib/base-generator.js +509 -0
- package/lib/cli.js +233 -0
- package/lib/connectors.json +894 -0
- package/lib/debug.js +16 -0
- package/lib/globalize.js +12 -0
- package/lib/model-discoverer.js +118 -0
- package/lib/project-generator.js +154 -57
- package/lib/tab-completion.js +127 -0
- package/lib/update-index.js +44 -0
- package/lib/utils.js +689 -20
- package/lib/version-helper.js +299 -0
- package/package.json +183 -39
- package/CHANGELOG.md +0 -75
- package/bin/cli.js +0 -66
- package/generators/.DS_Store +0 -0
- package/generators/app/templates/index.js +0 -14
- package/generators/app/templates/src/application.ts +0 -27
- package/generators/app/templates/src/controllers/ping-controller.ts +0 -25
- package/generators/app/templates/src/index.ts +0 -25
- package/generators/app/templates/test/ping-controller.test.ts +0 -46
- package/generators/extension/templates/index.js +0 -8
- package/generators/extension/templates/src/component.ts +0 -14
- package/generators/extension/templates/src/index.ts +0 -6
- package/generators/project/templates/.npmrc +0 -1
- package/generators/project/templates/.yo-rc.json +0 -1
- package/generators/project/templates/README.md +0 -4
- package/generators/project/templates/index.d.ts +0 -6
- package/generators/project/templates/index.ts +0 -11
- package/generators/project/templates/package.json +0 -79
- package/generators/project/templates/package.plain.json +0 -82
- package/generators/project/templates/test/mocha.opts +0 -1
- package/generators/project/templates/tsconfig.json +0 -29
- package/generators/project/templates/tslint.build.json +0 -17
- package/generators/project/templates/tslint.json +0 -33
package/lib/debug.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Copyright IBM Corp. and LoopBack contributors 2018,2020. All Rights Reserved.
|
|
2
|
+
// Node module: @loopback/cli
|
|
3
|
+
// This file is licensed under the MIT License.
|
|
4
|
+
// License text available at https://opensource.org/licenses/MIT
|
|
5
|
+
|
|
6
|
+
const debug = require('debug');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Returns a debug function whose prefix is automatically scoped to
|
|
10
|
+
* "loopback:cli:{scope}". If no scope is provided, it will be scoped
|
|
11
|
+
* to "loopback:cli".
|
|
12
|
+
* @param {String=} scope The scope to use for the debug statement.
|
|
13
|
+
*/
|
|
14
|
+
module.exports = function (scope) {
|
|
15
|
+
return debug(`loopback:cli${scope ? `:${scope}` : ''}`);
|
|
16
|
+
};
|
package/lib/globalize.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// Copyright IBM Corp. and LoopBack contributors 2020. All Rights Reserved.
|
|
2
|
+
// Node module: @loopback/cli
|
|
3
|
+
// This file is licensed under the MIT License.
|
|
4
|
+
// License text available at https://opensource.org/licenses/MIT
|
|
5
|
+
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const SG = require('strong-globalize');
|
|
10
|
+
|
|
11
|
+
SG.SetRootDir(path.join(__dirname, '..'), {autonomousMsgLoading: 'all'});
|
|
12
|
+
module.exports = SG();
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
// Copyright IBM Corp. and LoopBack contributors 2019,2020. All Rights Reserved.
|
|
2
|
+
// Node module: @loopback/cli
|
|
3
|
+
// This file is licensed under the MIT License.
|
|
4
|
+
// License text available at https://opensource.org/licenses/MIT
|
|
5
|
+
|
|
6
|
+
const debug = require('./debug')('model-discoverer');
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const {stringifyObject} = require('../lib/utils');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Given a datasource and discovery options,
|
|
13
|
+
* return a list of objects {table: 'foo', schema: 'bar}
|
|
14
|
+
*/
|
|
15
|
+
async function discoverModelNames(ds, options) {
|
|
16
|
+
if (!ds.connected) {
|
|
17
|
+
await new Promise(resolve => {
|
|
18
|
+
ds.on('connected', resolve);
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
return ds.discoverModelDefinitions(options);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Returns the schema definition for a model
|
|
26
|
+
* @param ds - {Juggler.DataSource}
|
|
27
|
+
* @param modelName - {string}
|
|
28
|
+
* @param options - {object}
|
|
29
|
+
* @returns {Promise<Juggler.SchemaDefinition>}
|
|
30
|
+
*/
|
|
31
|
+
async function discoverSingleModel(ds, modelName, options) {
|
|
32
|
+
const schema = await ds.discoverSchema(modelName, options);
|
|
33
|
+
if (schema) {
|
|
34
|
+
schema.settings = schema && schema.options;
|
|
35
|
+
}
|
|
36
|
+
return schema;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Loads a DataSource from a file
|
|
41
|
+
* If the path provided is a JSON, it instantiates a juggler.DataSource with the config as the only argument
|
|
42
|
+
* Else it requires it like a compiled loopback datasource
|
|
43
|
+
* @param modulePath
|
|
44
|
+
* @returns juggler.DataSource
|
|
45
|
+
*/
|
|
46
|
+
function loadDataSource(modulePath) {
|
|
47
|
+
const ds = require(modulePath);
|
|
48
|
+
const key = Object.keys(ds)[0];
|
|
49
|
+
const val = new ds[key]();
|
|
50
|
+
return val;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Loads a compiled loopback datasource by name
|
|
55
|
+
* @param name - {string}
|
|
56
|
+
* @returns {*}
|
|
57
|
+
*/
|
|
58
|
+
function loadDataSourceByName(name) {
|
|
59
|
+
debug(`Searching for specified dataSource ${name}`);
|
|
60
|
+
const dataSourceFiles = getAllDataSourceFiles();
|
|
61
|
+
debug(`Loaded ${dataSourceFiles.length} dataSource files`);
|
|
62
|
+
|
|
63
|
+
// eslint-disable-next-line @typescript-eslint/prefer-for-of
|
|
64
|
+
for (let i = 0; i < dataSourceFiles.length; i++) {
|
|
65
|
+
const f = dataSourceFiles[i];
|
|
66
|
+
const ds = loadDataSource(path.resolve(DEFAULT_DATASOURCE_DIRECTORY, f));
|
|
67
|
+
if (ds.name === name) {
|
|
68
|
+
debug(`Found dataSource ${name}`);
|
|
69
|
+
return ds;
|
|
70
|
+
} else {
|
|
71
|
+
debug(`Did not match dataSource ${name} !== ${ds.name}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
throw new Error(
|
|
75
|
+
`Cannot find datasource "${name}" in ${DEFAULT_DATASOURCE_DIRECTORY}`,
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const DEFAULT_DATASOURCE_DIRECTORY = './dist/datasources';
|
|
80
|
+
|
|
81
|
+
const MODEL_TEMPLATE_PATH = path.resolve(
|
|
82
|
+
__dirname,
|
|
83
|
+
'../generators/model/templates/model.ts.ejs',
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
const sanitizeProperty = function (o) {
|
|
87
|
+
Object.entries(o).forEach(([k, v]) => {
|
|
88
|
+
// Delete the null properties so the template doesn't spit out `key: ;`
|
|
89
|
+
if (v === null) {
|
|
90
|
+
delete o[k];
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// If you are an object or array, stringify so you don't appear as [object [object]
|
|
94
|
+
if (typeof v === 'object' && v !== null) {
|
|
95
|
+
o[k] = stringifyObject(o[k], {
|
|
96
|
+
// don't break lines to avoid formatting problems in the model template
|
|
97
|
+
inlineCharacterLimit: Infinity,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
o.tsType = o.type;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
function getAllDataSourceFiles(dir = DEFAULT_DATASOURCE_DIRECTORY) {
|
|
106
|
+
return fs.readdirSync(dir).filter(s => s.endsWith('.datasource.js'));
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
module.exports = {
|
|
110
|
+
getAllDataSourceFiles,
|
|
111
|
+
sanitizeProperty,
|
|
112
|
+
discoverModelNames,
|
|
113
|
+
discoverSingleModel,
|
|
114
|
+
loadDataSource,
|
|
115
|
+
loadDataSourceByName,
|
|
116
|
+
DEFAULT_DATASOURCE_DIRECTORY,
|
|
117
|
+
MODEL_TEMPLATE_PATH,
|
|
118
|
+
};
|
package/lib/project-generator.js
CHANGED
|
@@ -1,78 +1,130 @@
|
|
|
1
|
-
// Copyright IBM Corp. 2017. All Rights Reserved.
|
|
1
|
+
// Copyright IBM Corp. and LoopBack contributors 2017,2020. All Rights Reserved.
|
|
2
2
|
// Node module: @loopback/cli
|
|
3
3
|
// This file is licensed under the MIT License.
|
|
4
4
|
// License text available at https://opensource.org/licenses/MIT
|
|
5
5
|
|
|
6
6
|
'use strict';
|
|
7
|
-
|
|
8
|
-
const
|
|
7
|
+
|
|
8
|
+
const BaseGenerator = require('./base-generator');
|
|
9
9
|
const utils = require('./utils');
|
|
10
|
+
const chalk = require('chalk');
|
|
11
|
+
const cliVersion = require('../package.json').version;
|
|
12
|
+
const path = require('path');
|
|
13
|
+
const g = require('./globalize');
|
|
10
14
|
|
|
11
|
-
module.exports = class extends
|
|
15
|
+
module.exports = class ProjectGenerator extends BaseGenerator {
|
|
12
16
|
// Note: arguments and options should be defined in the constructor.
|
|
13
17
|
constructor(args, opts) {
|
|
14
18
|
super(args, opts);
|
|
15
|
-
|
|
19
|
+
// The default list of build options available for a project
|
|
20
|
+
// This list gets shown to users to let them select the appropriate
|
|
21
|
+
// build settings for their project.
|
|
22
|
+
this.buildOptions = [
|
|
23
|
+
{
|
|
24
|
+
name: 'eslint',
|
|
25
|
+
description: g.f('add a linter with pre-configured lint rules'),
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
name: 'prettier',
|
|
29
|
+
description: g.f('install prettier to format code conforming to rules'),
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
name: 'mocha',
|
|
33
|
+
description: g.f('install mocha to run tests'),
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: 'loopbackBuild',
|
|
37
|
+
description: g.f('use @loopback/build helpers (e.g. lb-eslint)'),
|
|
38
|
+
},
|
|
39
|
+
{name: 'vscode', description: g.f('add VSCode config files')},
|
|
40
|
+
];
|
|
16
41
|
}
|
|
17
42
|
|
|
18
43
|
_setupGenerator() {
|
|
19
44
|
this.argument('name', {
|
|
20
45
|
type: String,
|
|
21
46
|
required: false,
|
|
22
|
-
description: 'Project name for the '
|
|
47
|
+
description: g.f('Project name for the %s', this.projectType),
|
|
23
48
|
});
|
|
24
49
|
|
|
25
50
|
this.option('description', {
|
|
26
51
|
type: String,
|
|
27
|
-
description: 'Description for the '
|
|
52
|
+
description: g.f('Description for the %s', this.projectType),
|
|
28
53
|
});
|
|
29
54
|
|
|
30
55
|
this.option('outdir', {
|
|
31
56
|
type: String,
|
|
32
|
-
description: 'Project root directory for the '
|
|
57
|
+
description: g.f('Project root directory for the %s', this.projectType),
|
|
33
58
|
});
|
|
34
59
|
|
|
35
|
-
this.option('
|
|
60
|
+
this.option('eslint', {
|
|
36
61
|
type: Boolean,
|
|
37
|
-
description: 'Enable
|
|
62
|
+
description: g.f('Enable eslint'),
|
|
38
63
|
});
|
|
39
64
|
|
|
40
65
|
this.option('prettier', {
|
|
41
66
|
type: Boolean,
|
|
42
|
-
description: 'Enable prettier',
|
|
67
|
+
description: g.f('Enable prettier'),
|
|
43
68
|
});
|
|
44
69
|
|
|
45
70
|
this.option('mocha', {
|
|
46
71
|
type: Boolean,
|
|
47
|
-
description: 'Enable mocha',
|
|
72
|
+
description: g.f('Enable mocha'),
|
|
48
73
|
});
|
|
49
74
|
|
|
50
75
|
this.option('loopbackBuild', {
|
|
51
76
|
type: Boolean,
|
|
52
|
-
description: 'Use @loopback/build',
|
|
77
|
+
description: g.f('Use @loopback/build'),
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
this.option('vscode', {
|
|
81
|
+
type: Boolean,
|
|
82
|
+
description: g.f('Use preconfigured VSCode settings'),
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
this.option('private', {
|
|
86
|
+
type: Boolean,
|
|
87
|
+
description: g.f('Mark the project private (excluded from npm publish)'),
|
|
53
88
|
});
|
|
89
|
+
|
|
90
|
+
this._setupRenameTransformer();
|
|
91
|
+
super._setupGenerator();
|
|
54
92
|
}
|
|
55
93
|
|
|
56
94
|
/**
|
|
57
|
-
*
|
|
95
|
+
* Registers a Transform Stream with Yeoman. Removes `.ejs` extension
|
|
96
|
+
* from files that have it during project generation.
|
|
58
97
|
*/
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
return text.replace(/^yo loopback4:/g, 'lb4 ');
|
|
98
|
+
_setupRenameTransformer() {
|
|
99
|
+
this.registerTransformStream(utils.renameEJS());
|
|
62
100
|
}
|
|
63
101
|
|
|
64
|
-
setOptions() {
|
|
65
|
-
|
|
66
|
-
|
|
102
|
+
async setOptions() {
|
|
103
|
+
await super.setOptions();
|
|
104
|
+
if (this.shouldExit()) return false;
|
|
105
|
+
if (this.options.name) {
|
|
106
|
+
const msg = utils.validate(this.options.name);
|
|
107
|
+
if (typeof msg === 'string') {
|
|
108
|
+
this.exit(msg);
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
this.projectInfo = {
|
|
114
|
+
projectType: this.projectType,
|
|
115
|
+
dependencies: utils.getDependencies(),
|
|
116
|
+
};
|
|
117
|
+
this.projectOptions = [
|
|
67
118
|
'name',
|
|
68
119
|
'description',
|
|
69
120
|
'outdir',
|
|
70
|
-
'
|
|
71
|
-
'
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
'
|
|
75
|
-
|
|
121
|
+
'private',
|
|
122
|
+
'apiconnect',
|
|
123
|
+
].concat(this.buildOptions);
|
|
124
|
+
this.projectOptions.forEach(n => {
|
|
125
|
+
if (typeof n === 'object') {
|
|
126
|
+
n = n.name;
|
|
127
|
+
}
|
|
76
128
|
if (this.options[n]) {
|
|
77
129
|
this.projectInfo[n] = this.options[n];
|
|
78
130
|
}
|
|
@@ -80,18 +132,21 @@ module.exports = class extends Generator {
|
|
|
80
132
|
}
|
|
81
133
|
|
|
82
134
|
promptProjectName() {
|
|
135
|
+
if (this.shouldExit()) return false;
|
|
83
136
|
const prompts = [
|
|
84
137
|
{
|
|
85
138
|
type: 'input',
|
|
86
139
|
name: 'name',
|
|
87
|
-
message: 'Project name:',
|
|
140
|
+
message: g.f('Project name:'),
|
|
88
141
|
when: this.projectInfo.name == null,
|
|
89
|
-
default:
|
|
142
|
+
default:
|
|
143
|
+
this.options.name || utils.toFileName(path.basename(process.cwd())),
|
|
144
|
+
validate: utils.validate,
|
|
90
145
|
},
|
|
91
146
|
{
|
|
92
147
|
type: 'input',
|
|
93
148
|
name: 'description',
|
|
94
|
-
message: 'Project description:',
|
|
149
|
+
message: g.f('Project description:'),
|
|
95
150
|
when: this.projectInfo.description == null,
|
|
96
151
|
default: this.options.name || this.appname,
|
|
97
152
|
},
|
|
@@ -103,16 +158,18 @@ module.exports = class extends Generator {
|
|
|
103
158
|
}
|
|
104
159
|
|
|
105
160
|
promptProjectDir() {
|
|
161
|
+
if (this.shouldExit()) return false;
|
|
106
162
|
const prompts = [
|
|
107
163
|
{
|
|
108
164
|
type: 'input',
|
|
109
165
|
name: 'outdir',
|
|
110
|
-
message: 'Project root directory:',
|
|
166
|
+
message: g.f('Project root directory:'),
|
|
111
167
|
when:
|
|
112
168
|
this.projectInfo.outdir == null ||
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
169
|
+
// prompts if option was set to a directory that already exists
|
|
170
|
+
utils.validateNotExisting(this.projectInfo.outdir) !== true,
|
|
171
|
+
validate: utils.validateNotExisting,
|
|
172
|
+
default: this.projectInfo.name && this.projectInfo.name.toLowerCase(),
|
|
116
173
|
},
|
|
117
174
|
];
|
|
118
175
|
|
|
@@ -122,50 +179,86 @@ module.exports = class extends Generator {
|
|
|
122
179
|
}
|
|
123
180
|
|
|
124
181
|
promptOptions() {
|
|
182
|
+
if (this.shouldExit()) return false;
|
|
125
183
|
const choices = [];
|
|
126
|
-
|
|
127
|
-
if (
|
|
184
|
+
this.buildOptions.forEach(f => {
|
|
185
|
+
if (this.options[f.name] == null) {
|
|
186
|
+
const name = g.f('Enable %s', f.name);
|
|
128
187
|
choices.push({
|
|
129
|
-
name:
|
|
130
|
-
key: f,
|
|
188
|
+
name: `${name}: ${chalk.gray(f.description)}`,
|
|
189
|
+
key: f.name,
|
|
190
|
+
short: `Enable ${f.name}`,
|
|
131
191
|
checked: true,
|
|
132
192
|
});
|
|
193
|
+
} else {
|
|
194
|
+
this.projectInfo[f.name] = this.options[f.name];
|
|
133
195
|
}
|
|
134
196
|
});
|
|
135
197
|
const prompts = [
|
|
136
198
|
{
|
|
137
199
|
name: 'settings',
|
|
138
|
-
message: 'Select
|
|
200
|
+
message: g.f('Select features to enable in the project'),
|
|
139
201
|
type: 'checkbox',
|
|
140
202
|
choices: choices,
|
|
203
|
+
default: choices.map(c => c.short),
|
|
141
204
|
// Skip if all features are enabled by cli options
|
|
142
205
|
when: choices.length > 0,
|
|
143
206
|
},
|
|
144
207
|
];
|
|
145
|
-
return this.prompt(prompts).then(
|
|
146
|
-
const settings = props.settings || choices.map(c => c.name);
|
|
208
|
+
return this.prompt(prompts).then(({settings}) => {
|
|
147
209
|
const features = choices.map(c => {
|
|
148
210
|
return {
|
|
149
211
|
key: c.key,
|
|
150
|
-
value:
|
|
212
|
+
value:
|
|
213
|
+
settings.indexOf(c.name) !== -1 || settings.indexOf(c.short) !== -1,
|
|
151
214
|
};
|
|
152
215
|
});
|
|
153
216
|
features.forEach(f => (this.projectInfo[f.key] = f.value));
|
|
154
217
|
});
|
|
155
218
|
}
|
|
156
219
|
|
|
220
|
+
promptYarnInstall() {
|
|
221
|
+
if (this.shouldExit()) return false;
|
|
222
|
+
const prompts = [
|
|
223
|
+
{
|
|
224
|
+
type: 'confirm',
|
|
225
|
+
name: 'yarn',
|
|
226
|
+
message: g.f('Yarn is available. Do you prefer to use it by default?'),
|
|
227
|
+
when: !this.options.packageManager && utils.isYarnAvailable(),
|
|
228
|
+
default: false,
|
|
229
|
+
},
|
|
230
|
+
];
|
|
231
|
+
|
|
232
|
+
return this.prompt(prompts).then(props => {
|
|
233
|
+
if (props.yarn) {
|
|
234
|
+
this.options.packageManager = 'yarn';
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
|
|
157
239
|
scaffold() {
|
|
240
|
+
if (this.shouldExit()) return false;
|
|
241
|
+
|
|
158
242
|
this.destinationRoot(this.projectInfo.outdir);
|
|
159
243
|
|
|
244
|
+
// Store information for cli operation in .yo.rc.json
|
|
245
|
+
this.config.set('packageManager', this.options.packageManager || 'npm');
|
|
246
|
+
this.config.set('version', cliVersion);
|
|
247
|
+
|
|
160
248
|
// First copy common files from ../../project/templates
|
|
161
|
-
this.
|
|
249
|
+
this.copyTemplatedFiles(
|
|
162
250
|
this.templatePath('../../project/templates/**/*'),
|
|
163
251
|
this.destinationPath(''),
|
|
164
252
|
{
|
|
165
253
|
project: this.projectInfo,
|
|
254
|
+
packageManager: this.config.get('packageManager'),
|
|
255
|
+
author: this.user.git.email()
|
|
256
|
+
? {
|
|
257
|
+
name: this.user.git.name(),
|
|
258
|
+
email: this.user.git.email(),
|
|
259
|
+
}
|
|
260
|
+
: null,
|
|
166
261
|
},
|
|
167
|
-
{},
|
|
168
|
-
{globOptions: {dot: true}}
|
|
169
262
|
);
|
|
170
263
|
|
|
171
264
|
// Rename `_.gitignore` back to `.gitignore`.
|
|
@@ -173,22 +266,22 @@ module.exports = class extends Generator {
|
|
|
173
266
|
// if it's there in the templates.
|
|
174
267
|
this.fs.move(
|
|
175
268
|
this.destinationPath('_.gitignore'),
|
|
176
|
-
this.destinationPath('.gitignore')
|
|
269
|
+
this.destinationPath('.gitignore'),
|
|
177
270
|
);
|
|
178
271
|
|
|
179
272
|
// Copy project type specific files from ./templates
|
|
180
|
-
this.
|
|
273
|
+
this.copyTemplatedFiles(
|
|
181
274
|
this.templatePath('**/*'),
|
|
182
275
|
this.destinationPath(''),
|
|
183
276
|
{
|
|
184
277
|
project: this.projectInfo,
|
|
278
|
+
packageManager: this.config.get('packageManager'),
|
|
185
279
|
},
|
|
186
|
-
{},
|
|
187
|
-
{globOptions: {dot: true}}
|
|
188
280
|
);
|
|
189
281
|
|
|
190
|
-
if (!this.projectInfo.
|
|
191
|
-
this.fs.delete(this.destinationPath('
|
|
282
|
+
if (!this.projectInfo.eslint) {
|
|
283
|
+
this.fs.delete(this.destinationPath('.eslintrc.*.ejs'));
|
|
284
|
+
this.fs.delete(this.destinationPath('.eslintignore'));
|
|
192
285
|
}
|
|
193
286
|
|
|
194
287
|
if (!this.projectInfo.prettier) {
|
|
@@ -197,19 +290,23 @@ module.exports = class extends Generator {
|
|
|
197
290
|
|
|
198
291
|
if (!this.projectInfo.loopbackBuild) {
|
|
199
292
|
this.fs.move(
|
|
200
|
-
this.destinationPath('package.plain.json'),
|
|
201
|
-
this.destinationPath('package.json')
|
|
293
|
+
this.destinationPath('package.plain.json.ejs'),
|
|
294
|
+
this.destinationPath('package.json.ejs'),
|
|
202
295
|
);
|
|
203
296
|
} else {
|
|
204
|
-
this.fs.delete(this.destinationPath('package.plain.json'));
|
|
297
|
+
this.fs.delete(this.destinationPath('package.plain.json.ejs'));
|
|
205
298
|
}
|
|
206
299
|
|
|
207
300
|
if (!this.projectInfo.mocha) {
|
|
208
|
-
this.fs.delete(this.destinationPath('
|
|
301
|
+
this.fs.delete(this.destinationPath('.mocharc.json'));
|
|
209
302
|
}
|
|
210
|
-
}
|
|
211
303
|
|
|
212
|
-
|
|
213
|
-
|
|
304
|
+
if (!this.projectInfo.vscode) {
|
|
305
|
+
this.fs.delete(this.destinationPath('.vscode'));
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if (this.options.packageManager === 'yarn') {
|
|
309
|
+
this.fs.delete(this.destinationPath('.npmrc'));
|
|
310
|
+
}
|
|
214
311
|
}
|
|
215
312
|
};
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
// Copyright IBM Corp. and LoopBack contributors 2020. All Rights Reserved.
|
|
2
|
+
// Node module: @loopback/cli
|
|
3
|
+
// This file is licensed under the MIT License.
|
|
4
|
+
// License text available at https://opensource.org/licenses/MIT
|
|
5
|
+
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
const debug = require('./debug')();
|
|
9
|
+
const tabtab = require('tabtab');
|
|
10
|
+
|
|
11
|
+
const tabCompletionCommands = [
|
|
12
|
+
'install-completion',
|
|
13
|
+
'uninstall-completion',
|
|
14
|
+
'completion',
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Get all available commands or options depends on entered input
|
|
19
|
+
* @param optionsAndArgs - object of available options and arguments
|
|
20
|
+
* - name - generator name
|
|
21
|
+
* - options - list of option objects
|
|
22
|
+
* - arguments - list of argument objects
|
|
23
|
+
* @param partial - completion env.partial
|
|
24
|
+
*/
|
|
25
|
+
function generateCompletions(optionsAndArgs, partial) {
|
|
26
|
+
// Remove the `base`
|
|
27
|
+
delete optionsAndArgs.base;
|
|
28
|
+
const commands = Object.keys(optionsAndArgs);
|
|
29
|
+
const enteredCommand = commands.find(command => partial.includes(command));
|
|
30
|
+
|
|
31
|
+
if (!enteredCommand) {
|
|
32
|
+
return commands;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const options = optionsAndArgs[enteredCommand].options;
|
|
36
|
+
const optionNames = Object.keys(options).map(opt => `--${opt}`);
|
|
37
|
+
|
|
38
|
+
const enteredOptions = optionNames.filter(opt => partial.includes(opt));
|
|
39
|
+
|
|
40
|
+
if (!enteredOptions.length) {
|
|
41
|
+
return optionNames;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return optionNames.filter(opt => !enteredOptions.includes(opt));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Process bash-completion and take care about logging available commands
|
|
49
|
+
* and options
|
|
50
|
+
* @param optionsAndArgs - object of available options and arguments
|
|
51
|
+
* - name - generator name
|
|
52
|
+
* - options - list of option objects
|
|
53
|
+
* - arguments - list of argument objects
|
|
54
|
+
* @param env - completion environment object
|
|
55
|
+
* - complete A Boolean indicating whether we act in "plumbing mode" or not
|
|
56
|
+
* - words The Number of words in the completed line
|
|
57
|
+
* - point A Number indicating cursor position
|
|
58
|
+
* - line The String input line
|
|
59
|
+
* - partial The String part of line preceding cursor position
|
|
60
|
+
* - last The last String word of the line
|
|
61
|
+
* - lastPartial The last word String of partial
|
|
62
|
+
* - prev The String word preceding last
|
|
63
|
+
*/
|
|
64
|
+
function completion(optionsAndArgs, env) {
|
|
65
|
+
if (!env.complete) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return tabtab.log(generateCompletions(optionsAndArgs, env.partial));
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Register tabtab completion script
|
|
74
|
+
* Will be written in bashrc or zshrc or fish configs
|
|
75
|
+
*/
|
|
76
|
+
async function installTabCompletionScript() {
|
|
77
|
+
try {
|
|
78
|
+
await tabtab.install({
|
|
79
|
+
name: 'lb4',
|
|
80
|
+
completer: 'lb4',
|
|
81
|
+
});
|
|
82
|
+
} catch (error) /* istanbul ignore next */ {
|
|
83
|
+
debug('tab completion install script');
|
|
84
|
+
throw error;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Remove tabtab completion script
|
|
90
|
+
* Will be removed from bashrc or zshrc or fish configs
|
|
91
|
+
*/
|
|
92
|
+
async function uninstallTabCompletionScript() {
|
|
93
|
+
try {
|
|
94
|
+
await tabtab.uninstall({
|
|
95
|
+
name: 'lb4',
|
|
96
|
+
});
|
|
97
|
+
} catch (error) /* istanbul ignore next */ {
|
|
98
|
+
debug('tab completion uninstall script');
|
|
99
|
+
throw error;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Run corresponding tab-completion command
|
|
105
|
+
* @param optionsAndArgs - object of available options and arguments
|
|
106
|
+
* - name - generator name
|
|
107
|
+
* - options - list of option objects
|
|
108
|
+
* - arguments - list of argument objects
|
|
109
|
+
* @param originalCommand - command name
|
|
110
|
+
* @param log - Log function
|
|
111
|
+
*/
|
|
112
|
+
function runTabCompletionCommand(optionsAndArgs, originalCommand, log) {
|
|
113
|
+
if (originalCommand === 'install-completion') {
|
|
114
|
+
return installTabCompletionScript().catch(log);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (originalCommand === 'uninstall-completion') {
|
|
118
|
+
return uninstallTabCompletionScript().catch(log);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return completion(optionsAndArgs, tabtab.parseEnv(process.env));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
exports.tabCompletionCommands = tabCompletionCommands;
|
|
125
|
+
exports.runTabCompletionCommand = runTabCompletionCommand;
|
|
126
|
+
|
|
127
|
+
exports.generateCompletions = generateCompletions;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// Copyright IBM Corp. and LoopBack contributors 2018,2020. All Rights Reserved.
|
|
2
|
+
// Node module: @loopback/cli
|
|
3
|
+
// This file is licensed under the MIT License.
|
|
4
|
+
// License text available at https://opensource.org/licenses/MIT
|
|
5
|
+
|
|
6
|
+
const debug = require('./debug')('update-index');
|
|
7
|
+
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const fse = require('fs-extra');
|
|
10
|
+
const defaultFs = {
|
|
11
|
+
read: fse.readFile,
|
|
12
|
+
write: fse.writeFile,
|
|
13
|
+
append: fse.appendFile,
|
|
14
|
+
exists: fse.exists,
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
*
|
|
19
|
+
* @param {String} dir The directory in which index.ts is to be updated/created
|
|
20
|
+
* @param {*} file The new file to be exported from index.ts
|
|
21
|
+
*/
|
|
22
|
+
module.exports = async function (dir, file, fsApis) {
|
|
23
|
+
const {read, write, append, exists} = {...defaultFs, ...fsApis};
|
|
24
|
+
debug(`Updating index with ${path.join(dir, file)}`);
|
|
25
|
+
const indexFile = path.join(dir, 'index.ts');
|
|
26
|
+
if (!file.endsWith('.ts')) {
|
|
27
|
+
throw new Error(`${file} must be a TypeScript (.ts) file`);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
let index = '';
|
|
31
|
+
const indexExists = await exists(indexFile);
|
|
32
|
+
if (indexExists) {
|
|
33
|
+
index = await read(indexFile);
|
|
34
|
+
}
|
|
35
|
+
const content = `export * from './${file.slice(0, -3)}';\n`;
|
|
36
|
+
if (!index.includes(content)) {
|
|
37
|
+
if (indexExists) {
|
|
38
|
+
await append(indexFile, content);
|
|
39
|
+
} else {
|
|
40
|
+
await fse.ensureDir(dir);
|
|
41
|
+
await write(indexFile, content);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
};
|