UNPKG

7.62 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, '__esModule', {
4 value: true
5});
6
7const execa = require('execa');
8
9const mergeWith = require('lodash/mergeWith');
10
11const common = require('@boost/common');
12
13const event = require('@boost/event');
14
15const plugin = require('@boost/plugin');
16
17const constants = require('./constants.js');
18
19const isClassInstance = require('./helpers/isClassInstance.js');
20
21function _interopDefault(e) {
22 return e && e.__esModule ? e : {
23 'default': e
24 };
25}
26
27const execa__default = /*#__PURE__*/_interopDefault(execa);
28
29const mergeWith__default = /*#__PURE__*/_interopDefault(mergeWith);
30
31class Driver extends plugin.Plugin {
32 constructor(...args) {
33 super(...args);
34 this.commands = [];
35 this.config = void 0;
36 this.metadata = void 0;
37 this.tool = void 0;
38 this.output = {
39 stderr: '',
40 stdout: ''
41 };
42 this.onLoadProviderConfig = new event.Event('load-provider-config');
43 this.onLoadConsumerConfig = new event.Event('load-consumer-config');
44 this.onMergeConfig = new event.Event('merge-config');
45 this.onCreateConfigFile = new event.Event('create-config-file');
46 this.onCopyConfigFile = new event.Event('copy-config-file');
47 this.onReferenceConfigFile = new event.Event('reference-config-file');
48 this.onTemplateConfigFile = new event.Event('template-config-file');
49 this.onDeleteConfigFile = new event.Event('delete-config-file');
50 this.onBeforeExecute = new event.ConcurrentEvent('before-execute');
51 this.onAfterExecute = new event.ConcurrentEvent('after-execute');
52 this.onFailedExecute = new event.ConcurrentEvent('failed-execute');
53 }
54
55 static validate(driver) {
56 const name = isClassInstance.isClassInstance(driver) && driver.constructor.name || 'Driver';
57
58 if (!common.isObject(driver.options)) {
59 throw new Error(`\`${name}\` requires an options object.`);
60 }
61 }
62
63 blueprint({
64 array,
65 object,
66 string,
67 bool
68 }) {
69 return {
70 args: array(string()),
71 configStrategy: string(constants.STRATEGY_NATIVE).oneOf([constants.STRATEGY_NATIVE, constants.STRATEGY_CREATE, constants.STRATEGY_REFERENCE, constants.STRATEGY_TEMPLATE, constants.STRATEGY_COPY, constants.STRATEGY_NONE]),
72 dependencies: array(string()),
73 env: object(string()),
74 expandGlobs: bool(true),
75 outputStrategy: string(constants.STRATEGY_BUFFER).oneOf([constants.STRATEGY_BUFFER, constants.STRATEGY_PIPE, constants.STRATEGY_STREAM, constants.STRATEGY_NONE]),
76 template: string()
77 };
78 }
79
80 bootstrap() {}
81
82 startup(tool) {
83 this.tool = tool;
84 this.bootstrap();
85 }
86 /**
87 * Special case for merging arrays.
88 */
89
90
91 doMerge(prevValue, nextValue) {
92 if (Array.isArray(prevValue) && Array.isArray(nextValue)) {
93 // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
94 return [...new Set([...prevValue, ...nextValue])];
95 }
96
97 return undefined;
98 }
99 /**
100 * Extract the error message when the driver fails to execute.
101 */
102
103
104 extractErrorMessage(error) {
105 return error.message.split('\n', 1)[0] || '';
106 }
107 /**
108 * Format the configuration file before it's written.
109 */
110
111
112 formatConfig(data) {
113 const content = JSON.stringify(data, null, 2);
114
115 if (this.metadata.configName.endsWith('.js')) {
116 return `module.exports = ${content};`;
117 }
118
119 return content;
120 }
121 /**
122 * Return the module name without the Beemo namespace.
123 */
124
125
126 getName() {
127 return this.name.split('-').pop();
128 }
129 /**
130 * Return a list of user defined arguments.
131 */
132
133
134 getArgs() {
135 return common.toArray(this.options.args);
136 }
137 /**
138 * Return a list of dependent drivers.
139 */
140
141
142 getDependencies() {
143 return [// Always required; configured by the driver
144 ...this.metadata.dependencies, // Custom; configured by the consumer
145 ...common.toArray(this.options.dependencies)];
146 }
147 /**
148 * Either return the tool override strategy, or the per-driver strategy.
149 */
150
151
152 getOutputStrategy() {
153 var _ref;
154
155 return (_ref = this.tool.config.execute.output || this.options.outputStrategy) !== null && _ref !== void 0 ? _ref : constants.STRATEGY_BUFFER;
156 }
157 /**
158 * Return a list of supported CLI options.
159 */
160
161
162 getSupportedOptions() {
163 return [];
164 }
165 /**
166 * Extract the current version of the installed driver via its binary.
167 */
168
169
170 getVersion() {
171 var _execa__default$defau;
172
173 const _this$metadata = this.metadata,
174 bin = _this$metadata.bin,
175 versionOption = _this$metadata.versionOption;
176 const version = (((_execa__default$defau = execa__default['default'].sync(bin, [versionOption], {
177 preferLocal: true
178 })) === null || _execa__default$defau === void 0 ? void 0 : _execa__default$defau.stdout) || '').trim();
179 const match = version.match(/(\d+)\.(\d+)\.(\d+)/u);
180 return match ? match[0] : '0.0.0';
181 }
182 /**
183 * Merge multiple configuration objects.
184 */
185
186
187 mergeConfig(prev, next) {
188 return mergeWith__default['default'](prev, next, this.doMerge);
189 }
190 /**
191 * Handle command failures according to this driver.
192 */
193
194
195 processFailure(error) {
196 const _error$stderr = error.stderr,
197 stderr = _error$stderr === void 0 ? '' : _error$stderr,
198 _error$stdout = error.stdout,
199 stdout = _error$stdout === void 0 ? '' : _error$stdout;
200 const out = (stderr || stdout).trim();
201
202 if (out) {
203 this.setOutput('stderr', out);
204 }
205 }
206 /**
207 * Handle successful commands according to this driver.
208 */
209
210
211 processSuccess(response) {
212 const _response$stderr = response.stderr,
213 stderr = _response$stderr === void 0 ? '' : _response$stderr,
214 _response$stdout = response.stdout,
215 stdout = _response$stdout === void 0 ? '' : _response$stdout;
216 this.setOutput('stderr', stderr.trim());
217 this.setOutput('stdout', stdout.trim());
218 }
219 /**
220 * Register a sub-command within the CLI.
221 */
222
223
224 registerCommand(path, config, runner) {
225 this.commands.push({
226 config,
227 path,
228 runner
229 });
230 return this;
231 }
232 /**
233 * Set metadata about the binary/executable in which this driver wraps.
234 */
235
236
237 setMetadata(metadata) {
238 const _common$predicates = common.predicates,
239 array = _common$predicates.array,
240 bool = _common$predicates.bool,
241 string = _common$predicates.string,
242 object = _common$predicates.object,
243 shape = _common$predicates.shape;
244 this.metadata = common.optimal(metadata, {
245 bin: string().match(/^[a-z]{1}[a-zA-Z0-9-]+$/u).required(),
246 commandOptions: object(shape({
247 description: string().required(),
248 type: string().oneOf(['string', 'number', 'boolean'])
249 })),
250 configName: string().required(),
251 configOption: string('--config'),
252 configStrategy: string(constants.STRATEGY_CREATE).oneOf([constants.STRATEGY_CREATE, constants.STRATEGY_REFERENCE, constants.STRATEGY_COPY]),
253 dependencies: array(string()),
254 description: string(),
255 filterOptions: bool(true),
256 helpOption: string('--help'),
257 title: string().required(),
258 useConfigOption: bool(),
259 versionOption: string('--version'),
260 watchOptions: array(string()),
261 workspaceStrategy: string(constants.STRATEGY_REFERENCE).oneOf([constants.STRATEGY_REFERENCE, constants.STRATEGY_COPY])
262 }, {
263 name: this.constructor.name
264 });
265 return this;
266 }
267 /**
268 * Store the raw output of the driver's execution.
269 */
270
271
272 setOutput(type, value) {
273 this.output[type] = value.trim();
274 return this;
275 }
276
277}
278
279exports.Driver = Driver;
280//# sourceMappingURL=Driver.js.map