UNPKG

12.3 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, '__esModule', {
4 value: true
5});
6
7const _rollupPluginBabelHelpers = require('./_virtual/_rollupPluginBabelHelpers.js');
8
9const module$1 = require('module');
10
11const fs = require('fs-extra');
12
13const common = require('@boost/common');
14
15const debug = require('@boost/debug');
16
17const event = require('@boost/event');
18
19const internal = require('@boost/internal');
20
21const pipeline = require('@boost/pipeline');
22
23const plugin = require('@boost/plugin');
24
25const translate = require('@boost/translate');
26
27const Config = require('./Config.js');
28
29const constants = require('./constants.js');
30
31const ConfigContext = require('./contexts/ConfigContext.js');
32
33const DriverContext = require('./contexts/DriverContext.js');
34
35const ScaffoldContext = require('./contexts/ScaffoldContext.js');
36
37const ScriptContext = require('./contexts/ScriptContext.js');
38
39const Driver = require('./Driver.js');
40
41const CleanupConfigsRoutine = require('./routines/CleanupConfigsRoutine.js');
42
43const ResolveConfigsRoutine = require('./routines/ResolveConfigsRoutine.js');
44
45const RunDriverRoutine = require('./routines/RunDriverRoutine.js');
46
47const RunScriptRoutine = require('./routines/RunScriptRoutine.js');
48
49const ScaffoldRoutine = require('./routines/ScaffoldRoutine.js');
50
51const Script = require('./Script.js');
52
53function _interopDefault(e) {
54 return e && e.__esModule ? e : {
55 'default': e
56 };
57}
58
59const fs__default = /*#__PURE__*/_interopDefault(fs);
60
61var _dec, _dec2, _dec3, _class;
62
63let Tool = (_dec = common.Memoize(), _dec2 = common.Bind(), _dec3 = common.Bind(), (_class = class Tool extends common.Contract {
64 constructor(options) {
65 super(options);
66 this.config = void 0;
67 this.context = void 0;
68 this.errStream = void 0;
69 this.outStream = void 0;
70 this.package = void 0;
71 this.argv = void 0;
72 this.configManager = void 0;
73 this.cwd = void 0;
74 this.debug = void 0;
75 this.driverRegistry = void 0;
76 this.msg = void 0;
77 this.project = void 0;
78 this.onResolveDependencies = new event.Event('resolve-dependencies');
79 this.onRunCreateConfig = new event.Event('run-create-config');
80 this.onRunDriver = new event.Event('run-driver');
81 this.onRunScaffold = new event.Event('run-scaffold');
82 this.onRunScript = new event.Event('run-script');
83 this.scriptRegistry = void 0;
84 this.argv = this.options.argv;
85 this.cwd = common.Path.create(this.options.cwd);
86 this.debug = debug.createDebugger('core');
87 this.debug('Using beemo v%s', require('../package.json').version);
88 this.msg = translate.createTranslator(['app', 'common', 'errors'], [new common.Path(__dirname, '../resources'), ...this.options.resourcePaths]);
89 this.driverRegistry = new plugin.Registry('beemo', 'driver', {
90 resolver: this.resolveForPnP,
91 validate: Driver.Driver.validate
92 });
93 this.scriptRegistry = new plugin.Registry('beemo', 'script', {
94 resolver: this.resolveForPnP,
95 validate: Script.Script.validate
96 });
97 this.project = new common.Project(this.cwd);
98 this.configManager = new Config.Config(this.options.projectName, this.resolveForPnP);
99 }
100
101 blueprint({
102 array,
103 instance,
104 string,
105 union
106 }) {
107 return {
108 argv: array(string()),
109 cwd: union([instance(common.Path).notNullable(), string().notEmpty()], process.cwd()),
110 projectName: string('beemo').camelCase().notEmpty(),
111 resourcePaths: array(string().notEmpty())
112 };
113 }
114
115 async bootstrap() {
116 // Load config
117 const _await$this$configMan = await this.configManager.loadConfigFromRoot(this.cwd),
118 config = _await$this$configMan.config;
119
120 this.config = config;
121 this.package = this.project.getPackage(); // Load drivers
122
123 await this.driverRegistry.loadMany(config.drivers, {
124 tool: this
125 }); // Load scripts
126
127 await this.scriptRegistry.loadMany(config.scripts, {
128 tool: this
129 });
130 }
131 /**
132 * If the config module has an index that exports a function,
133 * execute it with the current tool instance.
134 */
135
136
137 async bootstrapConfigModule() {
138 var _ref, _bootstrapModule$boot, _bootstrapModule, _bootstrapModule2;
139
140 this.debug('Bootstrapping configuration module');
141 const module = this.config.module;
142 let bootstrapModule = null;
143
144 try {
145 const root = this.getConfigModuleRoot();
146 const resolver = new common.PathResolver().lookupFilePath('index.ts', root).lookupFilePath('index.js', root).lookupFilePath('src/index.ts', root).lookupFilePath('lib/index.js', root);
147
148 if (module !== '@local') {
149 resolver.lookupNodeModule(module);
150 }
151
152 const _resolver$resolve = resolver.resolve(),
153 resolvedPath = _resolver$resolve.resolvedPath;
154
155 bootstrapModule = common.requireModule(resolvedPath);
156 } catch {
157 this.debug('No bootstrap file detected, aborting bootstrap');
158 return this;
159 }
160
161 const bootstrap = (_ref = (_bootstrapModule$boot = (_bootstrapModule = bootstrapModule) === null || _bootstrapModule === void 0 ? void 0 : _bootstrapModule.bootstrap) !== null && _bootstrapModule$boot !== void 0 ? _bootstrapModule$boot : (_bootstrapModule2 = bootstrapModule) === null || _bootstrapModule2 === void 0 ? void 0 : _bootstrapModule2.default) !== null && _ref !== void 0 ? _ref : bootstrapModule;
162 const isFunction = typeof bootstrap === 'function';
163 this.debug.invariant(isFunction, 'Executing bootstrap function', 'Found', 'Not found');
164
165 if (bootstrap && isFunction) {
166 await bootstrap(this);
167 }
168
169 return this;
170 }
171 /**
172 * Validate the configuration module and return an absolute path to its root folder.
173 */
174
175
176 getConfigModuleRoot() {
177 const module = this.config.module;
178 this.debug('Locating configuration module root');
179
180 if (!module) {
181 throw new Error(this.msg('errors:moduleConfigMissing'));
182 } // Allow for local development
183
184
185 if (module === '@local') {
186 this.debug('Using %s configuration module', internal.color.moduleName('@local'));
187 return new common.Path(this.options.cwd);
188 } // Reference a node module
189
190
191 let rootPath;
192
193 try {
194 rootPath = common.Path.resolve(this.resolveForPnP(`${module}/package.json`)).parent();
195 } catch {
196 throw new Error(this.msg('errors:moduleMissing', {
197 module
198 }));
199 }
200
201 this.debug('Found configuration module root at path: %s', internal.color.filePath(rootPath));
202 return rootPath;
203 }
204 /**
205 * Delete config files if a process fails.
206 */
207
208
209 cleanupOnFailure(error) {
210 const context = this.context;
211
212 if (!error || !context) {
213 return;
214 } // Must not be async!
215
216
217 if (Array.isArray(context.configPaths)) {
218 context.configPaths.forEach(config => {
219 fs__default['default'].removeSync(config.path.path());
220 });
221 }
222 }
223 /**
224 * Create a pipeline to run the create config files flow.
225 */
226
227
228 createConfigurePipeline(args, driverNames = []) {
229 const context = this.prepareContext(new ConfigContext.ConfigContext(args)); // Create for all enabled drivers
230
231 if (driverNames.length === 0) {
232 this.driverRegistry.getAll().forEach(driver => {
233 context.addDriverDependency(driver);
234 driverNames.push(driver.getName());
235 });
236 this.debug('Running with all drivers'); // Create for one or many driver
237 } else {
238 driverNames.forEach(driverName => {
239 context.addDriverDependency(this.driverRegistry.get(driverName));
240 });
241 this.debug('Running with %s driver(s)', driverNames.join(', '));
242 }
243
244 this.onRunCreateConfig.emit([context, driverNames]);
245 return new pipeline.WaterfallPipeline(context).pipe(new ResolveConfigsRoutine.ResolveConfigsRoutine('config', this.msg('app:configGenerate'), {
246 tool: this
247 }));
248 }
249 /**
250 * Execute all routines for the chosen driver.
251 */
252
253
254 createRunDriverPipeline(args, driverName, parallelArgv = []) {
255 const driver = this.driverRegistry.get(driverName);
256 const context = this.prepareContext(new DriverContext.DriverContext(args, driver, parallelArgv));
257 const version = driver.getVersion();
258 this.onRunDriver.emit([context, driver], driverName);
259 this.debug('Running with %s v%s driver', driverName, version);
260 return new pipeline.WaterfallPipeline(context, driverName).pipe(new ResolveConfigsRoutine.ResolveConfigsRoutine('config', this.msg('app:configGenerate'), {
261 tool: this
262 })).pipe(new RunDriverRoutine.RunDriverRoutine('driver', this.msg('app:driverRun', {
263 name: driver.metadata.title,
264 version
265 }), {
266 tool: this
267 })).pipe(new CleanupConfigsRoutine.CleanupConfigsRoutine('cleanup', this.msg('app:cleanup'), {
268 tool: this
269 }) // Only add cleanup routine if we need it
270 .skip(!this.config.configure.cleanup));
271 }
272 /**
273 * Run a script found within the configuration module.
274 */
275
276
277 createRunScriptPipeline(args, scriptName) {
278 if (!scriptName || !scriptName.match(constants.KEBAB_PATTERN)) {
279 throw new Error(this.msg('errors:scriptNameInvalidFormat'));
280 }
281
282 const context = this.prepareContext(new ScriptContext.ScriptContext(args, scriptName));
283 this.onRunScript.emit([context], scriptName);
284 this.debug('Running with %s script', context.scriptName);
285 return new pipeline.WaterfallPipeline(context).pipe(new RunScriptRoutine.RunScriptRoutine('script', this.msg('app:scriptRun', {
286 name: scriptName
287 }), {
288 tool: this
289 }));
290 }
291 /**
292 * Create a pipeline to run the scaffolding flow.
293 */
294
295
296 createScaffoldPipeline(args, generator, action, name = '') {
297 const context = this.prepareContext(new ScaffoldContext.ScaffoldContext(args, generator, action, name));
298 this.onRunScaffold.emit([context, generator, action, name]);
299 this.debug('Creating scaffold pipeline');
300 return new pipeline.WaterfallPipeline(context).pipe(new ScaffoldRoutine.ScaffoldRoutine('scaffold', this.msg('app:scaffoldGenerate'), {
301 tool: this
302 }));
303 }
304 /**
305 * Resolve modules on *behalf* of the configuration module and within the context
306 * of its dependencies. This functionality is necessary to satisfy Yarn PnP and
307 * resolving plugins that aren't listed as direct dependencies.
308 */
309
310
311 resolveForPnP(id) {
312 // Create a `require` on behalf of the project root
313 const rootRequire = module$1.createRequire(this.cwd.append('package.json').path()); // Attempt to resolve from the root incase dependencies have been defined there
314
315 try {
316 return rootRequire.resolve(id);
317 } catch {// Ignore
318 } // Otherwise, create a `require` on behalf of the configuration module,
319 // which is ALSO resolved from the root (assumes the config module is a dependency there)
320
321
322 const moduleRequire = module$1.createRequire(rootRequire.resolve(`${this.config.module}/package.json`));
323 return moduleRequire.resolve(id);
324 }
325 /**
326 * Prepare the context object by setting default values for specific properties.
327 */
328
329
330 prepareContext(context) {
331 context.argv = this.argv;
332 context.cwd = this.cwd;
333 context.configModuleRoot = this.getConfigModuleRoot();
334 context.workspaceRoot = this.project.root;
335 context.workspaces = this.project.getWorkspaceGlobs(); // Make the tool available for all processes
336
337 const processObject = {
338 context,
339 tool: this
340 };
341 Object.defineProperties(process, {
342 beemo: {
343 configurable: true,
344 enumerable: true,
345 value: processObject
346 },
347 [this.options.projectName]: {
348 configurable: true,
349 enumerable: true,
350 value: processObject
351 }
352 }); // Set the current class to the tool instance
353
354 this.context = context;
355 return context;
356 }
357
358}, (_rollupPluginBabelHelpers.applyDecoratedDescriptor(_class.prototype, "getConfigModuleRoot", [_dec], Object.getOwnPropertyDescriptor(_class.prototype, "getConfigModuleRoot"), _class.prototype), _rollupPluginBabelHelpers.applyDecoratedDescriptor(_class.prototype, "cleanupOnFailure", [_dec2], Object.getOwnPropertyDescriptor(_class.prototype, "cleanupOnFailure"), _class.prototype), _rollupPluginBabelHelpers.applyDecoratedDescriptor(_class.prototype, "resolveForPnP", [_dec3], Object.getOwnPropertyDescriptor(_class.prototype, "resolveForPnP"), _class.prototype)), _class));
359exports.Tool = Tool;
360//# sourceMappingURL=Tool.js.map