@akemona-org/strapi-generate 3.7.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/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015-present Strapi Solutions SAS
2
+
3
+ Portions of the Strapi software are licensed as follows:
4
+
5
+ * All software that resides under an "ee/" directory (the “EE Software”), if that directory exists, is licensed under the license defined in "ee/LICENSE".
6
+
7
+ * All software outside of the above-mentioned directories or restrictions above is available under the "MIT Expat" license as set forth below.
8
+
9
+ MIT Expat License
10
+
11
+ Permission is hereby granted, free of charge, to any person obtaining a copy
12
+ of this software and associated documentation files (the "Software"), to deal
13
+ in the Software without restriction, including without limitation the rights
14
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
+ copies of the Software, and to permit persons to whom the Software is
16
+ furnished to do so, subject to the following conditions:
17
+
18
+ The above copyright notice and this permission notice shall be included in all
19
+ copies or substantial portions of the Software.
20
+
21
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,25 @@
1
+ # strapi-generate
2
+
3
+ [![npm version](https://img.shields.io/npm/v/strapi-generate.svg)](https://www.npmjs.org/package/strapi-generate)
4
+ [![npm downloads](https://img.shields.io/npm/dm/strapi-generate.svg)](https://www.npmjs.org/package/strapi-generate)
5
+ [![npm dependencies](https://david-dm.org/strapi/strapi-generate.svg)](https://david-dm.org/strapi/strapi-generate)
6
+ [![Build status](https://travis-ci.org/strapi/strapi-generate.svg?branch=master)](https://travis-ci.org/strapi/strapi-generate)
7
+ [![Slack status](https://slack.strapi.io/badge.svg)](https://slack.strapi.io)
8
+
9
+ Master of ceremonies for generators in the Strapi CLI.
10
+
11
+ Usage:
12
+
13
+ ```bash
14
+ $ strapi generate:something
15
+ ```
16
+
17
+ ## Resources
18
+
19
+ - [License](LICENSE)
20
+
21
+ ## Links
22
+
23
+ - [Strapi website](https://strapi.akemona.com/)
24
+ - [Strapi community on Slack](https://slack.strapi.io)
25
+ - [Strapi news on Twitter](https://twitter.com/strapijs)
@@ -0,0 +1,188 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Module dependencies
5
+ */
6
+
7
+ // Node.js core.
8
+ const path = require('path');
9
+ const util = require('util');
10
+
11
+ // Public node modules.
12
+ const _ = require('lodash');
13
+ const async = require('async');
14
+ const reportback = require('reportback')();
15
+
16
+ // Local dependencies.
17
+ const pathRegexp = require('./util').pathRegexp;
18
+ const generateTarget = require('./target');
19
+
20
+ /**
21
+ * Run a generator given an existing scope
22
+ *
23
+ * @param {Object} generator
24
+ * @param {Object} scope
25
+ * @param {Switchback} cb
26
+ */
27
+
28
+ /* eslint-disable prefer-template */
29
+ function generate(generator, scope, cb) {
30
+ const sb = reportback.extend(cb, {
31
+ error: cb.error,
32
+ invalid: cb.invalid,
33
+ alreadyExists: 'error',
34
+ });
35
+
36
+ // Resolve string shorthand for generator defs
37
+ // to `{ generator: 'originalDef' }`.
38
+ if (typeof generator === 'string') {
39
+ const generatorName = generator;
40
+ generator = {
41
+ generator: generatorName,
42
+ };
43
+ }
44
+
45
+ // Run the generator's `before()` method proceeding.
46
+ generator.before(
47
+ scope,
48
+ reportback.extend({
49
+ error: sb.error,
50
+ invalid: sb.invalid,
51
+ success: () => {
52
+ // Process all of the generator's targets concurrently.
53
+ async.each(
54
+ Object.keys(generator.targets),
55
+ (keyPath, asyncEachCb) => {
56
+ const asyncEachSb = reportback.extend(asyncEachCb);
57
+
58
+ // Create a new scope object for this target,
59
+ // with references to the important bits of the original
60
+ // (depth will be passed-by-value, but that's what we want).
61
+ // Then generate the target, passing along a reference to
62
+ // the base `generate` method to allow for recursive generators.
63
+ const target = generator.targets[keyPath];
64
+ if (!target) {
65
+ return asyncEachSb(
66
+ new Error(
67
+ 'Error: Invalid target: {"' + keyPath + '": ' + util.inspect(target) + '}'
68
+ )
69
+ );
70
+ }
71
+
72
+ // Input tolerance.
73
+ if (keyPath === '') {
74
+ keyPath = '.';
75
+ }
76
+
77
+ // Interpret `keyPath` using Express's parameterized route conventions,
78
+ // first parsing params, then replacing them with their proper values from scope.
79
+ const params = [];
80
+ pathRegexp(keyPath, params);
81
+ let err;
82
+ const parsedKeyPath = _.reduce(
83
+ params,
84
+ (memoKeyPath, param) => {
85
+ if (err) {
86
+ return false;
87
+ }
88
+
89
+ try {
90
+ const paramMatchExpr = ':' + param.name;
91
+ let actualParamValue = scope[param.name];
92
+ if (!actualParamValue) {
93
+ err = new Error(
94
+ 'generator error:\n' +
95
+ 'A scope variable (`' +
96
+ param.name +
97
+ '`) was referenced in target: `' +
98
+ memoKeyPath +
99
+ '`,\n' +
100
+ 'but `' +
101
+ param.name +
102
+ "` does not exist in the generator's scope."
103
+ );
104
+ return false;
105
+ }
106
+ actualParamValue = String(actualParamValue);
107
+
108
+ return memoKeyPath.replace(paramMatchExpr, actualParamValue);
109
+ } catch (e) {
110
+ err = new Error('Error: Could not parse target key ' + memoKeyPath);
111
+ err.message = e;
112
+ return false;
113
+ }
114
+ },
115
+ keyPath
116
+ );
117
+ if (!parsedKeyPath) {
118
+ return asyncEachSb(err);
119
+ }
120
+
121
+ // Create path from `rootPath` to `keyPath` to use as the `rootPath`
122
+ // for any generators or helpers in this target
123
+ // (use a copy so that child generators don't mutate the scope).
124
+ const targetScope = _.merge({}, scope, {
125
+ rootPath: path.resolve(scope.rootPath, parsedKeyPath),
126
+
127
+ // Include reference to original keypath for error reporting.
128
+ keyPath,
129
+ });
130
+
131
+ // If `target` is an array, run each item.
132
+ if (_.isArray(target)) {
133
+ async.eachSeries(
134
+ target,
135
+ (targetItem, asyncEachSeriesCb) => {
136
+ generateTarget(
137
+ {
138
+ target: targetItem,
139
+ parent: generator,
140
+ scope: _.cloneDeep(targetScope),
141
+ recursiveGenerate: generate,
142
+ },
143
+ asyncEachSeriesCb
144
+ );
145
+ },
146
+ asyncEachSb
147
+ );
148
+ return;
149
+ }
150
+
151
+ // Otherwise, just run the single target generator/helper.
152
+ generateTarget(
153
+ {
154
+ target,
155
+ parent: generator,
156
+ scope: targetScope,
157
+ recursiveGenerate: generate,
158
+ },
159
+ asyncEachSb
160
+ );
161
+ },
162
+
163
+ err => {
164
+ // Expose a `error` handler in generators.
165
+ if (err) {
166
+ const errorFn =
167
+ generator.error ||
168
+ function defaultError(err, scope, _cb) {
169
+ return _cb(err);
170
+ };
171
+ return errorFn(err, scope, sb);
172
+ }
173
+
174
+ // Expose a `after` handler in generators (on success only).
175
+ const afterFn =
176
+ generator.after ||
177
+ function defaultAfter(scope, _cb) {
178
+ return _cb();
179
+ };
180
+ return afterFn(scope, sb);
181
+ }
182
+ );
183
+ },
184
+ })
185
+ );
186
+ }
187
+
188
+ module.exports = generate;
@@ -0,0 +1,42 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Module dependencies
5
+ */
6
+
7
+ // Node.js core.
8
+ const path = require('path');
9
+
10
+ // Public node modules.
11
+ const _ = require('lodash');
12
+ const fs = require('fs-extra');
13
+ const reportback = require('reportback')();
14
+
15
+ // Local dependencies.
16
+ const fileHelper = require('../file');
17
+
18
+ /**
19
+ * Copy file from one place to another
20
+ */
21
+
22
+ module.exports = function (options, cb) {
23
+ cb = reportback.extend(cb, {
24
+ alreadyExists: 'error',
25
+ invalid: 'error'
26
+ });
27
+
28
+ // Compute the canonical path to copy from
29
+ // given its relative path from its source generator's
30
+ // `templates` directory.
31
+ const absSrcPath = path.resolve(options.templatesDirectory, options.templatePath);
32
+
33
+ fs.readFile(absSrcPath, 'utf8', (err, contents) => {
34
+ if (err) {
35
+ return cb.error(err);
36
+ }
37
+
38
+ return fileHelper(_.merge(options, {
39
+ contents
40
+ }), cb);
41
+ });
42
+ };
@@ -0,0 +1,69 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Module dependencies
5
+ */
6
+
7
+ // Node.js core.
8
+ const path = require('path');
9
+
10
+ // Public node modules.
11
+ const _ = require('lodash');
12
+ const async = require('async');
13
+ const fs = require('fs-extra');
14
+ const reportback = require('reportback')();
15
+
16
+ /**
17
+ * Generate a file using the specified string
18
+ */
19
+
20
+ /* eslint-disable prefer-template */
21
+ module.exports = function (options, cb) {
22
+
23
+ // Provide default values for switchback.
24
+ cb = reportback.extend(cb, {
25
+ alreadyExists: 'error'
26
+ });
27
+
28
+ // Provide defaults and validate required options.
29
+ _.defaults(options, {
30
+ force: false
31
+ });
32
+
33
+ const missingOpts = _.difference([
34
+ 'contents',
35
+ 'rootPath'
36
+ ], Object.keys(options));
37
+
38
+ if (missingOpts.length) {
39
+ return cb.invalid(missingOpts);
40
+ }
41
+
42
+ // In case we ended up here with a relative path,
43
+ // resolve it using the process's CWD
44
+ const rootPath = path.resolve(process.cwd(), options.rootPath);
45
+
46
+ // Only override an existing file if `options.force` is true.
47
+ fs.exists(rootPath, exists => {
48
+ if (exists && !options.force) {
49
+ return cb.alreadyExists('Something else already exists at `' + rootPath + '`.');
50
+ }
51
+
52
+ // Don't actually write the file if this is a dry run.
53
+ if (options.dry) {
54
+ return cb.success();
55
+ }
56
+
57
+ async.series([
58
+ function deleteExistingFileIfNecessary(cb) {
59
+ if (!exists) {
60
+ return cb();
61
+ }
62
+ return fs.remove(rootPath, cb);
63
+ },
64
+ function writeToDisk(cb) {
65
+ fs.outputFile(rootPath, options.contents, cb);
66
+ }
67
+ ], cb);
68
+ });
69
+ };
@@ -0,0 +1,81 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Module dependencies
5
+ */
6
+
7
+ // Node.js core.
8
+ const path = require('path');
9
+
10
+ // Public node modules.
11
+ const _ = require('lodash');
12
+ const fs = require('fs-extra');
13
+ const reportback = require('reportback')();
14
+
15
+ /**
16
+ * Generate a folder
17
+ */
18
+ /* eslint-disable prefer-template */
19
+ module.exports = function (options, cb) {
20
+
21
+ // Provide default values for cb.
22
+ cb = reportback.extend(cb, {
23
+ alreadyExists: 'error',
24
+ invalid: 'error'
25
+ });
26
+
27
+ // Provide defaults and validate required options.
28
+ _.defaults(options, {
29
+ force: false,
30
+ gitkeep: false
31
+ });
32
+
33
+ const missingOpts = _.difference([
34
+ 'rootPath'
35
+ ], Object.keys(options));
36
+
37
+ if (missingOpts.length) {
38
+ return cb.invalid(missingOpts);
39
+ }
40
+
41
+ const rootPath = path.resolve(process.cwd(), options.rootPath);
42
+
43
+ // Only override an existing folder if `options.force` is true.
44
+ fs.lstat(rootPath, err => {
45
+ const exists = !(err && err.code === 'ENOENT');
46
+ if (exists && err) {
47
+ return cb.error(err);
48
+ }
49
+
50
+ if (exists && !options.force) {
51
+ return cb.alreadyExists('Something else already exists at `' + rootPath + '`.');
52
+ }
53
+
54
+ if (exists) {
55
+ fs.remove(rootPath, err => {
56
+ if (err) {
57
+ return cb.error(err);
58
+ }
59
+ _afterwards_();
60
+ });
61
+ } else {
62
+ _afterwards_();
63
+ }
64
+
65
+ function _afterwards_() {
66
+
67
+ // Don't actually write the directory if this is a dry run.
68
+ if (options.dry) {
69
+ return cb.success();
70
+ }
71
+
72
+ // Create the directory.
73
+ fs.mkdirs(rootPath, err => {
74
+ if (err) {
75
+ return cb.error(err);
76
+ }
77
+ return cb.success();
78
+ });
79
+ }
80
+ });
81
+ };
@@ -0,0 +1,70 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Module dependencies
5
+ */
6
+
7
+ // Node.js core.
8
+ const path = require('path');
9
+
10
+ // Public node modules.
11
+ const _ = require('lodash');
12
+ const fs = require('fs-extra');
13
+ const reportback = require('reportback')();
14
+
15
+ /**
16
+ * Generate a JSON file
17
+ */
18
+
19
+ /* eslint-disable prefer-template */
20
+ module.exports = function (options, handlers) {
21
+
22
+ // Provide default values for handlers.
23
+ handlers = reportback.extend(handlers, {
24
+ alreadyExists: 'error'
25
+ });
26
+
27
+ // Provide defaults and validate required options.
28
+ _.defaults(options, {
29
+ force: false
30
+ });
31
+
32
+ const missingOpts = _.difference([
33
+ 'rootPath',
34
+ 'data'
35
+ ], Object.keys(options));
36
+
37
+ if (missingOpts.length) {
38
+ return handlers.invalid(missingOpts);
39
+ }
40
+
41
+ const rootPath = path.resolve(process.cwd(), options.rootPath);
42
+
43
+ // Only override an existing file if `options.force` is true.
44
+ fs.exists(rootPath, exists => {
45
+ if (exists && !options.force) {
46
+ return handlers.alreadyExists('Something else already exists at `' + rootPath + '`.');
47
+ }
48
+
49
+ if (exists) {
50
+ fs.remove(rootPath, err => {
51
+ if (err) {
52
+ return handlers.error(err);
53
+ }
54
+ _afterwards_();
55
+ });
56
+ } else {
57
+ _afterwards_();
58
+ }
59
+
60
+ function _afterwards_() {
61
+ fs.outputJSON(rootPath, options.data, {spaces: 2}, err => {
62
+ if (err) {
63
+ return handlers.error(err);
64
+ } else {
65
+ handlers.success();
66
+ }
67
+ });
68
+ }
69
+ });
70
+ };
@@ -0,0 +1,69 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Module dependencies
5
+ */
6
+
7
+ // Node.js core.
8
+ const path = require('path');
9
+
10
+ // Public node modules.
11
+ const _ = require('lodash');
12
+ const fs = require('fs-extra');
13
+ const reportback = require('reportback')();
14
+
15
+ // Local dependencies.
16
+ const fileHelper = require('../file');
17
+
18
+ /**
19
+ * Read a dynamic template, compile it using scope.
20
+ * Then use `file` helper to write it to its destination.
21
+ */
22
+
23
+ module.exports = function (options, cb) {
24
+ cb = reportback.extend(cb, {
25
+ noTemplate: 'error',
26
+ alreadyExists: 'error'
27
+ });
28
+
29
+ // Compute the canonical path to a template
30
+ // given its relative path from its source generator's
31
+ // `templates` directory.
32
+ if (_.isFunction(options.templatesDirectory)) {
33
+ options.templatesDirectory = options.templatesDirectory(options);
34
+ }
35
+
36
+ const absTemplatePath = path.resolve(options.templatesDirectory, options.templatePath);
37
+
38
+ fs.readFile(absTemplatePath, 'utf8', (err, contents) => {
39
+ if (err) {
40
+ err = err instanceof Error ? err : new Error(err);
41
+ err.message = `Template error: ${err.message}`;
42
+ err.path = absTemplatePath;
43
+ if (err.code === 'ENOENT') {
44
+ return cb.noTemplate(err);
45
+ } else {
46
+ return cb(err);
47
+ }
48
+ }
49
+
50
+ try {
51
+ const compiled = _.template(contents, {
52
+ interpolate: /<%=([\s\S]+?)%>/g
53
+ });
54
+ contents = compiled(options);
55
+
56
+ // With Lodash templates, HTML entities are escaped by default.
57
+ // Default assumption is we don't want that, so we'll reverse it.
58
+ if (!options.escapeHTMLEntities) {
59
+ contents = _.unescape(contents);
60
+ }
61
+ } catch (e) {
62
+ return cb(e);
63
+ }
64
+
65
+ return fileHelper(_.merge(options, {
66
+ contents
67
+ }), cb);
68
+ });
69
+ };
package/lib/index.js ADDED
@@ -0,0 +1,67 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Module dependencies
5
+ */
6
+
7
+ // Public node modules.
8
+ const reportback = require('reportback')();
9
+
10
+ // Logger.
11
+ const logger = require('@akemona-org/strapi-utils').logger;
12
+
13
+ // Local dependencies.
14
+ const generate = require('./generate');
15
+ const generateTarget = require('./target');
16
+
17
+ /* eslint-disable prefer-template */
18
+ /**
19
+ * Generate module(s)
20
+ *
21
+ * @param {Object} scope
22
+ * @param {Function} cb
23
+ *
24
+ * @return {[Type]}
25
+ */
26
+
27
+ module.exports = (scope, cb) => {
28
+ cb = cb || {};
29
+ cb = reportback.extend(cb, {
30
+ error: cb.error,
31
+ success: () => {},
32
+ notStrapiApp: () => {},
33
+ alreadyExists: () => {
34
+ return cb.error();
35
+ },
36
+ });
37
+
38
+ // Use configured module name for this `generatorType` if applicable.
39
+ const module = 'strapi-generate-' + scope.generatorType;
40
+ let generator;
41
+
42
+ function throwIfModuleNotFoundError(error, module) {
43
+ const isModuleNotFoundError =
44
+ error && error.code === 'MODULE_NOT_FOUND' && error.message.match(new RegExp(module));
45
+ if (!isModuleNotFoundError) {
46
+ logger.error('Invalid `' + scope.generatorType + '` generator.');
47
+ throw error;
48
+ } else {
49
+ return error;
50
+ }
51
+ }
52
+
53
+ // Try to require the module or throw if error.
54
+ try {
55
+ generator = require('../../' + module);
56
+ } catch (error) {
57
+ throwIfModuleNotFoundError(error, module);
58
+ }
59
+
60
+ if (!generator) {
61
+ return logger.error('No generator called `' + scope.generatorType + '` found.');
62
+ }
63
+
64
+ generate(generator, scope, cb);
65
+ };
66
+
67
+ module.exports.generateTarget = generateTarget;
package/lib/target.js ADDED
@@ -0,0 +1,318 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Module dependencies
5
+ */
6
+
7
+ /* eslint-disable prefer-template */
8
+ // Node.js core.
9
+ const path = require('path');
10
+ const util = require('util');
11
+
12
+ // Public node modules.
13
+ const _ = require('lodash');
14
+ const async = require('async');
15
+ const report = require('reportback')();
16
+
17
+ // Local dependencies.
18
+ const folderHelper = require('./helpers/folder');
19
+ const templateHelper = require('./helpers/template');
20
+ const jsonFileHelper = require('./helpers/jsonfile');
21
+ const copyHelper = require('./helpers/copy');
22
+
23
+ /**
24
+ * generateTarget()
25
+ *
26
+ * @param {Object} options
27
+ */
28
+
29
+ function generateTarget(options, cb) {
30
+ const sb = report.extend(cb);
31
+
32
+ // Options.
33
+ let target = options.target;
34
+ let scope = options.scope;
35
+ const parentGenerator = options.parent;
36
+ const recursiveGenerate = options.recursiveGenerate;
37
+
38
+ const maxResolves = 5;
39
+ let _resolves = 0;
40
+
41
+ async.until(
42
+ () => {
43
+ return isValidTarget(target) || ++_resolves > maxResolves;
44
+ },
45
+ asyncCb => {
46
+ parseTarget(target, scope, (err, resolvedTarget) => {
47
+ if (err) {
48
+ return asyncCb(err);
49
+ }
50
+ target = resolvedTarget;
51
+ return asyncCb();
52
+ });
53
+ },
54
+ err => {
55
+ if (err) {
56
+ return sb(err);
57
+ }
58
+ if (!isValidTarget(target)) {
59
+ return sb(
60
+ new Error(
61
+ 'Generator Error :: Could not resolve target `' +
62
+ scope.rootPath +
63
+ '` (probably a recursive loop)'
64
+ )
65
+ );
66
+ }
67
+
68
+ // Pass down parent Generator's template directory abs path.
69
+ scope.templatesDirectory = parentGenerator.templatesDirectory;
70
+
71
+ if (target.copy) {
72
+ scope = mergeSubtargetScope(
73
+ scope,
74
+ typeof target.copy === 'string'
75
+ ? {
76
+ templatePath: target.copy,
77
+ }
78
+ : target.copy
79
+ );
80
+ return copyHelper(scope, sb);
81
+ }
82
+
83
+ if (target.folder) {
84
+ scope = mergeSubtargetScope(scope, target.folder);
85
+ return folderHelper(scope, sb);
86
+ }
87
+
88
+ if (target.template) {
89
+ scope = mergeSubtargetScope(
90
+ scope,
91
+ typeof target.template === 'string'
92
+ ? {
93
+ templatePath: target.template,
94
+ }
95
+ : target.template
96
+ );
97
+
98
+ return templateHelper(scope, sb);
99
+ }
100
+
101
+ if (target.jsonfile) {
102
+ if (typeof target.jsonfile === 'object') {
103
+ scope = mergeSubtargetScope(scope, target.jsonfile);
104
+ } else if (typeof target.jsonfile === 'function') {
105
+ scope = _.merge(scope, {
106
+ data: target.jsonfile(scope),
107
+ });
108
+ }
109
+ return jsonFileHelper(scope, sb);
110
+ }
111
+
112
+ // If we made it here, this must be a recursive generator.
113
+ // Now that the generator definition has been resolved,
114
+ // call this method recursively on it, passing along our
115
+ // callback.
116
+ if (++scope._depth > scope.maxHops) {
117
+ return sb(
118
+ new Error(
119
+ '`maxHops` (' +
120
+ scope.maxHops +
121
+ ') exceeded! There is probably a recursive loop in one of your generators.'
122
+ )
123
+ );
124
+ }
125
+ return recursiveGenerate(target, scope, sb);
126
+ }
127
+ );
128
+ }
129
+
130
+ module.exports = generateTarget;
131
+
132
+ /**
133
+ * @param {[Type]} scope Description
134
+ * @param {[Type]} subtarget Description
135
+ * @return {[Type]} Description
136
+ */
137
+
138
+ function mergeSubtargetScope(scope, subtarget) {
139
+ return _.merge(scope, _.isObject(subtarget) ? subtarget : {});
140
+ }
141
+
142
+ /**
143
+ * Known helpers
144
+ *
145
+ * @type {Array}
146
+ */
147
+
148
+ const knownHelpers = ['folder', 'template', 'jsonfile', 'file', 'copy'];
149
+
150
+ function targetIsHelper(target) {
151
+ return _.some(target, (subTarget, key) => {
152
+ return _.includes(knownHelpers, key);
153
+ });
154
+ }
155
+
156
+ /**
157
+ * @param {String|Object} target Description
158
+ * @param {Object} scope Description
159
+ * @param {Function} cb Description
160
+ * @return {[type]} Description
161
+ */
162
+
163
+ function parseTarget(target, scope, cb) {
164
+ if (typeof target === 'string') {
165
+ target = {
166
+ generator: target,
167
+ };
168
+ }
169
+
170
+ // Interpret generator definition.
171
+ if (targetIsHelper(target)) {
172
+ return cb(null, target);
173
+ }
174
+
175
+ if (target.generator) {
176
+ // Normalize the subgenerator reference.
177
+ let subGeneratorRef;
178
+ if (typeof target.generator === 'string') {
179
+ subGeneratorRef = {
180
+ module: target.generator,
181
+ };
182
+ } else if (typeof target.generator === 'object') {
183
+ subGeneratorRef = target.generator;
184
+ }
185
+
186
+ if (!subGeneratorRef) {
187
+ return cb(
188
+ new Error(
189
+ 'Generator Error :: Invalid subgenerator referenced for target `' + scope.rootPath + '`'
190
+ )
191
+ );
192
+ }
193
+
194
+ // Now normalize the sub-generator.
195
+ let subGenerator;
196
+
197
+ // No `module` means we'll treat this subgenerator as an inline generator definition.
198
+ if (!subGeneratorRef.module) {
199
+ subGenerator = subGeneratorRef;
200
+ if (subGenerator) {
201
+ return cb(null, subGenerator);
202
+ }
203
+ }
204
+
205
+ // Otherwise, we'll attempt to load this subgenerator.
206
+ if (typeof subGeneratorRef.module === 'string') {
207
+ // Lookup the generator by name if a `module` was specified
208
+ // This allows the module for a given generator to be
209
+ // overridden.
210
+ const configuredReference = scope.modules && scope.modules[subGeneratorRef.module];
211
+
212
+ // Refers to a configured module.
213
+ // If this generator type is explicitly set to `false`,
214
+ // disable the generator.
215
+ if (configuredReference) {
216
+ return cb(null, configuredReference);
217
+ } else if (configuredReference === false) {
218
+ return cb(null);
219
+ }
220
+
221
+ // If `configuredReference` is undefined, continue on
222
+ // and try to require the module.
223
+ }
224
+
225
+ // At this point, `subGeneratorRef.module` should be a string,
226
+ // and the best guess at the generator module we're going
227
+ // to get.
228
+ const module = subGeneratorRef.module;
229
+ let requireError;
230
+
231
+ // Try requiring it directly as a path.
232
+ try {
233
+ subGenerator = require(module);
234
+ } catch (e0) {
235
+ requireError = e0;
236
+ }
237
+
238
+ // Try the scope's `rootPath`.
239
+ if (!subGenerator) {
240
+ try {
241
+ const asDependencyInRootPath = path.resolve(scope.rootPath, 'node_modules', module);
242
+ subGenerator = require(asDependencyInRootPath);
243
+ } catch (e1) {
244
+ requireError = e1;
245
+ }
246
+ }
247
+
248
+ // Try the current working directory.
249
+ if (!subGenerator) {
250
+ try {
251
+ subGenerator = require(path.resolve(process.cwd(), 'node_modules', module));
252
+ } catch (e1) {
253
+ requireError = e1;
254
+ }
255
+ }
256
+
257
+ // If we couldn't find a generator using the configured module,
258
+ // try requiring `strapi-generate-<module>` to get the core generator.
259
+ if (!subGenerator && !module.match(/^strapi-generate-/)) {
260
+ try {
261
+ if (process.mainModule.filename.indexOf('yarn') !== -1) {
262
+ subGenerator = require(path.resolve(
263
+ process.mainModule.paths[2],
264
+ 'strapi-generate-' + module
265
+ ));
266
+ } else {
267
+ subGenerator = require(path.resolve(
268
+ process.mainModule.paths[1],
269
+ 'strapi-generate-' + module
270
+ ));
271
+ }
272
+ } catch (e1) {
273
+ requireError = e1;
274
+ }
275
+ }
276
+
277
+ // If we were able to find it, send it back!
278
+ if (subGenerator) {
279
+ return cb(null, subGenerator);
280
+ }
281
+
282
+ // But if we still can't find it, give up.
283
+ return cb(
284
+ new Error(
285
+ 'Error: Failed to load `' +
286
+ subGeneratorRef.module +
287
+ '`...' +
288
+ (requireError ? ' (' + requireError + ')' : '') +
289
+ ''
290
+ )
291
+ );
292
+ }
293
+
294
+ return cb(
295
+ new Error(
296
+ 'Unrecognized generator syntax in `targets["' +
297
+ scope.keyPath +
298
+ '"]` ::\n' +
299
+ util.inspect(target)
300
+ )
301
+ );
302
+ }
303
+
304
+ /**
305
+ *
306
+ * @param {[Type]} target Description
307
+ * @return {Boolean} Description
308
+ */
309
+
310
+ function isValidTarget(target) {
311
+ let ok = typeof target === 'object';
312
+
313
+ // Is using a helper.
314
+ // Or is another generator def.
315
+ ok = ok && (targetIsHelper(target) || _.has(target, 'targets'));
316
+
317
+ return ok;
318
+ }
package/lib/util.js ADDED
@@ -0,0 +1,62 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * From Express core: (MIT License)
5
+ *
6
+ * Normalize the given path string,
7
+ * returning a regular expression.
8
+ *
9
+ * An empty array should be passed,
10
+ * which will contain the placeholder
11
+ * key names. For example "/user/:id" will
12
+ * then contain ["id"].
13
+ *
14
+ * @param {String|RegExp|Array} path
15
+ * @param {Array} keys
16
+ * @param {Boolean} sensitive
17
+ * @param {Boolean} strict
18
+ * @return {RegExp}
19
+ * @api private
20
+ */
21
+
22
+ /* eslint-disable prefer-template */
23
+ /* eslint-disable no-useless-escape */
24
+ const pathRegexp = (path, keys, sensitive, strict) => {
25
+ if (toString.call(path) === '[object RegExp]') {
26
+ return path;
27
+ }
28
+ if (Array.isArray(path)) {
29
+ path = '(' + path.join('|') + ')';
30
+ }
31
+ path = path
32
+ .concat(strict ? '' : '/?')
33
+ .replace(/\/\(/g, '(?:/')
34
+ .replace(
35
+ /(\/)?(\.)?:(\w+)(?:(\(.*?\)))?(\?)?(\*)?/g,
36
+ (_, slash, format, key, capture, optional, star) => {
37
+ keys.push({
38
+ name: key,
39
+ optional: !!optional,
40
+ });
41
+ slash = slash || '';
42
+ return (
43
+ '' +
44
+ (optional ? '' : slash) +
45
+ '(?:' +
46
+ (optional ? slash : '') +
47
+ (format || '') +
48
+ (capture || (format && '([^/.]+?)') || '([^/]+?)') +
49
+ ')' +
50
+ (optional || '') +
51
+ (star ? '(/*)?' : '')
52
+ );
53
+ }
54
+ )
55
+ .replace(/([\/.])/g, '\\$1')
56
+ .replace(/\*/g, '(.*)');
57
+ return new RegExp('^' + path + '$', sensitive ? '' : 'i');
58
+ };
59
+
60
+ module.exports = {
61
+ pathRegexp,
62
+ };
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@akemona-org/strapi-generate",
3
+ "publishConfig": {
4
+ "access": "public"
5
+ },
6
+ "version": "3.7.0",
7
+ "description": "Master of ceremonies for the Strapi generators.",
8
+ "homepage": "https://strapi.akemona.com",
9
+ "keywords": [
10
+ "generate",
11
+ "generator",
12
+ "strapi"
13
+ ],
14
+ "main": "./lib/index.js",
15
+ "directories": {
16
+ "lib": "./lib"
17
+ },
18
+ "scripts": {
19
+ "test": "echo \"no tests yet\""
20
+ },
21
+ "dependencies": {
22
+ "@akemona-org/strapi-utils": "3.7.0",
23
+ "async": "^2.6.2",
24
+ "fs-extra": "^9.1.0",
25
+ "lodash": "4.17.21",
26
+ "reportback": "^2.0.2"
27
+ },
28
+ "author": {
29
+ "name": "Akemona team",
30
+ "email": "strapi@akemona.com",
31
+ "url": "https://strapi.akemona.com"
32
+ },
33
+ "maintainers": [
34
+ {
35
+ "name": "Akemona team",
36
+ "email": "strapi@akemona.com",
37
+ "url": "https://strapi.akemona.com"
38
+ }
39
+ ],
40
+ "repository": {
41
+ "type": "git",
42
+ "url": "git://github.com/akemona/strapi.git"
43
+ },
44
+ "bugs": {
45
+ "url": "https://github.com/akemona/strapi/issues"
46
+ },
47
+ "engines": {
48
+ "node": ">=10.16.0 <=14.x.x",
49
+ "npm": ">=6.0.0"
50
+ },
51
+ "license": "SEE LICENSE IN LICENSE",
52
+ "gitHead": "129a8d6191b55810fd66448dcc47fee829df986c"
53
+ }