UNPKG

238 kBJavaScriptView Raw
1'use strict';
2
3function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
4
5var commander = _interopDefault(require('commander'));
6var chalk = _interopDefault(require('chalk'));
7var React = require('react');
8var React__default = _interopDefault(React);
9var ink = require('ink');
10var semver = require('semver');
11var semver__default = _interopDefault(semver);
12var execa = _interopDefault(require('execa'));
13var axios = _interopDefault(require('axios'));
14var path$1 = require('path');
15var path$1__default = _interopDefault(path$1);
16var lodash = require('lodash');
17var codeFrame = require('@babel/code-frame');
18var resolve = _interopDefault(require('resolve-from'));
19var Worker = _interopDefault(require('jest-worker'));
20var PQueue = _interopDefault(require('p-queue'));
21var fs = require('fs');
22var fs__default = _interopDefault(fs);
23require('core-js/modules/es.array.iterator');
24var yaml = require('js-yaml');
25var yaml__default = _interopDefault(yaml);
26var ora = _interopDefault(require('ora'));
27var slugify = _interopDefault(require('slugify'));
28var inquirer = require('inquirer');
29var util = require('util');
30var prettierConfig$1 = _interopDefault(require('@burst/prettier-config'));
31var stylelint = _interopDefault(require('stylelint'));
32var client = require('@slack/client');
33var xml2js = _interopDefault(require('xml2js'));
34var rimrafWithCallback = _interopDefault(require('rimraf'));
35var stagedFilesWithCallback = _interopDefault(require('staged-git-files'));
36
37var fails = function (exec) {
38 try {
39 return !!exec();
40 } catch (error) {
41 return true;
42 }
43};
44
45// Thank's IE8 for his funny defineProperty
46var descriptors = !fails(function () {
47 return Object.defineProperty({}, 'a', { get: function () { return 7; } }).a != 7;
48});
49
50var hasOwnProperty = {}.hasOwnProperty;
51
52var has = function (it, key) {
53 return hasOwnProperty.call(it, key);
54};
55
56var isObject = function (it) {
57 return typeof it === 'object' ? it !== null : typeof it === 'function';
58};
59
60// https://github.com/zloirock/core-js/issues/86#issuecomment-115759028
61var global$1 = typeof window == 'object' && window && window.Math == Math ? window
62 : typeof self == 'object' && self && self.Math == Math ? self
63 // eslint-disable-next-line no-new-func
64 : Function('return this')();
65
66var document$1 = global$1.document;
67// typeof document.createElement is 'object' in old IE
68var exist = isObject(document$1) && isObject(document$1.createElement);
69
70var documentCreateElement = function (it) {
71 return exist ? document$1.createElement(it) : {};
72};
73
74// Thank's IE8 for his funny defineProperty
75var ie8DomDefine = !descriptors && !fails(function () {
76 return Object.defineProperty(documentCreateElement('div'), 'a', {
77 get: function () { return 7; }
78 }).a != 7;
79});
80
81var anObject = function (it) {
82 if (!isObject(it)) {
83 throw TypeError(String(it) + ' is not an object');
84 } return it;
85};
86
87// 7.1.1 ToPrimitive(input [, PreferredType])
88
89// instead of the ES6 spec version, we didn't implement @@toPrimitive case
90// and the second argument - flag - preferred type is a string
91var toPrimitive = function (it, S) {
92 if (!isObject(it)) return it;
93 var fn, val;
94 if (S && typeof (fn = it.toString) == 'function' && !isObject(val = fn.call(it))) return val;
95 if (typeof (fn = it.valueOf) == 'function' && !isObject(val = fn.call(it))) return val;
96 if (!S && typeof (fn = it.toString) == 'function' && !isObject(val = fn.call(it))) return val;
97 throw TypeError("Can't convert object to primitive value");
98};
99
100var nativeDefineProperty = Object.defineProperty;
101
102var f = descriptors ? nativeDefineProperty : function defineProperty(O, P, Attributes) {
103 anObject(O);
104 P = toPrimitive(P, true);
105 anObject(Attributes);
106 if (ie8DomDefine) try {
107 return nativeDefineProperty(O, P, Attributes);
108 } catch (error) { /* empty */ }
109 if ('get' in Attributes || 'set' in Attributes) throw TypeError('Accessors not supported');
110 if ('value' in Attributes) O[P] = Attributes.value;
111 return O;
112};
113
114var objectDefineProperty = {
115 f: f
116};
117
118var toString = {}.toString;
119
120var classofRaw = function (it) {
121 return toString.call(it).slice(8, -1);
122};
123
124// fallback for non-array-like ES3 and non-enumerable old V8 strings
125
126
127var split = ''.split;
128
129var indexedObject = fails(function () {
130 // throws an error in rhino, see https://github.com/mozilla/rhino/issues/346
131 // eslint-disable-next-line no-prototype-builtins
132 return !Object('z').propertyIsEnumerable(0);
133}) ? function (it) {
134 return classofRaw(it) == 'String' ? split.call(it, '') : Object(it);
135} : Object;
136
137// `RequireObjectCoercible` abstract operation
138// https://tc39.github.io/ecma262/#sec-requireobjectcoercible
139var requireObjectCoercible = function (it) {
140 if (it == undefined) throw TypeError("Can't call method on " + it);
141 return it;
142};
143
144// toObject with fallback for non-array-like ES3 strings
145
146
147
148var toIndexedObject = function (it) {
149 return indexedObject(requireObjectCoercible(it));
150};
151
152var ceil = Math.ceil;
153var floor = Math.floor;
154
155// `ToInteger` abstract operation
156// https://tc39.github.io/ecma262/#sec-tointeger
157var toInteger = function (argument) {
158 return isNaN(argument = +argument) ? 0 : (argument > 0 ? floor : ceil)(argument);
159};
160
161var min = Math.min;
162
163// `ToLength` abstract operation
164// https://tc39.github.io/ecma262/#sec-tolength
165var toLength = function (argument) {
166 return argument > 0 ? min(toInteger(argument), 0x1FFFFFFFFFFFFF) : 0; // 2 ** 53 - 1 == 9007199254740991
167};
168
169var max = Math.max;
170var min$1 = Math.min;
171
172// Helper for a popular repeating case of the spec:
173// Let integer be ? ToInteger(index).
174// If integer < 0, let result be max((length + integer), 0); else let result be min(length, length).
175var toAbsoluteIndex = function (index, length) {
176 var integer = toInteger(index);
177 return integer < 0 ? max(integer + length, 0) : min$1(integer, length);
178};
179
180// `Array.prototype.{ indexOf, includes }` methods implementation
181// false -> Array#indexOf
182// https://tc39.github.io/ecma262/#sec-array.prototype.indexof
183// true -> Array#includes
184// https://tc39.github.io/ecma262/#sec-array.prototype.includes
185var arrayIncludes = function (IS_INCLUDES) {
186 return function ($this, el, fromIndex) {
187 var O = toIndexedObject($this);
188 var length = toLength(O.length);
189 var index = toAbsoluteIndex(fromIndex, length);
190 var value;
191 // Array#includes uses SameValueZero equality algorithm
192 // eslint-disable-next-line no-self-compare
193 if (IS_INCLUDES && el != el) while (length > index) {
194 value = O[index++];
195 // eslint-disable-next-line no-self-compare
196 if (value != value) return true;
197 // Array#indexOf ignores holes, Array#includes - not
198 } else for (;length > index; index++) if (IS_INCLUDES || index in O) {
199 if (O[index] === el) return IS_INCLUDES || index || 0;
200 } return !IS_INCLUDES && -1;
201 };
202};
203
204var hiddenKeys = {};
205
206var arrayIndexOf = arrayIncludes(false);
207
208
209var objectKeysInternal = function (object, names) {
210 var O = toIndexedObject(object);
211 var i = 0;
212 var result = [];
213 var key;
214 for (key in O) !has(hiddenKeys, key) && has(O, key) && result.push(key);
215 // Don't enum bug & hidden keys
216 while (names.length > i) if (has(O, key = names[i++])) {
217 ~arrayIndexOf(result, key) || result.push(key);
218 }
219 return result;
220};
221
222// IE8- don't enum bug keys
223var enumBugKeys = [
224 'constructor',
225 'hasOwnProperty',
226 'isPrototypeOf',
227 'propertyIsEnumerable',
228 'toLocaleString',
229 'toString',
230 'valueOf'
231];
232
233// 19.1.2.7 / 15.2.3.4 Object.getOwnPropertyNames(O)
234
235var hiddenKeys$1 = enumBugKeys.concat('length', 'prototype');
236
237var f$1 = Object.getOwnPropertyNames || function getOwnPropertyNames(O) {
238 return objectKeysInternal(O, hiddenKeys$1);
239};
240
241var objectGetOwnPropertyNames = {
242 f: f$1
243};
244
245var f$2 = Object.getOwnPropertySymbols;
246
247var objectGetOwnPropertySymbols = {
248 f: f$2
249};
250
251var Reflect = global$1.Reflect;
252
253// all object keys, includes non-enumerable and symbols
254var ownKeys = Reflect && Reflect.ownKeys || function ownKeys(it) {
255 var keys = objectGetOwnPropertyNames.f(anObject(it));
256 var getOwnPropertySymbols = objectGetOwnPropertySymbols.f;
257 return getOwnPropertySymbols ? keys.concat(getOwnPropertySymbols(it)) : keys;
258};
259
260var nativePropertyIsEnumerable = {}.propertyIsEnumerable;
261var nativeGetOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
262
263// Nashorn ~ JDK8 bug
264var NASHORN_BUG = nativeGetOwnPropertyDescriptor && !nativePropertyIsEnumerable.call({ 1: 2 }, 1);
265
266var f$3 = NASHORN_BUG ? function propertyIsEnumerable(V) {
267 var descriptor = nativeGetOwnPropertyDescriptor(this, V);
268 return !!descriptor && descriptor.enumerable;
269} : nativePropertyIsEnumerable;
270
271var objectPropertyIsEnumerable = {
272 f: f$3
273};
274
275var createPropertyDescriptor = function (bitmap, value) {
276 return {
277 enumerable: !(bitmap & 1),
278 configurable: !(bitmap & 2),
279 writable: !(bitmap & 4),
280 value: value
281 };
282};
283
284var nativeGetOwnPropertyDescriptor$1 = Object.getOwnPropertyDescriptor;
285
286var f$4 = descriptors ? nativeGetOwnPropertyDescriptor$1 : function getOwnPropertyDescriptor(O, P) {
287 O = toIndexedObject(O);
288 P = toPrimitive(P, true);
289 if (ie8DomDefine) try {
290 return nativeGetOwnPropertyDescriptor$1(O, P);
291 } catch (error) { /* empty */ }
292 if (has(O, P)) return createPropertyDescriptor(!objectPropertyIsEnumerable.f.call(O, P), O[P]);
293};
294
295var objectGetOwnPropertyDescriptor = {
296 f: f$4
297};
298
299var copyConstructorProperties = function (target, source) {
300 var keys = ownKeys(source);
301 var defineProperty = objectDefineProperty.f;
302 var getOwnPropertyDescriptor = objectGetOwnPropertyDescriptor.f;
303 for (var i = 0; i < keys.length; i++) {
304 var key = keys[i];
305 if (!has(target, key)) defineProperty(target, key, getOwnPropertyDescriptor(source, key));
306 }
307};
308
309var hide = descriptors ? function (object, key, value) {
310 return objectDefineProperty.f(object, key, createPropertyDescriptor(1, value));
311} : function (object, key, value) {
312 object[key] = value;
313 return object;
314};
315
316var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
317
318function createCommonjsModule(fn, module) {
319 return module = { exports: {} }, fn(module, module.exports), module.exports;
320}
321
322var setGlobal = function (key, value) {
323 try {
324 hide(global$1, key, value);
325 } catch (error) {
326 global$1[key] = value;
327 } return value;
328};
329
330var isPure = false;
331
332var shared = createCommonjsModule(function (module) {
333var SHARED = '__core-js_shared__';
334var store = global$1[SHARED] || setGlobal(SHARED, {});
335
336(module.exports = function (key, value) {
337 return store[key] || (store[key] = value !== undefined ? value : {});
338})('versions', []).push({
339 version: '3.0.1',
340 mode: 'global',
341 copyright: '© 2019 Denis Pushkarev (zloirock.ru)'
342});
343});
344
345var functionToString = shared('native-function-to-string', Function.toString);
346
347var WeakMap = global$1.WeakMap;
348
349var nativeWeakMap = typeof WeakMap === 'function' && /native code/.test(functionToString.call(WeakMap));
350
351var id = 0;
352var postfix = Math.random();
353
354var uid = function (key) {
355 return 'Symbol('.concat(key === undefined ? '' : key, ')_', (++id + postfix).toString(36));
356};
357
358var shared$1 = shared('keys');
359
360
361var sharedKey = function (key) {
362 return shared$1[key] || (shared$1[key] = uid(key));
363};
364
365var WeakMap$1 = global$1.WeakMap;
366var set, get, has$1;
367
368var enforce = function (it) {
369 return has$1(it) ? get(it) : set(it, {});
370};
371
372var getterFor = function (TYPE) {
373 return function (it) {
374 var state;
375 if (!isObject(it) || (state = get(it)).type !== TYPE) {
376 throw TypeError('Incompatible receiver, ' + TYPE + ' required');
377 } return state;
378 };
379};
380
381if (nativeWeakMap) {
382 var store = new WeakMap$1();
383 var wmget = store.get;
384 var wmhas = store.has;
385 var wmset = store.set;
386 set = function (it, metadata) {
387 wmset.call(store, it, metadata);
388 return metadata;
389 };
390 get = function (it) {
391 return wmget.call(store, it) || {};
392 };
393 has$1 = function (it) {
394 return wmhas.call(store, it);
395 };
396} else {
397 var STATE = sharedKey('state');
398 hiddenKeys[STATE] = true;
399 set = function (it, metadata) {
400 hide(it, STATE, metadata);
401 return metadata;
402 };
403 get = function (it) {
404 return has(it, STATE) ? it[STATE] : {};
405 };
406 has$1 = function (it) {
407 return has(it, STATE);
408 };
409}
410
411var internalState = {
412 set: set,
413 get: get,
414 has: has$1,
415 enforce: enforce,
416 getterFor: getterFor
417};
418
419var redefine = createCommonjsModule(function (module) {
420var getInternalState = internalState.get;
421var enforceInternalState = internalState.enforce;
422var TEMPLATE = String(functionToString).split('toString');
423
424shared('inspectSource', function (it) {
425 return functionToString.call(it);
426});
427
428(module.exports = function (O, key, value, options) {
429 var unsafe = options ? !!options.unsafe : false;
430 var simple = options ? !!options.enumerable : false;
431 var noTargetGet = options ? !!options.noTargetGet : false;
432 if (typeof value == 'function') {
433 if (typeof key == 'string' && !has(value, 'name')) hide(value, 'name', key);
434 enforceInternalState(value).source = TEMPLATE.join(typeof key == 'string' ? key : '');
435 }
436 if (O === global$1) {
437 if (simple) O[key] = value;
438 else setGlobal(key, value);
439 return;
440 } else if (!unsafe) {
441 delete O[key];
442 } else if (!noTargetGet && O[key]) {
443 simple = true;
444 }
445 if (simple) O[key] = value;
446 else hide(O, key, value);
447// add fake Function#toString for correct work wrapped methods / constructors with methods like LoDash isNative
448})(Function.prototype, 'toString', function toString() {
449 return typeof this == 'function' && getInternalState(this).source || functionToString.call(this);
450});
451});
452
453var replacement = /#|\.prototype\./;
454
455var isForced = function (feature, detection) {
456 var value = data[normalize(feature)];
457 return value == POLYFILL ? true
458 : value == NATIVE ? false
459 : typeof detection == 'function' ? fails(detection)
460 : !!detection;
461};
462
463var normalize = isForced.normalize = function (string) {
464 return String(string).replace(replacement, '.').toLowerCase();
465};
466
467var data = isForced.data = {};
468var NATIVE = isForced.NATIVE = 'N';
469var POLYFILL = isForced.POLYFILL = 'P';
470
471var isForced_1 = isForced;
472
473var getOwnPropertyDescriptor = objectGetOwnPropertyDescriptor.f;
474
475
476
477
478
479
480/*
481 options.target - name of the target object
482 options.global - target is the global object
483 options.stat - export as static methods of target
484 options.proto - export as prototype methods of target
485 options.real - real prototype method for the `pure` version
486 options.forced - export even if the native feature is available
487 options.bind - bind methods to the target, required for the `pure` version
488 options.wrap - wrap constructors to preventing global pollution, required for the `pure` version
489 options.unsafe - use the simple assignment of property instead of delete + defineProperty
490 options.sham - add a flag to not completely full polyfills
491 options.enumerable - export as enumerable property
492 options.noTargetGet - prevent calling a getter on target
493*/
494var _export = function (options, source) {
495 var TARGET = options.target;
496 var GLOBAL = options.global;
497 var STATIC = options.stat;
498 var FORCED, target, key, targetProperty, sourceProperty, descriptor;
499 if (GLOBAL) {
500 target = global$1;
501 } else if (STATIC) {
502 target = global$1[TARGET] || setGlobal(TARGET, {});
503 } else {
504 target = (global$1[TARGET] || {}).prototype;
505 }
506 if (target) for (key in source) {
507 sourceProperty = source[key];
508 if (options.noTargetGet) {
509 descriptor = getOwnPropertyDescriptor(target, key);
510 targetProperty = descriptor && descriptor.value;
511 } else targetProperty = target[key];
512 FORCED = isForced_1(GLOBAL ? key : TARGET + (STATIC ? '.' : '#') + key, options.forced);
513 // contained in target
514 if (!FORCED && targetProperty !== undefined) {
515 if (typeof sourceProperty === typeof targetProperty) continue;
516 copyConstructorProperties(sourceProperty, targetProperty);
517 }
518 // add a flag to not completely full polyfills
519 if (options.sham || (targetProperty && targetProperty.sham)) {
520 hide(sourceProperty, 'sham', true);
521 }
522 // extend global
523 redefine(target, key, sourceProperty, options);
524 }
525};
526
527var defineProperty = objectDefineProperty.f;
528
529var NativeSymbol = global$1.Symbol;
530
531if (descriptors && typeof NativeSymbol == 'function' && (!('description' in NativeSymbol.prototype) ||
532 // Safari 12 bug
533 NativeSymbol().description !== undefined
534)) {
535 var EmptyStringDescriptionStore = {};
536 // wrap Symbol constructor for correct work with undefined description
537 var SymbolWrapper = function Symbol() {
538 var description = arguments.length < 1 || arguments[0] === undefined ? undefined : String(arguments[0]);
539 var result = this instanceof SymbolWrapper
540 ? new NativeSymbol(description)
541 // in Edge 13, String(Symbol(undefined)) === 'Symbol(undefined)'
542 : description === undefined ? NativeSymbol() : NativeSymbol(description);
543 if (description === '') EmptyStringDescriptionStore[result] = true;
544 return result;
545 };
546 copyConstructorProperties(SymbolWrapper, NativeSymbol);
547 var symbolPrototype = SymbolWrapper.prototype = NativeSymbol.prototype;
548 symbolPrototype.constructor = SymbolWrapper;
549
550 var symbolToString = symbolPrototype.toString;
551 var native = String(NativeSymbol('test')) == 'Symbol(test)';
552 var regexp = /^Symbol\((.*)\)[^)]+$/;
553 defineProperty(symbolPrototype, 'description', {
554 configurable: true,
555 get: function description() {
556 var symbol = isObject(this) ? this.valueOf() : this;
557 var string = symbolToString.call(symbol);
558 if (has(EmptyStringDescriptionStore, symbol)) return '';
559 var desc = native ? string.slice(7, -1) : string.replace(regexp, '$1');
560 return desc === '' ? undefined : desc;
561 }
562 });
563
564 _export({ global: true, forced: true }, { Symbol: SymbolWrapper });
565}
566
567// Chrome 38 Symbol has incorrect toString conversion
568var nativeSymbol = !fails(function () {
569 // eslint-disable-next-line no-undef
570 return !String(Symbol());
571});
572
573var store$1 = shared('wks');
574
575var Symbol$1 = global$1.Symbol;
576
577
578var wellKnownSymbol = function (name) {
579 return store$1[name] || (store$1[name] = nativeSymbol && Symbol$1[name]
580 || (nativeSymbol ? Symbol$1 : uid)('Symbol.' + name));
581};
582
583// 19.1.2.14 / 15.2.3.14 Object.keys(O)
584
585
586
587var objectKeys = Object.keys || function keys(O) {
588 return objectKeysInternal(O, enumBugKeys);
589};
590
591var objectDefineProperties = descriptors ? Object.defineProperties : function defineProperties(O, Properties) {
592 anObject(O);
593 var keys = objectKeys(Properties);
594 var length = keys.length;
595 var i = 0;
596 var key;
597 while (length > i) objectDefineProperty.f(O, key = keys[i++], Properties[key]);
598 return O;
599};
600
601var document$2 = global$1.document;
602
603var html = document$2 && document$2.documentElement;
604
605// 19.1.2.2 / 15.2.3.5 Object.create(O [, Properties])
606
607
608
609
610
611var IE_PROTO = sharedKey('IE_PROTO');
612var PROTOTYPE = 'prototype';
613var Empty = function () { /* empty */ };
614
615// Create object with fake `null` prototype: use iframe Object with cleared prototype
616var createDict = function () {
617 // Thrash, waste and sodomy: IE GC bug
618 var iframe = documentCreateElement('iframe');
619 var length = enumBugKeys.length;
620 var lt = '<';
621 var script = 'script';
622 var gt = '>';
623 var js = 'java' + script + ':';
624 var iframeDocument;
625 iframe.style.display = 'none';
626 html.appendChild(iframe);
627 iframe.src = String(js);
628 iframeDocument = iframe.contentWindow.document;
629 iframeDocument.open();
630 iframeDocument.write(lt + script + gt + 'document.F=Object' + lt + '/' + script + gt);
631 iframeDocument.close();
632 createDict = iframeDocument.F;
633 while (length--) delete createDict[PROTOTYPE][enumBugKeys[length]];
634 return createDict();
635};
636
637var objectCreate = Object.create || function create(O, Properties) {
638 var result;
639 if (O !== null) {
640 Empty[PROTOTYPE] = anObject(O);
641 result = new Empty();
642 Empty[PROTOTYPE] = null;
643 // add "__proto__" for Object.getPrototypeOf polyfill
644 result[IE_PROTO] = O;
645 } else result = createDict();
646 return Properties === undefined ? result : objectDefineProperties(result, Properties);
647};
648
649hiddenKeys[IE_PROTO] = true;
650
651var UNSCOPABLES = wellKnownSymbol('unscopables');
652
653
654var ArrayPrototype = Array.prototype;
655
656// Array.prototype[@@unscopables]
657// https://tc39.github.io/ecma262/#sec-array.prototype-@@unscopables
658if (ArrayPrototype[UNSCOPABLES] == undefined) {
659 hide(ArrayPrototype, UNSCOPABLES, objectCreate(null));
660}
661
662// add a key to Array.prototype[@@unscopables]
663var addToUnscopables = function (key) {
664 ArrayPrototype[UNSCOPABLES][key] = true;
665};
666
667var iterators = {};
668
669// `ToObject` abstract operation
670// https://tc39.github.io/ecma262/#sec-toobject
671var toObject = function (argument) {
672 return Object(requireObjectCoercible(argument));
673};
674
675var correctPrototypeGetter = !fails(function () {
676 function F() { /* empty */ }
677 F.prototype.constructor = null;
678 return Object.getPrototypeOf(new F()) !== F.prototype;
679});
680
681// 19.1.2.9 / 15.2.3.2 Object.getPrototypeOf(O)
682
683
684var IE_PROTO$1 = sharedKey('IE_PROTO');
685
686var ObjectPrototype = Object.prototype;
687
688var objectGetPrototypeOf = correctPrototypeGetter ? Object.getPrototypeOf : function (O) {
689 O = toObject(O);
690 if (has(O, IE_PROTO$1)) return O[IE_PROTO$1];
691 if (typeof O.constructor == 'function' && O instanceof O.constructor) {
692 return O.constructor.prototype;
693 } return O instanceof Object ? ObjectPrototype : null;
694};
695
696var ITERATOR = wellKnownSymbol('iterator');
697var BUGGY_SAFARI_ITERATORS = false;
698
699var returnThis = function () { return this; };
700
701// `%IteratorPrototype%` object
702// https://tc39.github.io/ecma262/#sec-%iteratorprototype%-object
703var IteratorPrototype, PrototypeOfArrayIteratorPrototype, arrayIterator;
704
705if ([].keys) {
706 arrayIterator = [].keys();
707 // Safari 8 has buggy iterators w/o `next`
708 if (!('next' in arrayIterator)) BUGGY_SAFARI_ITERATORS = true;
709 else {
710 PrototypeOfArrayIteratorPrototype = objectGetPrototypeOf(objectGetPrototypeOf(arrayIterator));
711 if (PrototypeOfArrayIteratorPrototype !== Object.prototype) IteratorPrototype = PrototypeOfArrayIteratorPrototype;
712 }
713}
714
715if (IteratorPrototype == undefined) IteratorPrototype = {};
716
717// 25.1.2.1.1 %IteratorPrototype%[@@iterator]()
718if (!has(IteratorPrototype, ITERATOR)) hide(IteratorPrototype, ITERATOR, returnThis);
719
720var iteratorsCore = {
721 IteratorPrototype: IteratorPrototype,
722 BUGGY_SAFARI_ITERATORS: BUGGY_SAFARI_ITERATORS
723};
724
725var defineProperty$1 = objectDefineProperty.f;
726
727var TO_STRING_TAG = wellKnownSymbol('toStringTag');
728
729var setToStringTag = function (it, TAG, STATIC) {
730 if (it && !has(it = STATIC ? it : it.prototype, TO_STRING_TAG)) {
731 defineProperty$1(it, TO_STRING_TAG, { configurable: true, value: TAG });
732 }
733};
734
735var IteratorPrototype$1 = iteratorsCore.IteratorPrototype;
736
737
738
739
740
741var returnThis$1 = function () { return this; };
742
743var createIteratorConstructor = function (IteratorConstructor, NAME, next) {
744 var TO_STRING_TAG = NAME + ' Iterator';
745 IteratorConstructor.prototype = objectCreate(IteratorPrototype$1, { next: createPropertyDescriptor(1, next) });
746 setToStringTag(IteratorConstructor, TO_STRING_TAG, false, true);
747 iterators[TO_STRING_TAG] = returnThis$1;
748 return IteratorConstructor;
749};
750
751var validateSetPrototypeOfArguments = function (O, proto) {
752 anObject(O);
753 if (!isObject(proto) && proto !== null) {
754 throw TypeError("Can't set " + String(proto) + ' as a prototype');
755 }
756};
757
758// Works with __proto__ only. Old v8 can't work with null proto objects.
759/* eslint-disable no-proto */
760
761
762var objectSetPrototypeOf = Object.setPrototypeOf || ('__proto__' in {} ? function () {
763 var correctSetter = false;
764 var test = {};
765 var setter;
766 try {
767 setter = Object.getOwnPropertyDescriptor(Object.prototype, '__proto__').set;
768 setter.call(test, []);
769 correctSetter = test instanceof Array;
770 } catch (error) { /* empty */ }
771 return function setPrototypeOf(O, proto) {
772 validateSetPrototypeOfArguments(O, proto);
773 if (correctSetter) setter.call(O, proto);
774 else O.__proto__ = proto;
775 return O;
776 };
777}() : undefined);
778
779var ITERATOR$1 = wellKnownSymbol('iterator');
780
781
782var IteratorPrototype$2 = iteratorsCore.IteratorPrototype;
783var BUGGY_SAFARI_ITERATORS$1 = iteratorsCore.BUGGY_SAFARI_ITERATORS;
784var KEYS = 'keys';
785var VALUES = 'values';
786var ENTRIES = 'entries';
787
788var returnThis$2 = function () { return this; };
789
790var defineIterator = function (Iterable, NAME, IteratorConstructor, next, DEFAULT, IS_SET, FORCED) {
791 createIteratorConstructor(IteratorConstructor, NAME, next);
792
793 var getIterationMethod = function (KIND) {
794 if (KIND === DEFAULT && defaultIterator) return defaultIterator;
795 if (!BUGGY_SAFARI_ITERATORS$1 && KIND in IterablePrototype) return IterablePrototype[KIND];
796 switch (KIND) {
797 case KEYS: return function keys() { return new IteratorConstructor(this, KIND); };
798 case VALUES: return function values() { return new IteratorConstructor(this, KIND); };
799 case ENTRIES: return function entries() { return new IteratorConstructor(this, KIND); };
800 } return function () { return new IteratorConstructor(this); };
801 };
802
803 var TO_STRING_TAG = NAME + ' Iterator';
804 var INCORRECT_VALUES_NAME = false;
805 var IterablePrototype = Iterable.prototype;
806 var nativeIterator = IterablePrototype[ITERATOR$1]
807 || IterablePrototype['@@iterator']
808 || DEFAULT && IterablePrototype[DEFAULT];
809 var defaultIterator = !BUGGY_SAFARI_ITERATORS$1 && nativeIterator || getIterationMethod(DEFAULT);
810 var anyNativeIterator = NAME == 'Array' ? IterablePrototype.entries || nativeIterator : nativeIterator;
811 var CurrentIteratorPrototype, methods, KEY;
812
813 // fix native
814 if (anyNativeIterator) {
815 CurrentIteratorPrototype = objectGetPrototypeOf(anyNativeIterator.call(new Iterable()));
816 if (IteratorPrototype$2 !== Object.prototype && CurrentIteratorPrototype.next) {
817 if (objectGetPrototypeOf(CurrentIteratorPrototype) !== IteratorPrototype$2) {
818 if (objectSetPrototypeOf) {
819 objectSetPrototypeOf(CurrentIteratorPrototype, IteratorPrototype$2);
820 } else if (typeof CurrentIteratorPrototype[ITERATOR$1] != 'function') {
821 hide(CurrentIteratorPrototype, ITERATOR$1, returnThis$2);
822 }
823 }
824 // Set @@toStringTag to native iterators
825 setToStringTag(CurrentIteratorPrototype, TO_STRING_TAG, true, true);
826 }
827 }
828
829 // fix Array#{values, @@iterator}.name in V8 / FF
830 if (DEFAULT == VALUES && nativeIterator && nativeIterator.name !== VALUES) {
831 INCORRECT_VALUES_NAME = true;
832 defaultIterator = function values() { return nativeIterator.call(this); };
833 }
834
835 // define iterator
836 if (IterablePrototype[ITERATOR$1] !== defaultIterator) {
837 hide(IterablePrototype, ITERATOR$1, defaultIterator);
838 }
839 iterators[NAME] = defaultIterator;
840
841 // export additional methods
842 if (DEFAULT) {
843 methods = {
844 values: getIterationMethod(VALUES),
845 keys: IS_SET ? defaultIterator : getIterationMethod(KEYS),
846 entries: getIterationMethod(ENTRIES)
847 };
848 if (FORCED) for (KEY in methods) {
849 if (BUGGY_SAFARI_ITERATORS$1 || INCORRECT_VALUES_NAME || !(KEY in IterablePrototype)) {
850 redefine(IterablePrototype, KEY, methods[KEY]);
851 }
852 } else _export({ target: NAME, proto: true, forced: BUGGY_SAFARI_ITERATORS$1 || INCORRECT_VALUES_NAME }, methods);
853 }
854
855 return methods;
856};
857
858var ARRAY_ITERATOR = 'Array Iterator';
859var setInternalState = internalState.set;
860var getInternalState = internalState.getterFor(ARRAY_ITERATOR);
861
862// `Array.prototype.entries` method
863// https://tc39.github.io/ecma262/#sec-array.prototype.entries
864// `Array.prototype.keys` method
865// https://tc39.github.io/ecma262/#sec-array.prototype.keys
866// `Array.prototype.values` method
867// https://tc39.github.io/ecma262/#sec-array.prototype.values
868// `Array.prototype[@@iterator]` method
869// https://tc39.github.io/ecma262/#sec-array.prototype-@@iterator
870// `CreateArrayIterator` internal method
871// https://tc39.github.io/ecma262/#sec-createarrayiterator
872var es_array_iterator = defineIterator(Array, 'Array', function (iterated, kind) {
873 setInternalState(this, {
874 type: ARRAY_ITERATOR,
875 target: toIndexedObject(iterated), // target
876 index: 0, // next index
877 kind: kind // kind
878 });
879// `%ArrayIteratorPrototype%.next` method
880// https://tc39.github.io/ecma262/#sec-%arrayiteratorprototype%.next
881}, function () {
882 var state = getInternalState(this);
883 var target = state.target;
884 var kind = state.kind;
885 var index = state.index++;
886 if (!target || index >= target.length) {
887 state.target = undefined;
888 return { value: undefined, done: true };
889 }
890 if (kind == 'keys') return { value: index, done: false };
891 if (kind == 'values') return { value: target[index], done: false };
892 return { value: [index, target[index]], done: false };
893}, 'values');
894
895// argumentsList[@@iterator] is %ArrayProto_values%
896// https://tc39.github.io/ecma262/#sec-createunmappedargumentsobject
897// https://tc39.github.io/ecma262/#sec-createmappedargumentsobject
898iterators.Arguments = iterators.Array;
899
900// https://tc39.github.io/ecma262/#sec-array.prototype-@@unscopables
901addToUnscopables('keys');
902addToUnscopables('values');
903addToUnscopables('entries');
904
905var aFunction = function (it) {
906 if (typeof it != 'function') {
907 throw TypeError(String(it) + ' is not a function');
908 } return it;
909};
910
911var anInstance = function (it, Constructor, name) {
912 if (!(it instanceof Constructor)) {
913 throw TypeError('Incorrect ' + (name ? name + ' ' : '') + 'invocation');
914 } return it;
915};
916
917// check on default Array iterator
918
919var ITERATOR$2 = wellKnownSymbol('iterator');
920var ArrayPrototype$1 = Array.prototype;
921
922var isArrayIteratorMethod = function (it) {
923 return it !== undefined && (iterators.Array === it || ArrayPrototype$1[ITERATOR$2] === it);
924};
925
926// optional / simple context binding
927var bindContext = function (fn, that, length) {
928 aFunction(fn);
929 if (that === undefined) return fn;
930 switch (length) {
931 case 0: return function () {
932 return fn.call(that);
933 };
934 case 1: return function (a) {
935 return fn.call(that, a);
936 };
937 case 2: return function (a, b) {
938 return fn.call(that, a, b);
939 };
940 case 3: return function (a, b, c) {
941 return fn.call(that, a, b, c);
942 };
943 }
944 return function (/* ...args */) {
945 return fn.apply(that, arguments);
946 };
947};
948
949var TO_STRING_TAG$1 = wellKnownSymbol('toStringTag');
950// ES3 wrong here
951var CORRECT_ARGUMENTS = classofRaw(function () { return arguments; }()) == 'Arguments';
952
953// fallback for IE11 Script Access Denied error
954var tryGet = function (it, key) {
955 try {
956 return it[key];
957 } catch (error) { /* empty */ }
958};
959
960// getting tag from ES6+ `Object.prototype.toString`
961var classof = function (it) {
962 var O, tag, result;
963 return it === undefined ? 'Undefined' : it === null ? 'Null'
964 // @@toStringTag case
965 : typeof (tag = tryGet(O = Object(it), TO_STRING_TAG$1)) == 'string' ? tag
966 // builtinTag case
967 : CORRECT_ARGUMENTS ? classofRaw(O)
968 // ES3 arguments fallback
969 : (result = classofRaw(O)) == 'Object' && typeof O.callee == 'function' ? 'Arguments' : result;
970};
971
972var ITERATOR$3 = wellKnownSymbol('iterator');
973
974
975var getIteratorMethod = function (it) {
976 if (it != undefined) return it[ITERATOR$3]
977 || it['@@iterator']
978 || iterators[classof(it)];
979};
980
981// call something on iterator step with safe closing on error
982var callWithSafeIterationClosing = function (iterator, fn, value, ENTRIES) {
983 try {
984 return ENTRIES ? fn(anObject(value)[0], value[1]) : fn(value);
985 // 7.4.6 IteratorClose(iterator, completion)
986 } catch (error) {
987 var returnMethod = iterator['return'];
988 if (returnMethod !== undefined) anObject(returnMethod.call(iterator));
989 throw error;
990 }
991};
992
993var iterate = createCommonjsModule(function (module) {
994var BREAK = {};
995
996var exports = module.exports = function (iterable, fn, that, ENTRIES, ITERATOR) {
997 var boundFunction = bindContext(fn, that, ENTRIES ? 2 : 1);
998 var iterator, iterFn, index, length, result, step;
999
1000 if (ITERATOR) {
1001 iterator = iterable;
1002 } else {
1003 iterFn = getIteratorMethod(iterable);
1004 if (typeof iterFn != 'function') throw TypeError('Target is not iterable');
1005 // optimisation for array iterators
1006 if (isArrayIteratorMethod(iterFn)) {
1007 for (index = 0, length = toLength(iterable.length); length > index; index++) {
1008 result = ENTRIES ? boundFunction(anObject(step = iterable[index])[0], step[1]) : boundFunction(iterable[index]);
1009 if (result === BREAK) return BREAK;
1010 } return;
1011 }
1012 iterator = iterFn.call(iterable);
1013 }
1014
1015 while (!(step = iterator.next()).done) {
1016 if (callWithSafeIterationClosing(iterator, boundFunction, step.value, ENTRIES) === BREAK) return BREAK;
1017 }
1018};
1019
1020exports.BREAK = BREAK;
1021});
1022
1023var ITERATOR$4 = wellKnownSymbol('iterator');
1024var SAFE_CLOSING = false;
1025
1026try {
1027 var called = 0;
1028 var iteratorWithReturn = {
1029 next: function () {
1030 return { done: !!called++ };
1031 },
1032 'return': function () {
1033 SAFE_CLOSING = true;
1034 }
1035 };
1036 iteratorWithReturn[ITERATOR$4] = function () {
1037 return this;
1038 };
1039} catch (error) { /* empty */ }
1040
1041var checkCorrectnessOfIteration = function (exec, SKIP_CLOSING) {
1042 if (!SKIP_CLOSING && !SAFE_CLOSING) return false;
1043 var ITERATION_SUPPORT = false;
1044 try {
1045 var object = {};
1046 object[ITERATOR$4] = function () {
1047 return {
1048 next: function () {
1049 return { done: ITERATION_SUPPORT = true };
1050 }
1051 };
1052 };
1053 exec(object);
1054 } catch (error) { /* empty */ }
1055 return ITERATION_SUPPORT;
1056};
1057
1058var SPECIES = wellKnownSymbol('species');
1059
1060// `SpeciesConstructor` abstract operation
1061// https://tc39.github.io/ecma262/#sec-speciesconstructor
1062var speciesConstructor = function (O, defaultConstructor) {
1063 var C = anObject(O).constructor;
1064 var S;
1065 return C === undefined || (S = anObject(C)[SPECIES]) == undefined ? defaultConstructor : aFunction(S);
1066};
1067
1068var set$1 = global$1.setImmediate;
1069var clear = global$1.clearImmediate;
1070var process$1 = global$1.process;
1071var MessageChannel = global$1.MessageChannel;
1072var Dispatch = global$1.Dispatch;
1073var counter = 0;
1074var queue = {};
1075var ONREADYSTATECHANGE = 'onreadystatechange';
1076var defer, channel, port;
1077
1078var run = function () {
1079 var id = +this;
1080 // eslint-disable-next-line no-prototype-builtins
1081 if (queue.hasOwnProperty(id)) {
1082 var fn = queue[id];
1083 delete queue[id];
1084 fn();
1085 }
1086};
1087
1088var listener = function (event) {
1089 run.call(event.data);
1090};
1091
1092// Node.js 0.9+ & IE10+ has setImmediate, otherwise:
1093if (!set$1 || !clear) {
1094 set$1 = function setImmediate(fn) {
1095 var args = [];
1096 var i = 1;
1097 while (arguments.length > i) args.push(arguments[i++]);
1098 queue[++counter] = function () {
1099 // eslint-disable-next-line no-new-func
1100 (typeof fn == 'function' ? fn : Function(fn)).apply(undefined, args);
1101 };
1102 defer(counter);
1103 return counter;
1104 };
1105 clear = function clearImmediate(id) {
1106 delete queue[id];
1107 };
1108 // Node.js 0.8-
1109 if (classofRaw(process$1) == 'process') {
1110 defer = function (id) {
1111 process$1.nextTick(bindContext(run, id, 1));
1112 };
1113 // Sphere (JS game engine) Dispatch API
1114 } else if (Dispatch && Dispatch.now) {
1115 defer = function (id) {
1116 Dispatch.now(bindContext(run, id, 1));
1117 };
1118 // Browsers with MessageChannel, includes WebWorkers
1119 } else if (MessageChannel) {
1120 channel = new MessageChannel();
1121 port = channel.port2;
1122 channel.port1.onmessage = listener;
1123 defer = bindContext(port.postMessage, port, 1);
1124 // Browsers with postMessage, skip WebWorkers
1125 // IE8 has postMessage, but it's sync & typeof its postMessage is 'object'
1126 } else if (global$1.addEventListener && typeof postMessage == 'function' && !global$1.importScripts) {
1127 defer = function (id) {
1128 global$1.postMessage(id + '', '*');
1129 };
1130 global$1.addEventListener('message', listener, false);
1131 // IE8-
1132 } else if (ONREADYSTATECHANGE in documentCreateElement('script')) {
1133 defer = function (id) {
1134 html.appendChild(documentCreateElement('script'))[ONREADYSTATECHANGE] = function () {
1135 html.removeChild(this);
1136 run.call(id);
1137 };
1138 };
1139 // Rest old browsers
1140 } else {
1141 defer = function (id) {
1142 setTimeout(bindContext(run, id, 1), 0);
1143 };
1144 }
1145}
1146
1147var task = {
1148 set: set$1,
1149 clear: clear
1150};
1151
1152var navigator = global$1.navigator;
1153
1154var userAgent = navigator && navigator.userAgent || '';
1155
1156var getOwnPropertyDescriptor$1 = objectGetOwnPropertyDescriptor.f;
1157
1158var macrotask = task.set;
1159
1160var MutationObserver = global$1.MutationObserver || global$1.WebKitMutationObserver;
1161var process$2 = global$1.process;
1162var Promise$1 = global$1.Promise;
1163var IS_NODE = classofRaw(process$2) == 'process';
1164// Node.js 11 shows ExperimentalWarning on getting `queueMicrotask`
1165var queueMicrotaskDescriptor = getOwnPropertyDescriptor$1(global$1, 'queueMicrotask');
1166var queueMicrotask = queueMicrotaskDescriptor && queueMicrotaskDescriptor.value;
1167
1168var flush, head, last, notify, toggle, node, promise;
1169
1170// modern engines have queueMicrotask method
1171if (!queueMicrotask) {
1172 flush = function () {
1173 var parent, fn;
1174 if (IS_NODE && (parent = process$2.domain)) parent.exit();
1175 while (head) {
1176 fn = head.fn;
1177 head = head.next;
1178 try {
1179 fn();
1180 } catch (error) {
1181 if (head) notify();
1182 else last = undefined;
1183 throw error;
1184 }
1185 } last = undefined;
1186 if (parent) parent.enter();
1187 };
1188
1189 // Node.js
1190 if (IS_NODE) {
1191 notify = function () {
1192 process$2.nextTick(flush);
1193 };
1194 // browsers with MutationObserver, except iOS - https://github.com/zloirock/core-js/issues/339
1195 } else if (MutationObserver && !/(iPhone|iPod|iPad).*AppleWebKit/i.test(userAgent)) {
1196 toggle = true;
1197 node = document.createTextNode('');
1198 new MutationObserver(flush).observe(node, { characterData: true }); // eslint-disable-line no-new
1199 notify = function () {
1200 node.data = toggle = !toggle;
1201 };
1202 // environments with maybe non-completely correct, but existent Promise
1203 } else if (Promise$1 && Promise$1.resolve) {
1204 // Promise.resolve without an argument throws an error in LG WebOS 2
1205 promise = Promise$1.resolve(undefined);
1206 notify = function () {
1207 promise.then(flush);
1208 };
1209 // for other environments - macrotask based on:
1210 // - setImmediate
1211 // - MessageChannel
1212 // - window.postMessag
1213 // - onreadystatechange
1214 // - setTimeout
1215 } else {
1216 notify = function () {
1217 // strange IE + webpack dev server bug - use .call(global)
1218 macrotask.call(global$1, flush);
1219 };
1220 }
1221}
1222
1223var microtask = queueMicrotask || function (fn) {
1224 var task = { fn: fn, next: undefined };
1225 if (last) last.next = task;
1226 if (!head) {
1227 head = task;
1228 notify();
1229 } last = task;
1230};
1231
1232// 25.4.1.5 NewPromiseCapability(C)
1233
1234
1235var PromiseCapability = function (C) {
1236 var resolve, reject;
1237 this.promise = new C(function ($$resolve, $$reject) {
1238 if (resolve !== undefined || reject !== undefined) throw TypeError('Bad Promise constructor');
1239 resolve = $$resolve;
1240 reject = $$reject;
1241 });
1242 this.resolve = aFunction(resolve);
1243 this.reject = aFunction(reject);
1244};
1245
1246var f$5 = function (C) {
1247 return new PromiseCapability(C);
1248};
1249
1250var newPromiseCapability = {
1251 f: f$5
1252};
1253
1254var promiseResolve = function (C, x) {
1255 anObject(C);
1256 if (isObject(x) && x.constructor === C) return x;
1257 var promiseCapability = newPromiseCapability.f(C);
1258 var resolve = promiseCapability.resolve;
1259 resolve(x);
1260 return promiseCapability.promise;
1261};
1262
1263var hostReportErrors = function (a, b) {
1264 var console = global$1.console;
1265 if (console && console.error) {
1266 arguments.length === 1 ? console.error(a) : console.error(a, b);
1267 }
1268};
1269
1270var perform = function (exec) {
1271 try {
1272 return { error: false, value: exec() };
1273 } catch (error) {
1274 return { error: true, value: error };
1275 }
1276};
1277
1278var redefineAll = function (target, src, options) {
1279 for (var key in src) redefine(target, key, src[key], options);
1280 return target;
1281};
1282
1283var path = global$1;
1284
1285var aFunction$1 = function (variable) {
1286 return typeof variable == 'function' ? variable : undefined;
1287};
1288
1289var getBuiltIn = function (namespace, method) {
1290 return arguments.length < 2 ? aFunction$1(path[namespace]) || aFunction$1(global$1[namespace])
1291 : path[namespace] && path[namespace][method] || global$1[namespace] && global$1[namespace][method];
1292};
1293
1294var SPECIES$1 = wellKnownSymbol('species');
1295
1296var setSpecies = function (CONSTRUCTOR_NAME) {
1297 var C = getBuiltIn(CONSTRUCTOR_NAME);
1298 var defineProperty = objectDefineProperty.f;
1299 if (descriptors && C && !C[SPECIES$1]) defineProperty(C, SPECIES$1, {
1300 configurable: true,
1301 get: function () { return this; }
1302 });
1303};
1304
1305var PROMISE = 'Promise';
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316var task$1 = task.set;
1317
1318
1319
1320
1321
1322
1323var SPECIES$2 = wellKnownSymbol('species');
1324
1325
1326var getInternalState$1 = internalState.get;
1327var setInternalState$1 = internalState.set;
1328var getInternalPromiseState = internalState.getterFor(PROMISE);
1329var PromiseConstructor = global$1[PROMISE];
1330var TypeError$1 = global$1.TypeError;
1331var document$3 = global$1.document;
1332var process$3 = global$1.process;
1333var $fetch = global$1.fetch;
1334var versions = process$3 && process$3.versions;
1335var v8 = versions && versions.v8 || '';
1336var newPromiseCapability$1 = newPromiseCapability.f;
1337var newGenericPromiseCapability = newPromiseCapability$1;
1338var IS_NODE$1 = classofRaw(process$3) == 'process';
1339var DISPATCH_EVENT = !!(document$3 && document$3.createEvent && global$1.dispatchEvent);
1340var UNHANDLED_REJECTION = 'unhandledrejection';
1341var REJECTION_HANDLED = 'rejectionhandled';
1342var PENDING = 0;
1343var FULFILLED = 1;
1344var REJECTED = 2;
1345var HANDLED = 1;
1346var UNHANDLED = 2;
1347var Internal, OwnPromiseCapability, PromiseWrapper;
1348
1349var FORCED = isForced_1(PROMISE, function () {
1350 // correct subclassing with @@species support
1351 var promise = PromiseConstructor.resolve(1);
1352 var empty = function () { /* empty */ };
1353 var FakePromise = (promise.constructor = {})[SPECIES$2] = function (exec) {
1354 exec(empty, empty);
1355 };
1356 // unhandled rejections tracking support, NodeJS Promise without it fails @@species test
1357 return !((IS_NODE$1 || typeof PromiseRejectionEvent == 'function')
1358 && (!isPure || promise['finally'])
1359 && promise.then(empty) instanceof FakePromise
1360 // v8 6.6 (Node 10 and Chrome 66) have a bug with resolving custom thenables
1361 // https://bugs.chromium.org/p/chromium/issues/detail?id=830565
1362 // we can't detect it synchronously, so just check versions
1363 && v8.indexOf('6.6') !== 0
1364 && userAgent.indexOf('Chrome/66') === -1);
1365});
1366
1367var INCORRECT_ITERATION = FORCED || !checkCorrectnessOfIteration(function (iterable) {
1368 PromiseConstructor.all(iterable)['catch'](function () { /* empty */ });
1369});
1370
1371// helpers
1372var isThenable = function (it) {
1373 var then;
1374 return isObject(it) && typeof (then = it.then) == 'function' ? then : false;
1375};
1376
1377var notify$1 = function (promise, state, isReject) {
1378 if (state.notified) return;
1379 state.notified = true;
1380 var chain = state.reactions;
1381 microtask(function () {
1382 var value = state.value;
1383 var ok = state.state == FULFILLED;
1384 var i = 0;
1385 var run = function (reaction) {
1386 var handler = ok ? reaction.ok : reaction.fail;
1387 var resolve = reaction.resolve;
1388 var reject = reaction.reject;
1389 var domain = reaction.domain;
1390 var result, then, exited;
1391 try {
1392 if (handler) {
1393 if (!ok) {
1394 if (state.rejection === UNHANDLED) onHandleUnhandled(promise, state);
1395 state.rejection = HANDLED;
1396 }
1397 if (handler === true) result = value;
1398 else {
1399 if (domain) domain.enter();
1400 result = handler(value); // may throw
1401 if (domain) {
1402 domain.exit();
1403 exited = true;
1404 }
1405 }
1406 if (result === reaction.promise) {
1407 reject(TypeError$1('Promise-chain cycle'));
1408 } else if (then = isThenable(result)) {
1409 then.call(result, resolve, reject);
1410 } else resolve(result);
1411 } else reject(value);
1412 } catch (error) {
1413 if (domain && !exited) domain.exit();
1414 reject(error);
1415 }
1416 };
1417 while (chain.length > i) run(chain[i++]); // variable length - can't use forEach
1418 state.reactions = [];
1419 state.notified = false;
1420 if (isReject && !state.rejection) onUnhandled(promise, state);
1421 });
1422};
1423
1424var dispatchEvent = function (name, promise, reason) {
1425 var event, handler;
1426 if (DISPATCH_EVENT) {
1427 event = document$3.createEvent('Event');
1428 event.promise = promise;
1429 event.reason = reason;
1430 event.initEvent(name, false, true);
1431 global$1.dispatchEvent(event);
1432 } else event = { promise: promise, reason: reason };
1433 if (handler = global$1['on' + name]) handler(event);
1434 else if (name === UNHANDLED_REJECTION) hostReportErrors('Unhandled promise rejection', reason);
1435};
1436
1437var onUnhandled = function (promise, state) {
1438 task$1.call(global$1, function () {
1439 var value = state.value;
1440 var IS_UNHANDLED = isUnhandled(state);
1441 var result;
1442 if (IS_UNHANDLED) {
1443 result = perform(function () {
1444 if (IS_NODE$1) {
1445 process$3.emit('unhandledRejection', value, promise);
1446 } else dispatchEvent(UNHANDLED_REJECTION, promise, value);
1447 });
1448 // Browsers should not trigger `rejectionHandled` event if it was handled here, NodeJS - should
1449 state.rejection = IS_NODE$1 || isUnhandled(state) ? UNHANDLED : HANDLED;
1450 if (result.error) throw result.value;
1451 }
1452 });
1453};
1454
1455var isUnhandled = function (state) {
1456 return state.rejection !== HANDLED && !state.parent;
1457};
1458
1459var onHandleUnhandled = function (promise, state) {
1460 task$1.call(global$1, function () {
1461 if (IS_NODE$1) {
1462 process$3.emit('rejectionHandled', promise);
1463 } else dispatchEvent(REJECTION_HANDLED, promise, state.value);
1464 });
1465};
1466
1467var bind = function (fn, promise, state, unwrap) {
1468 return function (value) {
1469 fn(promise, state, value, unwrap);
1470 };
1471};
1472
1473var internalReject = function (promise, state, value, unwrap) {
1474 if (state.done) return;
1475 state.done = true;
1476 if (unwrap) state = unwrap;
1477 state.value = value;
1478 state.state = REJECTED;
1479 notify$1(promise, state, true);
1480};
1481
1482var internalResolve = function (promise, state, value, unwrap) {
1483 if (state.done) return;
1484 state.done = true;
1485 if (unwrap) state = unwrap;
1486 try {
1487 if (promise === value) throw TypeError$1("Promise can't be resolved itself");
1488 var then = isThenable(value);
1489 if (then) {
1490 microtask(function () {
1491 var wrapper = { done: false };
1492 try {
1493 then.call(value,
1494 bind(internalResolve, promise, wrapper, state),
1495 bind(internalReject, promise, wrapper, state)
1496 );
1497 } catch (error) {
1498 internalReject(promise, wrapper, error, state);
1499 }
1500 });
1501 } else {
1502 state.value = value;
1503 state.state = FULFILLED;
1504 notify$1(promise, state, false);
1505 }
1506 } catch (error) {
1507 internalReject(promise, { done: false }, error, state);
1508 }
1509};
1510
1511// constructor polyfill
1512if (FORCED) {
1513 // 25.4.3.1 Promise(executor)
1514 PromiseConstructor = function Promise(executor) {
1515 anInstance(this, PromiseConstructor, PROMISE);
1516 aFunction(executor);
1517 Internal.call(this);
1518 var state = getInternalState$1(this);
1519 try {
1520 executor(bind(internalResolve, this, state), bind(internalReject, this, state));
1521 } catch (error) {
1522 internalReject(this, state, error);
1523 }
1524 };
1525 // eslint-disable-next-line no-unused-vars
1526 Internal = function Promise(executor) {
1527 setInternalState$1(this, {
1528 type: PROMISE,
1529 done: false,
1530 notified: false,
1531 parent: false,
1532 reactions: [],
1533 rejection: false,
1534 state: PENDING,
1535 value: undefined
1536 });
1537 };
1538 Internal.prototype = redefineAll(PromiseConstructor.prototype, {
1539 // `Promise.prototype.then` method
1540 // https://tc39.github.io/ecma262/#sec-promise.prototype.then
1541 then: function then(onFulfilled, onRejected) {
1542 var state = getInternalPromiseState(this);
1543 var reaction = newPromiseCapability$1(speciesConstructor(this, PromiseConstructor));
1544 reaction.ok = typeof onFulfilled == 'function' ? onFulfilled : true;
1545 reaction.fail = typeof onRejected == 'function' && onRejected;
1546 reaction.domain = IS_NODE$1 ? process$3.domain : undefined;
1547 state.parent = true;
1548 state.reactions.push(reaction);
1549 if (state.state != PENDING) notify$1(this, state, false);
1550 return reaction.promise;
1551 },
1552 // `Promise.prototype.catch` method
1553 // https://tc39.github.io/ecma262/#sec-promise.prototype.catch
1554 'catch': function (onRejected) {
1555 return this.then(undefined, onRejected);
1556 }
1557 });
1558 OwnPromiseCapability = function () {
1559 var promise = new Internal();
1560 var state = getInternalState$1(promise);
1561 this.promise = promise;
1562 this.resolve = bind(internalResolve, promise, state);
1563 this.reject = bind(internalReject, promise, state);
1564 };
1565 newPromiseCapability.f = newPromiseCapability$1 = function (C) {
1566 return C === PromiseConstructor || C === PromiseWrapper
1567 ? new OwnPromiseCapability(C)
1568 : newGenericPromiseCapability(C);
1569 };
1570
1571 // wrap fetch result
1572 if (typeof $fetch == 'function') _export({ global: true, enumerable: true, forced: true }, {
1573 // eslint-disable-next-line no-unused-vars
1574 fetch: function fetch(input) {
1575 return promiseResolve(PromiseConstructor, $fetch.apply(global$1, arguments));
1576 }
1577 });
1578}
1579
1580_export({ global: true, wrap: true, forced: FORCED }, { Promise: PromiseConstructor });
1581
1582setToStringTag(PromiseConstructor, PROMISE, false, true);
1583setSpecies(PROMISE);
1584
1585PromiseWrapper = path[PROMISE];
1586
1587// statics
1588_export({ target: PROMISE, stat: true, forced: FORCED }, {
1589 // `Promise.reject` method
1590 // https://tc39.github.io/ecma262/#sec-promise.reject
1591 reject: function reject(r) {
1592 var capability = newPromiseCapability$1(this);
1593 capability.reject.call(undefined, r);
1594 return capability.promise;
1595 }
1596});
1597
1598_export({ target: PROMISE, stat: true, forced: FORCED }, {
1599 // `Promise.resolve` method
1600 // https://tc39.github.io/ecma262/#sec-promise.resolve
1601 resolve: function resolve(x) {
1602 return promiseResolve(this, x);
1603 }
1604});
1605
1606_export({ target: PROMISE, stat: true, forced: INCORRECT_ITERATION }, {
1607 // `Promise.all` method
1608 // https://tc39.github.io/ecma262/#sec-promise.all
1609 all: function all(iterable) {
1610 var C = this;
1611 var capability = newPromiseCapability$1(C);
1612 var resolve = capability.resolve;
1613 var reject = capability.reject;
1614 var result = perform(function () {
1615 var values = [];
1616 var counter = 0;
1617 var remaining = 1;
1618 iterate(iterable, function (promise) {
1619 var index = counter++;
1620 var alreadyCalled = false;
1621 values.push(undefined);
1622 remaining++;
1623 C.resolve(promise).then(function (value) {
1624 if (alreadyCalled) return;
1625 alreadyCalled = true;
1626 values[index] = value;
1627 --remaining || resolve(values);
1628 }, reject);
1629 });
1630 --remaining || resolve(values);
1631 });
1632 if (result.error) reject(result.value);
1633 return capability.promise;
1634 },
1635 // `Promise.race` method
1636 // https://tc39.github.io/ecma262/#sec-promise.race
1637 race: function race(iterable) {
1638 var C = this;
1639 var capability = newPromiseCapability$1(C);
1640 var reject = capability.reject;
1641 var result = perform(function () {
1642 iterate(iterable, function (promise) {
1643 C.resolve(promise).then(capability.resolve, reject);
1644 });
1645 });
1646 if (result.error) reject(result.value);
1647 return capability.promise;
1648 }
1649});
1650
1651function _defineProperty(obj, key, value) {
1652 if (key in obj) {
1653 Object.defineProperty(obj, key, {
1654 value: value,
1655 enumerable: true,
1656 configurable: true,
1657 writable: true
1658 });
1659 } else {
1660 obj[key] = value;
1661 }
1662
1663 return obj;
1664}
1665
1666function _objectSpread(target) {
1667 for (var i = 1; i < arguments.length; i++) {
1668 var source = arguments[i] != null ? Object(arguments[i]) : {};
1669 var ownKeys = Object.keys(source);
1670
1671 if (typeof Object.getOwnPropertySymbols === 'function') {
1672 ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) {
1673 return Object.getOwnPropertyDescriptor(source, sym).enumerable;
1674 }));
1675 }
1676
1677 ownKeys.forEach(function (key) {
1678 _defineProperty(target, key, source[key]);
1679 });
1680 }
1681
1682 return target;
1683}
1684
1685function _objectWithoutPropertiesLoose(source, excluded) {
1686 if (source == null) return {};
1687 var target = {};
1688 var sourceKeys = Object.keys(source);
1689 var key, i;
1690
1691 for (i = 0; i < sourceKeys.length; i++) {
1692 key = sourceKeys[i];
1693 if (excluded.indexOf(key) >= 0) continue;
1694 target[key] = source[key];
1695 }
1696
1697 return target;
1698}
1699
1700function _objectWithoutProperties(source, excluded) {
1701 if (source == null) return {};
1702
1703 var target = _objectWithoutPropertiesLoose(source, excluded);
1704
1705 var key, i;
1706
1707 if (Object.getOwnPropertySymbols) {
1708 var sourceSymbolKeys = Object.getOwnPropertySymbols(source);
1709
1710 for (i = 0; i < sourceSymbolKeys.length; i++) {
1711 key = sourceSymbolKeys[i];
1712 if (excluded.indexOf(key) >= 0) continue;
1713 if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
1714 target[key] = source[key];
1715 }
1716 }
1717
1718 return target;
1719}
1720
1721/**
1722 * This abstract class should be implemented by all commands.
1723 */
1724class Command {
1725 constructor() {
1726 _defineProperty(this, "command", void 0);
1727
1728 _defineProperty(this, "description", void 0);
1729
1730 _defineProperty(this, "options", []);
1731 }
1732
1733}
1734
1735// a string of all valid unicode whitespaces
1736// eslint-disable-next-line max-len
1737var whitespaces = '\u0009\u000A\u000B\u000C\u000D\u0020\u00A0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFF';
1738
1739var whitespace = '[' + whitespaces + ']';
1740var ltrim = RegExp('^' + whitespace + whitespace + '*');
1741var rtrim = RegExp(whitespace + whitespace + '*$');
1742
1743// 1 -> String#trimStart
1744// 2 -> String#trimEnd
1745// 3 -> String#trim
1746var stringTrim = function (string, TYPE) {
1747 string = String(requireObjectCoercible(string));
1748 if (TYPE & 1) string = string.replace(ltrim, '');
1749 if (TYPE & 2) string = string.replace(rtrim, '');
1750 return string;
1751};
1752
1753var non = '\u200B\u0085\u180E';
1754
1755// check that a method works with the correct list
1756// of whitespaces and has a correct name
1757var forcedStringTrimMethod = function (METHOD_NAME) {
1758 return fails(function () {
1759 return !!whitespaces[METHOD_NAME]() || non[METHOD_NAME]() != non || whitespaces[METHOD_NAME].name !== METHOD_NAME;
1760 });
1761};
1762
1763var FORCED$1 = forcedStringTrimMethod('trim');
1764
1765// `String.prototype.trim` method
1766// https://tc39.github.io/ecma262/#sec-string.prototype.trim
1767_export({ target: 'String', proto: true, forced: FORCED$1 }, {
1768 trim: function trim() {
1769 return stringTrim(this, 3);
1770 }
1771});
1772
1773const semverRegex = require('semver-regex');
1774
1775const getLatestVersion = require('latest-version');
1776
1777function parseVersion(v) {
1778 if (v === null) throw new Error('Version is null.');
1779
1780 if (typeof v === 'string') {
1781 const parsedV = semver__default.parse(semverRegex().exec(v)[0]);
1782
1783 if (parsedV === null) {
1784 throw new Error(`Version ${v.trim()} cannot be parsed.`);
1785 }
1786
1787 return parsedV;
1788 }
1789
1790 return v;
1791}
1792async function latestVersion(npmPackageName) {
1793 return parseVersion((await getLatestVersion(npmPackageName)));
1794}
1795
1796function useExeca(cmd, options) {
1797 const [execaResult, setExecaResult] = React__default.useState();
1798 React__default.useEffect(() => {
1799 const p = execa.command(cmd, _objectSpread({
1800 reject: false
1801 }, options));
1802 p.then(r => {
1803 if (r.killed) return;
1804 setExecaResult(r);
1805 });
1806 return () => p.kill();
1807 }, [cmd, options]);
1808 return execaResult;
1809}
1810function useLatestNpmVersion(pkg) {
1811 const [latest, setLatest] = React__default.useState(null);
1812 const [error, setError] = React__default.useState();
1813 React__default.useEffect(() => {
1814 let mounted = true;
1815 latestVersion(pkg).then(v => {
1816 if (mounted) setLatest(v);
1817 }).catch(e => {
1818 if (mounted) setError(e);
1819 });
1820 return () => {
1821 mounted = false;
1822 };
1823 }, [pkg]);
1824 return {
1825 latest,
1826 error
1827 };
1828}
1829function latestVersionResult(version) {
1830 return {
1831 type: CheckStatusType.Ok,
1832 message: React__default.createElement(React__default.Fragment, null, "Version ", React__default.createElement(Version, {
1833 version: version
1834 }), " is the latest.")
1835 };
1836}
1837function outdatedVersionResult(current, latest, type = CheckStatusType.Warning) {
1838 return {
1839 type,
1840 message: React__default.createElement(React__default.Fragment, null, "You have version ", React__default.createElement(Version, {
1841 version: current
1842 }), " while the latest is", ' ', React__default.createElement(Version, {
1843 version: latest
1844 }), ".")
1845 };
1846}
1847function Version({
1848 version
1849}) {
1850 return React__default.createElement(ink.Text, {
1851 color: "cyan"
1852 }, typeof version === 'string' ? version : version.format());
1853}
1854
1855function usePHPCheck() {
1856 const phpV = useExeca('php -v');
1857 const version = phpV && !phpV.failed ? parseVersion(phpV.stdout) : undefined;
1858
1859 if (!phpV) {
1860 return {
1861 type: CheckStatusType.Loading,
1862 message: 'Checking your PHP version...'
1863 };
1864 }
1865
1866 if (!version) {
1867 return {
1868 type: CheckStatusType.Error,
1869 message: "Looks like you don't have PHP correctly installed."
1870 };
1871 }
1872
1873 if (version.major >= 7 && version.minor >= 4) {
1874 return {
1875 type: CheckStatusType.Ok,
1876 message: React__default.createElement(React__default.Fragment, null, "You have PHP ", React__default.createElement(Version, {
1877 version: version
1878 }), " installed.")
1879 };
1880 }
1881
1882 return {
1883 type: CheckStatusType.Warning,
1884 message: React__default.createElement(React__default.Fragment, null, "You have PHP ", React__default.createElement(Version, {
1885 version: version
1886 }), " installed, but you need at least ", React__default.createElement(Version, {
1887 version: "7.4"
1888 }), ".")
1889 };
1890}
1891
1892function useExit(shouldExit, error) {
1893 const {
1894 exit
1895 } = ink.useApp();
1896 React__default.useEffect(() => {
1897 if (shouldExit) exit(error);
1898 }, [error, exit, shouldExit]);
1899}
1900
1901function useAxios(url, config) {
1902 const [res, setRes] = React__default.useState({
1903 loading: true
1904 });
1905 React__default.useEffect(() => {
1906 const source = axios.CancelToken.source();
1907 axios(_objectSpread({
1908 url,
1909 cancelToken: source.token
1910 }, config)).then(response => {
1911 setRes({
1912 response,
1913 loading: false
1914 });
1915 }).catch(error => {
1916 if (!axios.isCancel(error)) {
1917 setRes({
1918 error,
1919 loading: false
1920 });
1921 }
1922 });
1923 return () => {
1924 source.cancel();
1925 };
1926 }, [config, url]);
1927 return res;
1928}
1929
1930const axiosConfig = {
1931 timeout: 3000
1932};
1933function useNodeJsCheck() {
1934 const nodeVersions = useAxios('https://nodejs.org/dist/index.json', axiosConfig);
1935 const nodeVersion = parseVersion(process.version);
1936 const versionSupported = nodeVersion.major === 8 || nodeVersion.major === 10;
1937
1938 if (!versionSupported) {
1939 return {
1940 type: CheckStatusType.Error,
1941 message: 'You should use Node.js 8 or 10.'
1942 };
1943 }
1944
1945 if (nodeVersions.error) {
1946 return {
1947 type: CheckStatusType.LoadingError,
1948 message: `Error fetching latest version: ${nodeVersions.error.message}`
1949 };
1950 }
1951
1952 if (nodeVersions.loading) {
1953 return {
1954 type: CheckStatusType.Loading,
1955 message: 'Fetching latest version...'
1956 };
1957 }
1958
1959 const latestInMajor = nodeVersions.response.data.map(v => parseVersion(v.version)).find(s => !!s && s.major === nodeVersion.major);
1960
1961 if (!latestInMajor) {
1962 return {
1963 type: CheckStatusType.LoadingError,
1964 message: "Can't find latest Node.js version."
1965 };
1966 }
1967
1968 if (latestInMajor.compare(nodeVersion) === 0) {
1969 return latestVersionResult(nodeVersion);
1970 }
1971
1972 return outdatedVersionResult(nodeVersion, latestInMajor);
1973}
1974
1975function useNPMCheck() {
1976 const npmV = useExeca('npm -v');
1977 const version = npmV ? parseVersion(npmV.stdout) : undefined;
1978 const {
1979 latest,
1980 error
1981 } = useLatestNpmVersion('npm');
1982
1983 if (!npmV) {
1984 return {
1985 type: CheckStatusType.Loading,
1986 message: 'Getting your NPM version...'
1987 };
1988 }
1989
1990 if (!version) {
1991 return {
1992 type: CheckStatusType.Error,
1993 message: 'Something is wrong with your NPM installation.'
1994 };
1995 }
1996
1997 if (error) {
1998 return {
1999 type: CheckStatusType.LoadingError,
2000 message: `Error fetching latest version: ${error.message}`
2001 };
2002 }
2003
2004 if (!latest) {
2005 return {
2006 type: CheckStatusType.Loading,
2007 message: 'Getting latest version from NPM...'
2008 };
2009 }
2010
2011 if (latest.compare(version.version) === 0) {
2012 return latestVersionResult(version);
2013 }
2014
2015 return outdatedVersionResult(version, latest);
2016}
2017
2018var version = "0.0.151";
2019
2020const updatedError = new Error('Burst CLI was updated!');
2021function UpdateBurstCli() {
2022 const updateCommand = useExeca('npm i -g @burst/cli');
2023 useExit(!!updateCommand, updatedError);
2024
2025 if (!updateCommand) {
2026 return React__default.createElement(ink.Box, {
2027 marginTop: 1,
2028 marginBottom: 1
2029 }, React__default.createElement(ink.Text, null, "Updating the Burst CLI to the latest version..."));
2030 }
2031
2032 return React__default.createElement(ink.Box, {
2033 marginTop: 1,
2034 marginBottom: 1
2035 }, updateCommand.failed ? React__default.createElement(ink.Text, null, "Burst CLI ", React__default.createElement(ink.Text, {
2036 bold: true
2037 }, "failed to update"), ", please run", ' ', React__default.createElement(ink.Text, {
2038 color: "cyan"
2039 }, "npm i -g @burst/cli"), " yourself.") : React__default.createElement(ink.Text, null, "Burst CLI updated, please re-run your command."));
2040}
2041function useBurstCliCheck() {
2042 const {
2043 latest,
2044 error
2045 } = useLatestNpmVersion('@burst/cli');
2046
2047 if (error) {
2048 return {
2049 type: CheckStatusType.LoadingError,
2050 message: `Error fetching latest version: ${error.message}`
2051 };
2052 }
2053
2054 if (latest) {
2055 if (latest.compare(version) !== 0) {
2056 return outdatedVersionResult(version, latest, CheckStatusType.Error);
2057 }
2058
2059 return latestVersionResult(latest);
2060 }
2061
2062 return {
2063 type: CheckStatusType.Loading,
2064 message: 'Getting latest version from NPM...'
2065 };
2066}
2067
2068const minVersion = '3.0.0-rc.12';
2069const maxVersion = '3.0.0-rc.15';
2070function useLandoCheck() {
2071 const lando = useExeca('lando version');
2072 const version = lando && lando.exitCode === 0 ? parseVersion(lando.stdout) : undefined;
2073
2074 if (!lando) {
2075 return {
2076 type: CheckStatusType.Loading,
2077 message: 'Checking your Lando version...'
2078 };
2079 }
2080
2081 if (!version) {
2082 return {
2083 type: CheckStatusType.Ok,
2084 message: "You don't have Lando installed, which is fine."
2085 };
2086 }
2087
2088 const downloadLink = React__default.createElement(React__default.Fragment, null, "Download the latest supported version here:", ' ', `https://github.com/lando/lando/releases/tag/v${maxVersion}`);
2089
2090 if (version.compare(minVersion) === -1) {
2091 return {
2092 type: CheckStatusType.Error,
2093 message: React__default.createElement(React__default.Fragment, null, "You have Lando ", React__default.createElement(Version, {
2094 version: version
2095 }), " installed, but you need at least ", React__default.createElement(Version, {
2096 version: minVersion
2097 }), ". Please update to", ' ', React__default.createElement(Version, {
2098 version: maxVersion
2099 }), " if possible. ", downloadLink)
2100 };
2101 }
2102
2103 if (version.compare(maxVersion) === 1) {
2104 return {
2105 type: CheckStatusType.Error,
2106 message: React__default.createElement(React__default.Fragment, null, "You have Lando ", React__default.createElement(Version, {
2107 version: version
2108 }), " installed, but the latest supported version is ", React__default.createElement(Version, {
2109 version: maxVersion
2110 }), ". Please downgrade to to that version. ", downloadLink)
2111 };
2112 }
2113
2114 if (version.compare(maxVersion) === -1) {
2115 return {
2116 type: CheckStatusType.Warning,
2117 message: React__default.createElement(React__default.Fragment, null, "You have Lando ", React__default.createElement(Version, {
2118 version: version
2119 }), " installed, but the latest supported version is ", React__default.createElement(Version, {
2120 version: maxVersion
2121 }), ". ", downloadLink)
2122 };
2123 }
2124
2125 return {
2126 type: CheckStatusType.Ok,
2127 message: React__default.createElement(React__default.Fragment, null, "You have Lando ", React__default.createElement(Version, {
2128 version: version
2129 }), " installed.")
2130 };
2131}
2132
2133const isCI = require('is-ci');
2134
2135class CheckCommand extends Command {
2136 constructor(...args) {
2137 super(...args);
2138
2139 _defineProperty(this, "command", 'check');
2140
2141 _defineProperty(this, "description", 'Check your local environment.');
2142 }
2143
2144 async action() {
2145 const a = ink.render(React__default.createElement(Check, null));
2146 await a.waitUntilExit();
2147 }
2148
2149}
2150function checkFirst(funcToWrap) {
2151 return async (...args) => {
2152 // We don't want to check first on the CI.
2153 if (!isCI) {
2154 try {
2155 const a = ink.render(React__default.createElement(Check, {
2156 onlyDisplayErrors: true
2157 }));
2158 await a.waitUntilExit();
2159 a.cleanup();
2160 } catch (error) {
2161 if (error !== updatedError) {
2162 throw error;
2163 } // The Burst CLI was just updated, so we need to stop.
2164
2165
2166 process.exit(1);
2167 }
2168 }
2169
2170 return funcToWrap(...args);
2171 };
2172}
2173let CheckStatusType;
2174
2175(function (CheckStatusType) {
2176 CheckStatusType[CheckStatusType["Loading"] = 0] = "Loading";
2177 CheckStatusType[CheckStatusType["Warning"] = 1] = "Warning";
2178 CheckStatusType[CheckStatusType["Error"] = 2] = "Error";
2179 CheckStatusType[CheckStatusType["LoadingError"] = 3] = "LoadingError";
2180 CheckStatusType[CheckStatusType["Ok"] = 4] = "Ok";
2181})(CheckStatusType || (CheckStatusType = {}));
2182
2183function Check({
2184 onlyDisplayErrors = false
2185}) {
2186 const checks = [['Burst CLI', useBurstCliCheck()], ['Node.js', useNodeJsCheck()], ['PHP', usePHPCheck()], ['NPM', useNPMCheck()], ['Lando', useLandoCheck()]];
2187 const burstCliNeedsUpdate = checks[0][1].type === CheckStatusType.Error;
2188 const checksLoaded = checks.every(([, c]) => c.type !== CheckStatusType.Loading);
2189 useExit(checksLoaded && !burstCliNeedsUpdate);
2190 return React__default.createElement(ink.Box, {
2191 marginBottom: 1,
2192 flexDirection: "column"
2193 }, (onlyDisplayErrors ? checks.filter(([, c]) => c.type !== CheckStatusType.Loading && c.type !== CheckStatusType.Ok) : checks).map(([n, c]) => React__default.createElement(ink.Box, {
2194 key: n
2195 }, React__default.createElement(ink.Box, {
2196 width: 4
2197 }, React__default.createElement(ink.Text, null, c.type === CheckStatusType.Loading ? '⌚' : c.type === CheckStatusType.Warning ? '🚧' : c.type === CheckStatusType.Error ? '❌' : c.type === CheckStatusType.LoadingError ? '❌' : '👍')), React__default.createElement(ink.Box, {
2198 width: 12
2199 }, React__default.createElement(ink.Text, null, n)), React__default.createElement(ink.Box, {
2200 flexGrow: 1
2201 }, React__default.createElement(ink.Text, null, c.message)))), !checksLoaded && React__default.createElement(ink.Box, {
2202 marginTop: 1,
2203 marginBottom: 1
2204 }, React__default.createElement(ink.Text, null, "Checking your local development environment...")), burstCliNeedsUpdate && React__default.createElement(UpdateBurstCli, null));
2205}
2206
2207const isCI$1 = require('is-ci');
2208
2209class PrepareCICommand extends Command {
2210 constructor(...args) {
2211 super(...args);
2212
2213 _defineProperty(this, "command", 'prepare-ci');
2214
2215 _defineProperty(this, "description", 'This adds various environment varibles.');
2216
2217 _defineProperty(this, "action", async () => {
2218 if (!isCI$1) {
2219 console.log('You can only run this command in the CI.');
2220 process.exit(1);
2221 }
2222
2223 console.log((await prepareCI()));
2224 });
2225 }
2226
2227}
2228async function prepareCI() {
2229 if (!isCI$1) return [];
2230 const toEval = []; // Start ssh agent
2231
2232 if (!process.env.SSH_AUTH_SOCK || !process.env.SSH_AGENT_PID) {
2233 const {
2234 stdout: agent
2235 } = await execa('ssh-agent');
2236 toEval.push(agent);
2237 const [, authSock] = /SSH_AUTH_SOCK=(.*); export/.exec(agent) || ['', ''];
2238 const [, agentPid] = /SSH_AGENT_PID=(.*); export/.exec(agent) || ['', ''];
2239 process.env.SSH_AUTH_SOCK = authSock;
2240 process.env.SSH_AGENT_PID = agentPid;
2241 } // Add ssh key
2242
2243
2244 if (process.env.PLATFORMSH_SSH_KEY) {
2245 await execa.command(`echo "$PLATFORMSH_SSH_KEY" | tr -d '\\r' | ssh-add - > /dev/null`, {
2246 shell: true
2247 });
2248 }
2249
2250 return toEval.join('\n');
2251}
2252
2253const isCI$2 = require('is-ci');
2254
2255const repoRootGitCmd = process.env.CI_PROJECT_DIR ? {
2256 stdout: process.env.CI_PROJECT_DIR,
2257 failed: false
2258} : execa.sync('git', ['rev-parse', '--show-toplevel'], {
2259 reject: false
2260});
2261
2262if (repoRootGitCmd.failed) {
2263 throw new Error('Please use the Burst CLI in a git repository.');
2264}
2265
2266const repoRoot = repoRootGitCmd.stdout;
2267/** @deprecated */
2268
2269function getRepoRoot() {
2270 return repoRoot;
2271}
2272async function push(url, branch, {
2273 dir
2274} = {}) {
2275 // Remove any possible old remote we could still have.
2276 // We catch everything, because it fails if there isn't one.
2277 // That's no problem.
2278 await execa('git', ['remote', 'remove', '_burst_tmp_']).catch(() => undefined); // Add a new remote with the push url.
2279
2280 await execa('git', ['remote', 'add', '_burst_tmp_', url]); // Push current head to the new remote on the branch provided.
2281
2282 try {
2283 let src = 'HEAD';
2284
2285 if (dir) {
2286 console.log(`Creating git subtree of the ${chalk.cyan(dir)} directory.`);
2287 ({
2288 stdout: src
2289 } = await execa('git', ['subtree', 'split', '--prefix', dir], {
2290 stderr: !isCI$2 ? 'inherit' : undefined,
2291 // We always need to run the subtree command from the root of the
2292 // project, see #44.
2293 cwd: repoRoot
2294 }));
2295 console.log('Done with creating subtree.');
2296 } // Make sure we can push with SSH if on the Gitlab CI
2297
2298
2299 await prepareCI(); // We push the src (which is HEAD or a commit id) to the remote repository. We prefix
2300 // the remote repository with refs/heads/ so the branch is created if it doesn't
2301 // exist on the remote already.
2302
2303 await execa('git', ['push', '_burst_tmp_', `${src}:refs/heads/${branch}`, '--force', '--verbose'], {
2304 stdio: 'inherit'
2305 });
2306 } finally {
2307 // Remove the remote (even if pushing failed).
2308 await execa('git', ['remote', 'remove', '_burst_tmp_']).catch(() => {// do nothing
2309 });
2310 }
2311}
2312async function getCurrentBranch() {
2313 // In Gitlab CI, we can use this environment variable.
2314 if (process.env.CI_COMMIT_REF_NAME) return process.env.CI_COMMIT_REF_NAME; // Otherwise, we use the Git CLI to get the current branch.
2315
2316 return (await execa('git', ['rev-parse', '--abbrev-ref', 'HEAD'])).stdout;
2317}
2318async function getListOfRepoFiles(search = [], fromRoot = false) {
2319 const cwd = fromRoot || !search.length ? repoRoot : undefined; // To get a complete list of all files that are on disk and not excluded by a
2320 // gitignore rule, we need to do multple 'git ls-files' calls.
2321 //
2322 // CACHED:
2323 // This are all the files that are currently staged.
2324 // If a file is deleted but that change isn't staged yet, it will still be
2325 // returned.
2326 //
2327 // DELETED:
2328 // This returns all files that are staged at this moment, but aren't
2329 // available on the disk anymore. If a deletion is staged, it isn't returned
2330 // anymore.
2331 //
2332 // UNTRACKED:
2333 // This are all the new files that exist on disk, but aren't tracked / staged
2334 // yet.
2335
2336 const [cached, deleted, untracked] = await Promise.all([gitLsFiles(search, cwd), gitLsFiles(['--deleted', ...search], cwd), gitLsFiles([...search, '--others', '--exclude-standard'], cwd)]);
2337 return [...untracked, ...cached.filter(file => !deleted.includes(file))];
2338}
2339
2340async function gitLsFiles(opts, cwd) {
2341 const {
2342 stdout: command
2343 } = await execa('git', ['ls-files', ...opts, '--full-name'], {
2344 cwd
2345 });
2346 return command.split('\n').filter(f => f.length);
2347}
2348
2349function useTsWorker() {
2350 return useWorker('./workers/ts', React.useMemo(() => ['doTsCheck'], []), React.useMemo(() => ({
2351 numWorkers: 1
2352 }), []));
2353}
2354function usePrettierWorker() {
2355 return useWorker('./workers/prettier', React.useMemo(() => ['getFileInfo', 'format'], []), React.useMemo(() => ({
2356 numWorkers: 1
2357 }), []));
2358}
2359function useEslintWorker() {
2360 return useWorker('./workers/eslint', React.useMemo(() => ['lintFile', 'writeToDisk'], []), React.useMemo(() => ({
2361 numWorkers: 2
2362 }), []));
2363}
2364
2365function useWorker(path, exposedMethods, options) {
2366 const worker = React.useMemo(() => new Worker(require.resolve(path), _objectSpread({}, options, {
2367 exposedMethods: exposedMethods
2368 })), [exposedMethods, path, options]);
2369 React.useEffect(() => () => {
2370 worker.end();
2371 }, [worker]);
2372 return worker;
2373}
2374
2375function useTsChecker(allFiles) {
2376 const files = React.useMemo(() => allFiles.filter(f => f.path.endsWith('.ts') || f.path.endsWith('.tsx')), [allFiles]);
2377 const [filesWithTs, filesWithoutTs] = React.useMemo(() => {
2378 const resolved = lodash.groupBy(files, file => resolve.silent(file.absolutePath, 'typescript'));
2379
2380 const {
2381 undefined: withoutTs = []
2382 } = resolved,
2383 withTs = _objectWithoutProperties(resolved, ["undefined"]);
2384
2385 return [withTs, withoutTs];
2386 }, [files]);
2387 const worker = useTsWorker();
2388 const [workerResults, setWorkerResults] = React.useState([]);
2389 React.useEffect(() => {
2390 Object.entries(filesWithTs).forEach(async ([tsPath, tsFiles]) => {
2391 const workerResult = await worker.doTsCheck(tsPath, tsFiles.map(f => f.absolutePath));
2392 setWorkerResults(r => [...r, workerResult]);
2393 });
2394 }, [filesWithTs, worker]);
2395 const filesWithoutProject = lodash.flatten(workerResults.map(r => r.filesWithoutProject));
2396 const filesNotIncludedInProject = lodash.flatten(workerResults.map(r => r.filesNotIncludedInProject));
2397 const errors = [...filesWithoutTs.map(f => ({
2398 filename: f.absolutePath,
2399 message: 'No TypeScript module can be found for this file. \nAre you sure TypeScript is installed?'
2400 })), ...filesWithoutProject.map(f => ({
2401 filename: f,
2402 message: 'Found no tsconfig.json file. \nAre you sure there is a tsconfig.json file in the root of the app?'
2403 })), ...filesNotIncludedInProject.map(f => ({
2404 filename: f,
2405 message: 'There is a tsconfig.json file, but it looks like this file is excluded. \nPlease check the include / exclude part of the tsconfig.json file.'
2406 })), ...lodash.flatten(workerResults.map(r => r.errors))].map(f => _objectSpread({}, f, {
2407 linter: 'TypeScript',
2408 autoFixable: false
2409 }));
2410 return {
2411 files,
2412 done: workerResults.length === Object.keys(filesWithTs).length,
2413 errors
2414 };
2415}
2416
2417function useEslint(allFiles, fix) {
2418 const files = React.useMemo(() => allFiles.filter(f => f.path.endsWith('.js') || f.path.endsWith('.jsx') || f.path.endsWith('.ts') || f.path.endsWith('.tsx')), [allFiles]);
2419 const eslint = useEslintWorker();
2420 const [reports, setReports] = React.useState([]);
2421 const [execErrors, setExecErrors] = React.useState({});
2422 React.useEffect(() => {
2423 files.forEach(async file => {
2424 try {
2425 const report = await eslint.lintFile(file.absolutePath, fix);
2426
2427 if (report.results.length === 0) {
2428 throw new Error('The file could not be linted by ESLint.');
2429 }
2430
2431 if (fix) {
2432 await eslint.writeToDisk(report);
2433 }
2434
2435 setReports(r => [...r, ...report.results]);
2436 } catch (e) {
2437 setExecErrors(exe => _objectSpread({}, exe, {
2438 [file.absolutePath]: e.message || e.toString()
2439 }));
2440 }
2441 });
2442 }, [eslint, files, fix]);
2443 const [longTimeAgoSinceLastReport, setLTASLR] = React.useState(false);
2444 const allFilesLinted = reports.length + Object.keys(execErrors).length === files.length;
2445 React.useEffect(() => {
2446 if (allFilesLinted || longTimeAgoSinceLastReport) return; // When not a single file has been linted in the last minute - it is probabily
2447 // stuck on one file. We add an error for these files.
2448
2449 const timeoutId = setTimeout(() => {
2450 setLTASLR(true);
2451 }, 5 * 60 * 1000);
2452 return () => clearTimeout(timeoutId);
2453 }, [reports, execErrors, allFilesLinted, longTimeAgoSinceLastReport]);
2454 const filesAutoFixed = fix ? reports.reduce((c, r) => c + (r.output ? 1 : 0), 0) : 0;
2455 const errors = [];
2456 const prettierErrors = [];
2457 reports.forEach(r => {
2458 r.messages.forEach(m => {
2459 // We only want to show the Prettier error once per file.
2460 if (m.ruleId === 'prettier/prettier') {
2461 if (prettierErrors.includes(r.filePath)) return;
2462 errors.push({
2463 linter: 'ESLint',
2464 filename: r.filePath,
2465 autoFixable: true,
2466 message: 'Not according to Prettier styling.',
2467 rule: 'prettier/prettier'
2468 });
2469 prettierErrors.push(r.filePath);
2470 return;
2471 }
2472
2473 errors.push({
2474 linter: 'ESLint',
2475 filename: r.filePath,
2476 autoFixable: !!m.fix,
2477 message: m.message,
2478 rule: m.ruleId || undefined,
2479 sourceLocation: _objectSpread({
2480 start: {
2481 line: m.line,
2482 column: m.column
2483 }
2484 }, m.endLine ? {
2485 end: {
2486 line: m.endLine,
2487 column: m.endColumn
2488 }
2489 } : {})
2490 });
2491 });
2492 });
2493 Object.entries(execErrors).forEach(([filename, error]) => {
2494 errors.push({
2495 linter: 'ESLint',
2496 filename,
2497 autoFixable: false,
2498 message: error
2499 });
2500 });
2501 const filesReported = reports.map(r => r.filePath);
2502 const filesWithErrors = Object.keys(execErrors);
2503
2504 if (longTimeAgoSinceLastReport) {
2505 files.filter(f => !filesReported.includes(f.absolutePath) && !filesWithErrors.includes(f.absolutePath)).forEach(file => {
2506 errors.push({
2507 linter: 'ESLint',
2508 filename: file.absolutePath,
2509 autoFixable: false,
2510 message: 'ESLint has probabily timeout while linting this file.'
2511 });
2512 });
2513 }
2514
2515 return {
2516 files,
2517 reports,
2518 filesAutoFixed,
2519 errors,
2520 done: allFilesLinted || longTimeAgoSinceLastReport
2521 };
2522}
2523
2524var sloppyArrayMethod = function (METHOD_NAME, argument) {
2525 var method = [][METHOD_NAME];
2526 return !method || !fails(function () {
2527 // eslint-disable-next-line no-useless-call,no-throw-literal
2528 method.call(null, argument || function () { throw 1; }, 1);
2529 });
2530};
2531
2532var nativeSort = [].sort;
2533var test = [1, 2, 3];
2534
2535// IE8-
2536var FAILS_ON_UNDEFINED = fails(function () {
2537 test.sort(undefined);
2538});
2539// V8 bug
2540var FAILS_ON_NULL = fails(function () {
2541 test.sort(null);
2542});
2543// Old WebKit
2544var SLOPPY_METHOD = sloppyArrayMethod('sort');
2545
2546var FORCED$2 = FAILS_ON_UNDEFINED || !FAILS_ON_NULL || SLOPPY_METHOD;
2547
2548// `Array.prototype.sort` method
2549// https://tc39.github.io/ecma262/#sec-array.prototype.sort
2550_export({ target: 'Array', proto: true, forced: FORCED$2 }, {
2551 sort: function sort(comparefn) {
2552 return comparefn === undefined
2553 ? nativeSort.call(toObject(this))
2554 : nativeSort.call(toObject(this), aFunction(comparefn));
2555 }
2556});
2557
2558function isObject$1(something) {
2559 return typeof something === 'object' && something !== null;
2560}
2561
2562const appTypes = ['drupal', 'wordpress', 'magento', 'other'];
2563function getProjectConfiguration(burstYaml, gitlabYaml, getPathFromDir) {
2564 const burstConfig = yaml.safeLoad(burstYaml || '{}');
2565 const gitlabConfig = yaml.safeLoad(gitlabYaml || '{}');
2566
2567 if (!isObject$1(burstConfig)) {
2568 throw new Error('The burst.yaml is invalid. Please export an object.');
2569 }
2570
2571 if (!isObject$1(gitlabConfig)) {
2572 throw new Error('The .gitlab-ci.yml file is invalid. The contents should be an object.');
2573 }
2574
2575 const apps = isObject$1(burstConfig.apps) ? Object.entries(burstConfig.apps).map(([name, app]) => {
2576 if (!isObject$1(app)) {
2577 throw new Error(`App "${name}" should be an object.`);
2578 }
2579
2580 let type = 'other';
2581
2582 if (typeof app.type !== 'undefined') {
2583 if (!isAppType(app.type)) {
2584 throw new Error(`The type of "${name}" should be any of: ${appTypes.join(', ')}.`);
2585 }
2586
2587 ({
2588 type
2589 } = app);
2590 } else if (isAppType(name)) {
2591 type = name;
2592 }
2593
2594 let dir = name;
2595
2596 if (typeof app.dir === 'string') {
2597 ({
2598 dir
2599 } = app);
2600
2601 if (app.dir === '__legacy__project_root__') {
2602 dir = undefined;
2603 }
2604 }
2605
2606 const hosting = (typeof app.hosting === 'undefined' ? [] : Array.isArray(app.hosting) ? app.hosting : [app.hosting]).map(h => {
2607 if (!isObject$1(h)) {
2608 throw new Error(`The hosting of ${name} should be an object or an array of objects.`);
2609 }
2610
2611 if (h.type !== 'platform' && h.type !== 'heroku') {
2612 throw new Error(`Hosting of "${name}" has an unknown type. Only "platform" and "heroku" are currently allowed.`);
2613 }
2614
2615 if (typeof h.id !== 'string') {
2616 throw new Error(`Hosting "${h.type}" of "${name}" does not have an id provided.`);
2617 }
2618
2619 return {
2620 type: h.type,
2621 id: h.id
2622 };
2623 });
2624 const path = getPathFromDir(dir);
2625 return {
2626 name,
2627 type,
2628 dir,
2629 path,
2630 disableLinting: !!app.disableLinting,
2631 hosting
2632 };
2633 }) : [];
2634
2635 if (typeof burstConfig.apps !== 'undefined' && !apps.length) {
2636 throw new Error("The 'apps' property in the burst.yaml should be an object with one or more keys.");
2637 }
2638
2639 const usesProjectCiTemplate = Array.isArray(gitlabConfig.include) && gitlabConfig.include.some(i => isObject$1(i) && i.project === 'burstdigital/utils/burst-devtools' && i.file === '/ci-templates/project.yml');
2640 const vars = isObject$1(gitlabConfig.variables) ? gitlabConfig.variables : {};
2641 return {
2642 apps,
2643 usesProjectCiTemplate,
2644 deployEnabled: variableFlag(vars, 'BURST_DEPLOY', true),
2645 lintEnabled: variableFlag(vars, 'BURST_LINT', usesProjectCiTemplate),
2646 lintStylesEnabled: variableFlag(vars, 'BURST_LINT_STYLES', usesProjectCiTemplate),
2647 lintPhpEnabled: variableFlag(vars, 'BURST_LINT_PHP', usesProjectCiTemplate)
2648 };
2649}
2650
2651function variableFlag(variables, variableName, fallback) {
2652 const variable = variables[variableName];
2653
2654 if (typeof process.env[variableName] !== 'undefined' && process.env[variableName] !== variable) {
2655 throw new Error(`It looks like there exists an environment variable with the name of ${variableName}. You should not set this environment variable yourself. It should only be present in the 'variables' section in the .gitlab-ci.yml file. This way, the configuration is consistent for everyone. The .gitlab-ci.yml file is also read when using the Burst CLI locally.`);
2656 }
2657
2658 if (typeof variable === 'undefined') return fallback;
2659 if (variable === 'disable') return false;
2660 if (variable === 'enable') return true;
2661 throw new Error(`The variable ${variableName} defined in .gitlab-ci.yml should be 'enable' or 'disable'. ` + `If you remove the variable, it will default to '${fallback ? 'enable' : 'disable'}'.`);
2662}
2663
2664function isAppType(something) {
2665 return typeof something === 'string' && appTypes.includes(something);
2666}
2667
2668// CONVERT_TO_STRING: true -> String#at
2669// CONVERT_TO_STRING: false -> String#codePointAt
2670var stringAt = function (that, pos, CONVERT_TO_STRING) {
2671 var S = String(requireObjectCoercible(that));
2672 var position = toInteger(pos);
2673 var size = S.length;
2674 var first, second;
2675 if (position < 0 || position >= size) return CONVERT_TO_STRING ? '' : undefined;
2676 first = S.charCodeAt(position);
2677 return first < 0xD800 || first > 0xDBFF || position + 1 === size
2678 || (second = S.charCodeAt(position + 1)) < 0xDC00 || second > 0xDFFF
2679 ? CONVERT_TO_STRING ? S.charAt(position) : first
2680 : CONVERT_TO_STRING ? S.slice(position, position + 2) : (first - 0xD800 << 10) + (second - 0xDC00) + 0x10000;
2681};
2682
2683// `AdvanceStringIndex` abstract operation
2684// https://tc39.github.io/ecma262/#sec-advancestringindex
2685var advanceStringIndex = function (S, index, unicode) {
2686 return index + (unicode ? stringAt(S, index, true).length : 1);
2687};
2688
2689// `RegExp.prototype.flags` getter implementation
2690// https://tc39.github.io/ecma262/#sec-get-regexp.prototype.flags
2691var regexpFlags = function () {
2692 var that = anObject(this);
2693 var result = '';
2694 if (that.global) result += 'g';
2695 if (that.ignoreCase) result += 'i';
2696 if (that.multiline) result += 'm';
2697 if (that.unicode) result += 'u';
2698 if (that.sticky) result += 'y';
2699 return result;
2700};
2701
2702var nativeExec = RegExp.prototype.exec;
2703// This always refers to the native implementation, because the
2704// String#replace polyfill uses ./fix-regexp-well-known-symbol-logic.js,
2705// which loads this file before patching the method.
2706var nativeReplace = String.prototype.replace;
2707
2708var patchedExec = nativeExec;
2709
2710var UPDATES_LAST_INDEX_WRONG = (function () {
2711 var re1 = /a/;
2712 var re2 = /b*/g;
2713 nativeExec.call(re1, 'a');
2714 nativeExec.call(re2, 'a');
2715 return re1.lastIndex !== 0 || re2.lastIndex !== 0;
2716})();
2717
2718// nonparticipating capturing group, copied from es5-shim's String#split patch.
2719var NPCG_INCLUDED = /()??/.exec('')[1] !== undefined;
2720
2721var PATCH = UPDATES_LAST_INDEX_WRONG || NPCG_INCLUDED;
2722
2723if (PATCH) {
2724 patchedExec = function exec(str) {
2725 var re = this;
2726 var lastIndex, reCopy, match, i;
2727
2728 if (NPCG_INCLUDED) {
2729 reCopy = new RegExp('^' + re.source + '$(?!\\s)', regexpFlags.call(re));
2730 }
2731 if (UPDATES_LAST_INDEX_WRONG) lastIndex = re.lastIndex;
2732
2733 match = nativeExec.call(re, str);
2734
2735 if (UPDATES_LAST_INDEX_WRONG && match) {
2736 re.lastIndex = re.global ? match.index + match[0].length : lastIndex;
2737 }
2738 if (NPCG_INCLUDED && match && match.length > 1) {
2739 // Fix browsers whose `exec` methods don't consistently return `undefined`
2740 // for NPCG, like IE8. NOTE: This doesn' work for /(.?)?/
2741 nativeReplace.call(match[0], reCopy, function () {
2742 for (i = 1; i < arguments.length - 2; i++) {
2743 if (arguments[i] === undefined) match[i] = undefined;
2744 }
2745 });
2746 }
2747
2748 return match;
2749 };
2750}
2751
2752var regexpExec = patchedExec;
2753
2754// `RegExpExec` abstract operation
2755// https://tc39.github.io/ecma262/#sec-regexpexec
2756var regexpExecAbstract = function (R, S) {
2757 var exec = R.exec;
2758 if (typeof exec === 'function') {
2759 var result = exec.call(R, S);
2760 if (typeof result !== 'object') {
2761 throw TypeError('RegExp exec method returned something other than an Object or null');
2762 }
2763 return result;
2764 }
2765
2766 if (classofRaw(R) !== 'RegExp') {
2767 throw TypeError('RegExp#exec called on incompatible receiver');
2768 }
2769
2770 return regexpExec.call(R, S);
2771};
2772
2773var SPECIES$3 = wellKnownSymbol('species');
2774
2775var REPLACE_SUPPORTS_NAMED_GROUPS = !fails(function () {
2776 // #replace needs built-in support for named groups.
2777 // #match works fine because it just return the exec results, even if it has
2778 // a "grops" property.
2779 var re = /./;
2780 re.exec = function () {
2781 var result = [];
2782 result.groups = { a: '7' };
2783 return result;
2784 };
2785 return ''.replace(re, '$<a>') !== '7';
2786});
2787
2788// Chrome 51 has a buggy "split" implementation when RegExp#exec !== nativeExec
2789// Weex JS has frozen built-in prototypes, so use try / catch wrapper
2790var SPLIT_WORKS_WITH_OVERWRITTEN_EXEC = !fails(function () {
2791 var re = /(?:)/;
2792 var originalExec = re.exec;
2793 re.exec = function () { return originalExec.apply(this, arguments); };
2794 var result = 'ab'.split(re);
2795 return result.length !== 2 || result[0] !== 'a' || result[1] !== 'b';
2796});
2797
2798var fixRegexpWellKnownSymbolLogic = function (KEY, length, exec, sham) {
2799 var SYMBOL = wellKnownSymbol(KEY);
2800
2801 var DELEGATES_TO_SYMBOL = !fails(function () {
2802 // String methods call symbol-named RegEp methods
2803 var O = {};
2804 O[SYMBOL] = function () { return 7; };
2805 return ''[KEY](O) != 7;
2806 });
2807
2808 var DELEGATES_TO_EXEC = DELEGATES_TO_SYMBOL && !fails(function () {
2809 // Symbol-named RegExp methods call .exec
2810 var execCalled = false;
2811 var re = /a/;
2812 re.exec = function () { execCalled = true; return null; };
2813
2814 if (KEY === 'split') {
2815 // RegExp[@@split] doesn't call the regex's exec method, but first creates
2816 // a new one. We need to return the patched regex when creating the new one.
2817 re.constructor = {};
2818 re.constructor[SPECIES$3] = function () { return re; };
2819 }
2820
2821 re[SYMBOL]('');
2822 return !execCalled;
2823 });
2824
2825 if (
2826 !DELEGATES_TO_SYMBOL ||
2827 !DELEGATES_TO_EXEC ||
2828 (KEY === 'replace' && !REPLACE_SUPPORTS_NAMED_GROUPS) ||
2829 (KEY === 'split' && !SPLIT_WORKS_WITH_OVERWRITTEN_EXEC)
2830 ) {
2831 var nativeRegExpMethod = /./[SYMBOL];
2832 var methods = exec(SYMBOL, ''[KEY], function (nativeMethod, regexp, str, arg2, forceStringMethod) {
2833 if (regexp.exec === regexpExec) {
2834 if (DELEGATES_TO_SYMBOL && !forceStringMethod) {
2835 // The native String method already delegates to @@method (this
2836 // polyfilled function), leasing to infinite recursion.
2837 // We avoid it by directly calling the native @@method method.
2838 return { done: true, value: nativeRegExpMethod.call(regexp, str, arg2) };
2839 }
2840 return { done: true, value: nativeMethod.call(str, regexp, arg2) };
2841 }
2842 return { done: false };
2843 });
2844 var stringMethod = methods[0];
2845 var regexMethod = methods[1];
2846
2847 redefine(String.prototype, KEY, stringMethod);
2848 redefine(RegExp.prototype, SYMBOL, length == 2
2849 // 21.2.5.8 RegExp.prototype[@@replace](string, replaceValue)
2850 // 21.2.5.11 RegExp.prototype[@@split](string, limit)
2851 ? function (string, arg) { return regexMethod.call(string, this, arg); }
2852 // 21.2.5.6 RegExp.prototype[@@match](string)
2853 // 21.2.5.9 RegExp.prototype[@@search](string)
2854 : function (string) { return regexMethod.call(string, this); }
2855 );
2856 if (sham) hide(RegExp.prototype[SYMBOL], 'sham', true);
2857 }
2858};
2859
2860var max$1 = Math.max;
2861var min$2 = Math.min;
2862var floor$1 = Math.floor;
2863var SUBSTITUTION_SYMBOLS = /\$([$&`']|\d\d?|<[^>]*>)/g;
2864var SUBSTITUTION_SYMBOLS_NO_NAMED = /\$([$&`']|\d\d?)/g;
2865
2866var maybeToString = function (it) {
2867 return it === undefined ? it : String(it);
2868};
2869
2870// @@replace logic
2871fixRegexpWellKnownSymbolLogic(
2872 'replace',
2873 2,
2874 function (REPLACE, nativeReplace, maybeCallNative) {
2875 return [
2876 // `String.prototype.replace` method
2877 // https://tc39.github.io/ecma262/#sec-string.prototype.replace
2878 function replace(searchValue, replaceValue) {
2879 var O = requireObjectCoercible(this);
2880 var replacer = searchValue == undefined ? undefined : searchValue[REPLACE];
2881 return replacer !== undefined
2882 ? replacer.call(searchValue, O, replaceValue)
2883 : nativeReplace.call(String(O), searchValue, replaceValue);
2884 },
2885 // `RegExp.prototype[@@replace]` method
2886 // https://tc39.github.io/ecma262/#sec-regexp.prototype-@@replace
2887 function (regexp, replaceValue) {
2888 var res = maybeCallNative(nativeReplace, regexp, this, replaceValue);
2889 if (res.done) return res.value;
2890
2891 var rx = anObject(regexp);
2892 var S = String(this);
2893
2894 var functionalReplace = typeof replaceValue === 'function';
2895 if (!functionalReplace) replaceValue = String(replaceValue);
2896
2897 var global = rx.global;
2898 if (global) {
2899 var fullUnicode = rx.unicode;
2900 rx.lastIndex = 0;
2901 }
2902 var results = [];
2903 while (true) {
2904 var result = regexpExecAbstract(rx, S);
2905 if (result === null) break;
2906
2907 results.push(result);
2908 if (!global) break;
2909
2910 var matchStr = String(result[0]);
2911 if (matchStr === '') rx.lastIndex = advanceStringIndex(S, toLength(rx.lastIndex), fullUnicode);
2912 }
2913
2914 var accumulatedResult = '';
2915 var nextSourcePosition = 0;
2916 for (var i = 0; i < results.length; i++) {
2917 result = results[i];
2918
2919 var matched = String(result[0]);
2920 var position = max$1(min$2(toInteger(result.index), S.length), 0);
2921 var captures = [];
2922 // NOTE: This is equivalent to
2923 // captures = result.slice(1).map(maybeToString)
2924 // but for some reason `nativeSlice.call(result, 1, result.length)` (called in
2925 // the slice polyfill when slicing native arrays) "doesn't work" in safari 9 and
2926 // causes a crash (https://pastebin.com/N21QzeQA) when trying to debug it.
2927 for (var j = 1; j < result.length; j++) captures.push(maybeToString(result[j]));
2928 var namedCaptures = result.groups;
2929 if (functionalReplace) {
2930 var replacerArgs = [matched].concat(captures, position, S);
2931 if (namedCaptures !== undefined) replacerArgs.push(namedCaptures);
2932 var replacement = String(replaceValue.apply(undefined, replacerArgs));
2933 } else {
2934 replacement = getSubstitution(matched, S, position, captures, namedCaptures, replaceValue);
2935 }
2936 if (position >= nextSourcePosition) {
2937 accumulatedResult += S.slice(nextSourcePosition, position) + replacement;
2938 nextSourcePosition = position + matched.length;
2939 }
2940 }
2941 return accumulatedResult + S.slice(nextSourcePosition);
2942 }
2943 ];
2944
2945 // https://tc39.github.io/ecma262/#sec-getsubstitution
2946 function getSubstitution(matched, str, position, captures, namedCaptures, replacement) {
2947 var tailPos = position + matched.length;
2948 var m = captures.length;
2949 var symbols = SUBSTITUTION_SYMBOLS_NO_NAMED;
2950 if (namedCaptures !== undefined) {
2951 namedCaptures = toObject(namedCaptures);
2952 symbols = SUBSTITUTION_SYMBOLS;
2953 }
2954 return nativeReplace.call(replacement, symbols, function (match, ch) {
2955 var capture;
2956 switch (ch.charAt(0)) {
2957 case '$': return '$';
2958 case '&': return matched;
2959 case '`': return str.slice(0, position);
2960 case "'": return str.slice(tailPos);
2961 case '<':
2962 capture = namedCaptures[ch.slice(1, -1)];
2963 break;
2964 default: // \d\d?
2965 var n = +ch;
2966 if (n === 0) return match;
2967 if (n > m) {
2968 var f = floor$1(n / 10);
2969 if (f === 0) return match;
2970 if (f <= m) return captures[f - 1] === undefined ? ch.charAt(1) : captures[f - 1] + ch.charAt(1);
2971 return match;
2972 }
2973 capture = captures[n - 1];
2974 }
2975 return capture === undefined ? '' : capture;
2976 });
2977 }
2978 }
2979);
2980
2981class HostingProvider {
2982 constructor(config) {
2983 this.config = config;
2984 }
2985
2986 /**
2987 * The number of deploy target levels this hosting provider supports. For example,
2988 * Platform.sh supports 2 special ones: 'Production', 'Staging'.
2989 *
2990 * Heroku only has one environment per app, so there it's only 1.
2991 */
2992 static getAvailableDeployTargetLevels() {
2993 return 1;
2994 }
2995
2996}
2997class HostingProviderEnvironment {
2998 /**
2999 * The deploy target level for this application. Should be set using the
3000 * 'deployTargetLevels' option. This should never be the same or higher then the passed
3001 * option.
3002 *
3003 * The lower the number, the more important the deploy target is.
3004 */
3005 getDeployTarget() {
3006 return DeployTarget.Other;
3007 }
3008
3009 isSuggested() {
3010 return false;
3011 }
3012
3013 isActive() {
3014 return false;
3015 }
3016
3017}
3018
3019const PlatformClient = require('platformsh-client').default;
3020
3021class Platform extends HostingProvider {
3022 constructor(...args) {
3023 super(...args);
3024
3025 _defineProperty(this, "name", 'platform');
3026
3027 _defineProperty(this, "isEnterpriseProject", false);
3028
3029 _defineProperty(this, "platformProject", null);
3030 }
3031
3032 isSameAs(config) {
3033 return config.id === this.config.id;
3034 }
3035
3036 getDisplayName() {
3037 if (this.platformProject) return this.platformProject.title;
3038 return this.config.id;
3039 }
3040
3041 getLink() {
3042 return `https://console.platform.sh/burst/${encodeURIComponent(this.config.id)}`;
3043 }
3044
3045 static getAvailableDeployTargetLevels() {
3046 return 3;
3047 }
3048
3049 static async getClient() {
3050 if (this.client) return this.client;
3051
3052 if (process.env.PLATFORMSH_CLI_TOKEN) {
3053 this.client = new PlatformClient({
3054 api_token: process.env.PLATFORMSH_CLI_TOKEN
3055 });
3056 } else {
3057 this.client = new PlatformClient({
3058 access_token: await getPlatformToken()
3059 });
3060 }
3061
3062 return this.client;
3063 }
3064
3065 async getPlatformProject() {
3066 if (this.platformProject) return this.platformProject;
3067 const platformClient = await Platform.getClient();
3068 this.platformProject = await platformClient.getProject(this.config.id);
3069 return this.platformProject;
3070 }
3071
3072 async getPossibleEnvs(config) {
3073 const spinner = ora().start(`Getting platform environments for project ${this.config.id}.`);
3074 const platformProject = await this.getPlatformProject();
3075 const platformEnvs = await platformProject.getEnvironments();
3076 this.isEnterpriseProject = platformEnvs.some(e => e.id === 'production' && e.deployment_target === 'enterprise');
3077 spinner.stop();
3078 const instances = [];
3079 instances.push(...platformEnvs.map( // eslint-disable-next-line no-use-before-define
3080 e => new PlatformEnvironment(this, e, config, instances)));
3081
3082 if (!instances.find(i => i.isSuggested())) {
3083 instances.push( // eslint-disable-next-line no-use-before-define
3084 new PlatformEnvironment(this, {
3085 new: true
3086 }, config, instances));
3087 }
3088
3089 return instances;
3090 }
3091
3092 async getGitUrl() {
3093 return (await this.getPlatformProject()).getGitUrl();
3094 }
3095
3096}
3097
3098_defineProperty(Platform, "client", void 0);
3099
3100class PlatformEnvironment extends HostingProviderEnvironment {
3101 constructor(project, model, config, environments) {
3102 super();
3103 this.project = project;
3104 this.config = config;
3105 this.environments = environments;
3106
3107 _defineProperty(this, "model", void 0);
3108
3109 if (model.new) {
3110 const target = Object.entries(this.branchNamesWithTargets()).find(([, t]) => t === config.suggestedTarget);
3111 const id = target ? target[0] : config.suggestedName;
3112
3113 if (!id) {
3114 throw new Error(`Not a valid config was passed. Either pass a 'suggestedTarget' or ` + `'suggestedName'.\n Passed now: \n${JSON.stringify(config)}`);
3115 }
3116
3117 this.model = _objectSpread({}, model, {
3118 id
3119 });
3120 } else {
3121 this.model = model;
3122 }
3123 }
3124
3125 getDisplayName() {
3126 const {
3127 id
3128 } = this.model;
3129
3130 if (this.project.isEnterpriseProject) {
3131 if (id === 'production') return 'Production (enterprise)';
3132 if (id === 'staging') return 'Staging (enterprise)';
3133 if (id === 'master') return 'Mirror';
3134 }
3135
3136 if (id === 'master') return 'Production';
3137 if (id === 'staging') return 'Staging (will be deleted in the future)';
3138 if (id === 'mirror') return 'Mirror';
3139 if (this.hasOptedOutResync()) return `${id} [keep data]`;
3140 if (this.hasOptedOutDeactvation()) return `${id} [keep]`;
3141 return id;
3142 }
3143
3144 branchNamesWithTargets() {
3145 if (this.project.isEnterpriseProject) {
3146 return {
3147 production: DeployTarget.Production,
3148 staging: DeployTarget.Staging,
3149 master: DeployTarget.Staging
3150 };
3151 }
3152
3153 return {
3154 master: DeployTarget.Production,
3155 staging: DeployTarget.Staging,
3156 mirror: DeployTarget.Staging
3157 };
3158 }
3159
3160 getDeployTarget() {
3161 const {
3162 id
3163 } = this.model;
3164
3165 if (this.branchNamesWithTargets()[id]) {
3166 return this.branchNamesWithTargets()[id];
3167 }
3168
3169 return DeployTarget.Dynamic;
3170 }
3171
3172 isSuggested() {
3173 return this.config.suggestedTarget === this.getDeployTarget() || this.config.suggestedName === this.model.id || // We also check if there is a slugified version, because previously we
3174 // used the branch slug from the Gitlab CI env variables instead of the
3175 // real branch name. This way we can still deploy to the 'old' name.
3176 !!this.config.suggestedName && slugify(this.config.suggestedName).replace(/-+/g, '') === slugify(this.model.id).replace(/-+/g, '');
3177 }
3178
3179 isActive() {
3180 if (this.model.new) return false; // There is a bug in the Platform.sh client, that marks 'dirty' environments
3181 // as inactive. An environment is dirty when someting is happening on that
3182 // env (deploy, backup, activation, deactivation). Most of the time when an
3183 // env is dirty, it's active. Only if there is an #activate _link available,
3184 // it's not.
3185
3186 if (this.model.is_dirty) {
3187 return !this.model.hasLink('#activate');
3188 }
3189
3190 return this.model.isActive();
3191 }
3192
3193 hasOptedOutDeactvation() {
3194 return this.hasOptedOutResync() || !this.model.new && this.model.title.endsWith('[keep]');
3195 }
3196
3197 hasOptedOutResync() {
3198 return !this.model.new && this.model.title.endsWith('[keep data]');
3199 }
3200
3201 canBeResyncedOrDeactivated() {
3202 return !this.model.new && !['master', 'production', 'mirror'].includes(this.model.id) && !(this.project.isEnterpriseProject && this.model.id === 'staging') && this.isActive();
3203 }
3204
3205 async deploy({
3206 deployOnlySubdirectory
3207 }) {
3208 if (!this.project.platformProject) {
3209 throw Error('Not possible.');
3210 }
3211
3212 const newParent = this.project.isEnterpriseProject || this.getDeployTarget() !== DeployTarget.Dynamic ? 'master' : 'mirror';
3213 let resync = false;
3214
3215 if (this.canBeResyncedOrDeactivated() && !this.hasOptedOutResync() && !process.env.CI) {
3216 ({
3217 resync
3218 } = await inquirer.prompt([{
3219 type: 'confirm',
3220 name: 'resync',
3221 message: `💣 Do you want to use fresh data (and remove the database on this environment)?`
3222 }]));
3223 }
3224
3225 if (this.canBeResyncedOrDeactivated() && !this.hasOptedOutResync() && !resync) {
3226 console.log('\n\n💣');
3227 console.log('💣 WARNING');
3228 console.log('💣');
3229 console.log('💣 In the future, a deploy will automatically use fresh data.');
3230 console.log('💣 This means that the database will be removed.');
3231 console.log('💣');
3232 console.log(`💣 If you want to opt out, add ${chalk.cyan('[keep data]')} to the name of the environment.`);
3233 console.log('💣\n\n');
3234 }
3235
3236 console.log(`\n\n${chalk.bgYellow.black(' DEPLOY START ')} Deploying to Platform.sh project ${this.project.getDisplayName()} branch ${this.model.id}\n\n`);
3237
3238 try {
3239 // If we want to resync, we first deactivate the environment.
3240 if (resync && !this.model.new) {
3241 console.log('Creating a backup (just to be sure)...');
3242
3243 try {
3244 await this.model.backup();
3245 } catch (e) {
3246 ({
3247 resync
3248 } = await inquirer.prompt([{
3249 type: 'confirm',
3250 name: 'resync',
3251 message: `💣 Creating a backup isn't possible at the moment. Continue?`
3252 }]));
3253 }
3254 }
3255
3256 if (resync && !this.model.new) {
3257 console.log('De-activating environment...');
3258 await this.model.runLongOperation('deactivate', 'POST', undefined);
3259 await this.model.refresh();
3260 } // If the environment doesn't exist yet, we first need to push. This creates an inactive environment.
3261
3262
3263 let isPushed = false;
3264
3265 if (this.model.new) {
3266 console.log('Creating new environment by pushing...');
3267 await this.push(deployOnlySubdirectory);
3268 isPushed = true;
3269 this.model = await this.project.platformProject.getEnvironment(encodeURIComponent(this.model.id));
3270 } // We make sure the title and parent are as expected.
3271 // If they aren't currently, we set them before deploying.
3272
3273
3274 let needsSave = false;
3275 const {
3276 title
3277 } = this.model;
3278 const newTitle = this.getDisplayName();
3279
3280 if (title !== newTitle) {
3281 console.log(`The environment title is currently ${chalk.red(title)}. That will be changed to ${chalk.cyan(newTitle)}.`);
3282 this.model.title = newTitle;
3283 needsSave = true;
3284 }
3285
3286 if (this.getDeployTarget() === DeployTarget.Dynamic) {
3287 if (this.model.parent !== newParent) {
3288 console.log(`The parent of the environment was ${chalk.red(this.model.parent)}. That will be changed to ${chalk.cyan(newParent)}.`);
3289 this.model.parent = newParent;
3290 needsSave = true;
3291 } // Check if the needed parent actually exists. If not, we should create it.
3292 // We do this by branching from the master. If it does exist but it's
3293 // inactive, we activate it.
3294
3295
3296 const p = this.environments.find(e => e.model.id === newParent);
3297
3298 if (!p) {
3299 const m = this.environments.find(e => e.model.id === 'master');
3300 if (!m || m.model.new) throw new Error("The master envronment doesn't exist.");
3301 console.log('Creating parent environment...');
3302 await this.catchTooManyEnvironments(() => {
3303 if (m.model.new) throw new Error('Not possible.');
3304 return m.model.branch('Mirror', newParent);
3305 });
3306 } else if (!p.isActive()) {
3307 console.log('Activating parent environment...');
3308 if (p.model.new) throw new Error('Not possible.');
3309 await this.activateSafely(p.model);
3310 }
3311 }
3312
3313 if (needsSave) {
3314 await this.model.update(this.model.data);
3315 console.log('Updated environment information.');
3316 } // We push the code to Platform now. Except when we did that to create an inactive
3317 // environment.
3318
3319
3320 if (!isPushed) {
3321 await this.push(deployOnlySubdirectory);
3322 } // We use our own isActive instead of Platform.sh's one, because the
3323 // Platform.sh one is buggy.
3324
3325
3326 if (!this.isActive()) {
3327 await this.activateSafely(this.model);
3328 console.log('\n\nThe environment is being activated.');
3329 console.log('Follow the progress here: ');
3330 console.log(`${this.project.getLink()}/${encodeURIComponent(this.model.id)}`);
3331 }
3332
3333 console.log(`\n\n${chalk.bgGreen.black(' DEPLOY DONE ')} Deploy successfully completed.\n\n`);
3334 } catch (e) {
3335 console.error(chalk.bgRed(' DEPLOY FAILED '));
3336 throw e;
3337 }
3338 }
3339
3340 async push(dir) {
3341 return push((await this.project.getGitUrl()), this.model.id, {
3342 dir
3343 });
3344 }
3345
3346 getUrls() {
3347 if (this.model.new) return [];
3348 const urls = this.model.getRouteUrls();
3349 return urls.filter(u => !u.startsWith('http://'));
3350 }
3351
3352 async activateSafely(model, retry = 0) {
3353 await this.catchTooManyEnvironments(async () => {
3354 try {
3355 await model.runLongOperation('activate', 'POST', undefined);
3356 } catch (error) {
3357 // Sometimes, Platform.sh introduces a bug where the environment will appear
3358 // activated while it's not. This happens when you try to activate an
3359 // environment, but an error returns. The environment is then not really
3360 // activated, but it does show up in Platform.sh as activated. In this case, it
3361 // needs to be de-activated and activated again. See also issue #65.
3362 if (error.message !== 'Access was denied to this resource.' && retry < 5) {
3363 throw error;
3364 }
3365
3366 console.log("Platform.sh acts like this environment was already activated, but it isn't. This is a bug in Platform.sh.");
3367 console.log('De-activating to recover from bug...');
3368 await model.refresh();
3369 await model.runLongOperation('deactivate', 'POST', undefined);
3370 console.log('Activating again...');
3371 await model.refresh();
3372 await this.activateSafely(model, retry + 1);
3373 }
3374 });
3375 }
3376
3377 async catchTooManyEnvironments(action) {
3378 try {
3379 return await action();
3380 } catch (error) {
3381 if (error.message !== 'This action would raise the count of environments over its limit.') {
3382 throw error;
3383 }
3384
3385 console.log(chalk.red('\n\nThere are not enough environments available.\n\n'));
3386 const envsThatCanBeDeleted = this.environments.filter(env => env.canBeResyncedOrDeactivated() && !env.hasOptedOutDeactvation());
3387
3388 if (!envsThatCanBeDeleted.length) {
3389 throw new Error('There are no environments that can be deactivated. Please upgrade the number of available environments.');
3390 }
3391
3392 if (process.env.CI) {
3393 throw new Error('Use the Burst CLI locally to choose an environment to remove.');
3394 }
3395
3396 const {
3397 envToDeactivate
3398 } = await inquirer.prompt([{
3399 type: 'list',
3400 name: 'envToDeactivate',
3401 message: '💣 What environment do you want to deactivate? (we will create a backup before deactivation, just to be sure)',
3402 choices: envsThatCanBeDeleted.map(env => ({
3403 name: env.getDisplayName(),
3404 value: env
3405 }))
3406 }]);
3407 if (envToDeactivate.model.new) throw new Error('Not possible');
3408 await envToDeactivate.model.backup();
3409 await envToDeactivate.model.deactivate(); // Make sure that if there is a next round of deactivations, that it can't be
3410 // selected again.
3411
3412 await envToDeactivate.model.refresh();
3413 return this.catchTooManyEnvironments(() => action());
3414 }
3415 }
3416
3417}
3418
3419async function getPlatformToken() {
3420 const {
3421 stdout: res
3422 } = await execa('platform', ['auth:token'], {
3423 preferLocal: false
3424 });
3425
3426 if (res.length === 0) {
3427 throw new Error("The Platform access_token token can't be fetched from the Platform CLI.");
3428 }
3429
3430 return res;
3431}
3432
3433class Heroku extends HostingProvider {
3434 constructor(config) {
3435 super(config);
3436
3437 if (typeof config.id !== 'string') {
3438 throw new Error('Hosting config not okay.');
3439 }
3440 }
3441
3442 getDisplayName() {
3443 return this.config.id;
3444 }
3445
3446 getLink() {
3447 return '';
3448 }
3449
3450 isSameAs(config) {
3451 return config.id === this.config.id;
3452 }
3453
3454 async getPossibleEnvs() {
3455 // eslint-disable-next-line no-use-before-define
3456 return [new HerokuApp(this)];
3457 }
3458
3459}
3460class HerokuApp extends HostingProviderEnvironment {
3461 constructor(hostingProvider) {
3462 super();
3463 this.hostingProvider = hostingProvider;
3464 }
3465
3466 getDisplayName() {
3467 return this.hostingProvider.getDisplayName();
3468 }
3469
3470 async deploy() {
3471 throw new Error('Not possible to deploy a Heroku application yet.');
3472 }
3473
3474 getUrls() {
3475 return [];
3476 }
3477
3478}
3479
3480const hostingProviders = {
3481 platform: Platform,
3482 heroku: Heroku
3483};
3484
3485let DeployTarget;
3486
3487(function (DeployTarget) {
3488 DeployTarget["Production"] = "production";
3489 DeployTarget["Staging"] = "staging";
3490 DeployTarget["Dynamic"] = "dynamic";
3491 DeployTarget["Other"] = "other";
3492})(DeployTarget || (DeployTarget = {}));
3493
3494function isFile(path) {
3495 try {
3496 return fs.statSync(path).isFile();
3497 } catch (_unused) {
3498 return false;
3499 }
3500}
3501
3502const burstYamlPath = `${repoRoot}/burst.yaml`;
3503const gitlabYamlPath = `${repoRoot}/.gitlab-ci.yml`;
3504const projectConfig = getProjectConfiguration(isFile(burstYamlPath) ? fs.readFileSync(burstYamlPath, 'utf8') : null, isFile(gitlabYamlPath) ? fs.readFileSync(gitlabYamlPath, 'utf8') : null, dir => {
3505 const path = dir ? `${repoRoot}/${dir}` : repoRoot;
3506
3507 try {
3508 const isDir = fs.statSync(path).isDirectory();
3509
3510 if (!isDir) {
3511 throw new Error(`The location ${path} was found, but it's not a directory.`);
3512 }
3513
3514 return path;
3515 } catch (e) {
3516 console.log();
3517 console.log();
3518 console.log(chalk.red("Your burst.yaml file references a path that doesn't exist:"));
3519 console.log(chalk.yellow(path));
3520 console.log();
3521 console.log();
3522 console.log(chalk.red('Please fix the burst.yaml file in the root.'));
3523 console.log();
3524 console.log();
3525 throw e;
3526 }
3527});
3528
3529class ProjectInfo {
3530 /**
3531 * This gets all different hosting options there are.
3532 *
3533 * Every hosting option can deploy one or more apps.
3534 * Every hosting option can have multiple deploy targets (production for
3535 * example). These deploy targets can be different per app.
3536 */
3537 async getHostingProvidersWithApps() {
3538 const hostingProvidersWithApps = [];
3539 projectConfig.apps.forEach(app => {
3540 app.hosting.forEach(hc => {
3541 const {
3542 type
3543 } = hc,
3544 hostingConfig = _objectWithoutProperties(hc, ["type"]); // Verify that there is a class for this hosting type.
3545
3546
3547 const ThisHostingProvider = hostingProviders[type];
3548
3549 if (!ThisHostingProvider) {
3550 throw new Error(`There is no hosting provider with the name '${type}' supported.`);
3551 } // Check if there is a hosting with the same type and id.
3552 // If there is, we just need to add the app.
3553
3554
3555 const existingHosting = hostingProvidersWithApps.find(h => h.hostingProvider instanceof ThisHostingProvider && h.hostingProvider.isSameAs(hostingConfig));
3556
3557 if (existingHosting) {
3558 existingHosting.apps.push(app);
3559 } else {
3560 hostingProvidersWithApps.push({
3561 hostingProvider: new ThisHostingProvider(hostingConfig),
3562 apps: [app]
3563 });
3564 }
3565 });
3566 });
3567 return hostingProvidersWithApps;
3568 }
3569 /**
3570 * This gets all hosting options, and groups them on the combination of apps.
3571 *
3572 * The apps will be the same for all hostings in a collection, but the deploy
3573 * type can be different per app.
3574 */
3575
3576
3577 async getHostingProvidersByAppCominations() {
3578 const hostings = await this.getHostingProvidersWithApps();
3579 const hostingsGrouped = lodash.groupBy(hostings, hosting => hosting.apps.map(a => a.name).sort().join('__'));
3580 return Object.values(hostingsGrouped).map(hostingsGroup => ({
3581 apps: hostingsGroup[0].apps,
3582 hostingProviders: hostingsGroup.map(hosting => hosting.hostingProvider)
3583 }));
3584 }
3585
3586}
3587
3588let projectInfo;
3589function getProjectInfo() {
3590 if (projectInfo) return projectInfo;
3591 projectInfo = new ProjectInfo();
3592 return projectInfo;
3593}
3594
3595const composerHelperDir = path$1__default.join(__dirname, '../composer-helper');
3596function usePHPCS(allFiles, fix) {
3597 const files = React.useMemo(() => allFiles.filter(f => // Keep this in sync with drupal_ruleset.xml.
3598 f.path.endsWith('.php') || f.path.endsWith('.module') || f.path.endsWith('.theme') || f.path.endsWith('.inc') || f.path.endsWith('.install')), [allFiles]);
3599 const composerInstalled = useComposerHelper(files.length > 0 && projectConfig.lintPhpEnabled);
3600 const fileChunksPerStandard = React.useMemo(() => {
3601 const filesPerStandard = lodash.groupBy(files, file => {
3602 if (file.app) {
3603 if (file.app.type === 'drupal') {
3604 return `${composerHelperDir}/drupal_ruleset.xml`;
3605 }
3606
3607 if (file.app.type === 'magento') {
3608 return `${composerHelperDir}/magento_ruleset.xml`;
3609 }
3610
3611 if (file.app.type === 'wordpress') {
3612 return `${composerHelperDir}/wordpress_ruleset.xml`;
3613 }
3614 }
3615
3616 return `${composerHelperDir}/other_ruleset.xml`;
3617 });
3618 return lodash.flatten(Object.entries(filesPerStandard).map(([standard, fs]) => lodash.chunk(fs, 20).map(fc => ({
3619 chunkFiles: fc,
3620 standard
3621 }))));
3622 }, [files]);
3623 const [results, setResults] = React.useState({});
3624 const [filesFixed, setFilesFixed] = React.useState(0);
3625 const [filesWithoutFixes, setFilesWithoutFixes] = React.useState(0);
3626 React.useEffect(() => {
3627 if (!composerInstalled) return;
3628 const queue = new PQueue({
3629 concurrency: 20
3630 });
3631 queue.addAll(fileChunksPerStandard.map(({
3632 chunkFiles,
3633 standard
3634 }) => async () => {
3635 const absolutePaths = chunkFiles.map(f => f.absolutePath); // The arguments we need to pass to the phpcs and phpcbf commands.
3636
3637 const args = [...chunkFiles.map(f => f.absolutePath), '-q', `--standard=${standard}`, ...(standard === `${composerHelperDir}/wordpress_ruleset.xml` ? ['--runtime-set', 'installed_paths', `${composerHelperDir}/vendor/wp-coding-standards/wpcs`] : [])]; // We first execute phpcs. This way we know how many errors there are.
3638
3639 const result = parsePhpcsResult((await execa(`${composerHelperDir}/vendor/bin/phpcs`, [...args, '--report=json'], {
3640 reject: false,
3641 preferLocal: false
3642 })).stdout, absolutePaths); // Sometimes, files aren't linted. We should still add them to the
3643 // result, so we won't wait forever for these files to be linted.
3644
3645 absolutePaths.forEach(f => {
3646 if (!result.files[f]) result.files[f] = {
3647 errors: 0,
3648 warnings: 0,
3649 messages: []
3650 };
3651 });
3652 setResults(r => _objectSpread({}, r, result.files)); // If there are auto-fixable errors or warnings, we can fix them.
3653
3654 if (fix) {
3655 if (result.totals.fixable > 0) {
3656 await execa(`${composerHelperDir}/vendor/bin/phpcbf`, args, {
3657 reject: false,
3658 preferLocal: false
3659 });
3660 setFilesFixed(f => f + chunkFiles.length);
3661 } else {
3662 setFilesWithoutFixes(f => f + chunkFiles.length);
3663 }
3664 }
3665 }));
3666 return () => queue.clear();
3667 }, [composerInstalled, fileChunksPerStandard, fix]); // If there are, create nice error objects.
3668
3669 const errors = lodash.flatten(Object.entries(results).map(([filename, r]) => r.messages.filter(message => fix ? message.type === 'ERROR' && !message.fixable : message.type === 'ERROR' || message.fixable).map(message => ({
3670 linter: 'PHPCS',
3671 filename,
3672 autoFixable: message.fixable,
3673 message: message.message,
3674 rule: message.source,
3675 sourceLocation: {
3676 start: {
3677 line: message.line,
3678 column: message.column
3679 }
3680 }
3681 }))));
3682
3683 if (composerInstalled === false) {
3684 errors.push({
3685 linter: 'PHPCS',
3686 filename: 'Composer dependencies',
3687 autoFixable: false,
3688 message: "The composer dependencies couldn't be installed. PHP files can't be linted."
3689 });
3690 }
3691
3692 const filesLinted = Object.keys(results).length;
3693 const done = !projectConfig.lintPhpEnabled || composerInstalled === false || filesLinted === files.length && (!fix || files.length - filesFixed - filesWithoutFixes === 0);
3694 return {
3695 errors,
3696 files,
3697 filesLinted,
3698 filesFixed,
3699 filesWithFixes: fix ? files.length - filesWithoutFixes : 0,
3700 done
3701 };
3702}
3703
3704function parsePhpcsResult(result, pathsLinted) {
3705 try {
3706 return JSON.parse(result);
3707 } catch (error) {
3708 const resultJson = {
3709 files: {},
3710 totals: {
3711 errors: pathsLinted.length,
3712 warnings: 0,
3713 fixable: 0
3714 }
3715 };
3716 pathsLinted.forEach(p => {
3717 resultJson.files[p] = {
3718 errors: 1,
3719 warnings: 0,
3720 messages: [{
3721 message: result,
3722 source: '',
3723 severity: 9999,
3724 fixable: false,
3725 type: 'ERROR',
3726 line: 0,
3727 column: 0
3728 }]
3729 };
3730 });
3731 return resultJson;
3732 }
3733}
3734
3735function useComposerHelper(install) {
3736 const [installCompleted, setInstallCompleted] = React.useState();
3737 React.useEffect(() => {
3738 if (!install) return;
3739 const composerInstall = execa('composer', ['install', '--no-interaction'], {
3740 cwd: composerHelperDir,
3741 reject: false,
3742 preferLocal: false
3743 });
3744 composerInstall.then(a => {
3745 if (a.killed) return;
3746 if (a.failed) setInstallCompleted(false);
3747 setInstallCompleted(true);
3748 });
3749 return () => composerInstall.kill();
3750 }, [install]);
3751 return installCompleted;
3752}
3753
3754const readFileAsync = util.promisify(fs.readFile);
3755const writeFileAsync = util.promisify(fs.writeFile);
3756function usePrettier(allFiles, fix) {
3757 const prettier = usePrettierWorker();
3758 const [filesInfo, setFilesInfo] = React.useState({});
3759 React.useEffect(() => {
3760 const queue = new PQueue({
3761 concurrency: 10
3762 });
3763 queue.addAll(allFiles.map(file => async () => {
3764 // We don't want to test Drupal configuration exports.
3765 if (/\/config\/[\w/]+\/[\w.-]+\.yml$/.test(file.absolutePath)) {
3766 setFilesInfo(i => _objectSpread({}, i, {
3767 [file.absolutePath]: {
3768 ignored: true,
3769 inferredParser: null
3770 }
3771 }));
3772 return;
3773 }
3774
3775 const fileInfo = await prettier.getFileInfo(file.absolutePath);
3776 setFilesInfo(i => _objectSpread({}, i, {
3777 [file.absolutePath]: fileInfo
3778 }));
3779 }));
3780 return () => queue.clear();
3781 }, [allFiles, prettier]);
3782 const filesChecked = Object.keys(filesInfo).length;
3783 const files = React.useMemo(() => Object.entries(filesInfo).filter(([, result]) => result.inferredParser).map(([filename, result]) => ({
3784 filename,
3785 inferredParser: result.inferredParser
3786 })), [filesInfo]);
3787 const [results, setResults] = React.useState({});
3788 const [errorResults, setErrorResults] = React.useState({});
3789 React.useEffect(() => {
3790 if (filesChecked < allFiles.length) return;
3791 const queue = new PQueue({
3792 concurrency: 10
3793 });
3794 queue.addAll(files.map(({
3795 filename,
3796 inferredParser
3797 }) => async () => {
3798 // Create the default prettier config.
3799 const filePrettierConfig = _objectSpread({}, prettierConfig$1, {
3800 parser: inferredParser
3801 }); // Some files have a special prettier config.
3802
3803
3804 if (filename.endsWith('composer.lock') || filename.endsWith('composer.json')) {
3805 filePrettierConfig.parser = 'json-stringify';
3806 filePrettierConfig.tabWidth = 4;
3807 }
3808
3809 try {
3810 // Get the contents of the file.
3811 const fileContents = await readFileAsync(filename, {
3812 encoding: 'utf8'
3813 }); // Format the files, so we can check if they are different.
3814
3815 const newFileContents = await prettier.format(fileContents, filePrettierConfig); // If the file contents didn't change, nothing was fixed.
3816
3817 const correct = fileContents === newFileContents; // If something was fixed, write the results back to disk.
3818
3819 if (fix && !correct) {
3820 await writeFileAsync(filename, newFileContents, {
3821 encoding: 'utf8'
3822 });
3823 }
3824
3825 setResults(r => _objectSpread({}, r, {
3826 [filename]: correct
3827 }));
3828 } catch (e) {
3829 setErrorResults(r => _objectSpread({}, r, {
3830 [filename]: e.message || e.toString()
3831 }));
3832 }
3833 }));
3834 return () => queue.clear();
3835 }, [allFiles.length, files, filesChecked, fix, prettier]);
3836 const filesToLint = Object.keys(files).length;
3837 const linted = Object.keys(results).length + Object.keys(errorResults).length;
3838 const filesNotCorrect = Object.entries(results).filter(([, correct]) => !correct).map(([file]) => file);
3839 const errors = [...(fix ? [] : filesNotCorrect.map(f => ({
3840 linter: 'Prettier',
3841 filename: f,
3842 autoFixable: true,
3843 message: 'Not according to Prettier styling.'
3844 }))), ...Object.entries(errorResults).map(([filename, error]) => ({
3845 linter: 'Prettier',
3846 filename,
3847 autoFixable: false,
3848 message: `Error while linting with Prettier: ${error}`
3849 }))];
3850 return {
3851 filesChecked,
3852 filesToLint,
3853 linted,
3854 done: allFiles.length === filesChecked && linted === filesToLint,
3855 errors,
3856 fixed: fix ? filesNotCorrect : [],
3857 filesNotCorrect
3858 };
3859}
3860
3861function useStylelint(allFiles, fix) {
3862 const [lintResults, setLintResults] = React.useState();
3863 const [fixResults, setFixResults] = React.useState();
3864 const filesLintable = React.useMemo(() => projectConfig.lintStylesEnabled ? allFiles.filter(({
3865 filename: f
3866 }) => !f.endsWith('.d.ts') && (f.endsWith('.js') || f.endsWith('.jsx') || f.endsWith('.ts') || f.endsWith('.tsx'))) : [], [allFiles]);
3867 const filesFixable = React.useMemo(() => projectConfig.lintStylesEnabled ? allFiles.filter(({
3868 filename: f
3869 }) => f.endsWith('.css') || f.endsWith('.sass') || f.endsWith('.scss') || f.endsWith('.less')) : [], [allFiles]);
3870 const filesForLintRun = React.useMemo(() => fix ? filesLintable : [...filesLintable, ...filesFixable], [filesFixable, filesLintable, fix]);
3871 const filesForFixRun = React.useMemo(() => fix ? filesFixable : [], [filesFixable, fix]);
3872 React.useEffect(() => {
3873 if (!filesForLintRun.length) return;
3874 stylelint.lint({
3875 configFile: require.resolve('@burst/stylelint-config'),
3876 files: filesForLintRun.map(f => f.absolutePath)
3877 }).then(r => setLintResults(r));
3878 }, [filesForLintRun]);
3879 React.useEffect(() => {
3880 if (!filesForFixRun.length) return;
3881 stylelint.lint({
3882 configFile: require.resolve('@burst/stylelint-config/pure'),
3883 files: filesForFixRun.map(f => f.absolutePath),
3884 fix: true
3885 }).then(() => // We need to lint a second time, because the autofixer disables
3886 // stylelint-disable comments. We only get the correct results if we
3887 // lint without fix: true.
3888 stylelint.lint({
3889 configFile: require.resolve('@burst/stylelint-config/pure'),
3890 files: filesForFixRun.map(f => f.absolutePath)
3891 })).then(r => setFixResults(r));
3892 }, [filesForFixRun]);
3893 const errors = [];
3894 [...(lintResults ? lintResults.results : []), ...(fixResults ? fixResults.results : [])].forEach(r => {
3895 errors.push(...[...r.parseErrors, ...r.warnings].map(e => ({
3896 linter: 'Stylelint',
3897 filename: r.source,
3898 autoFixable: false,
3899 message: e.text.replace(` (${e.line}:${e.column})`, '').replace(` (${e.rule})`, ''),
3900 rule: e.rule,
3901 sourceLocation: {
3902 start: {
3903 line: e.line,
3904 column: e.column
3905 }
3906 }
3907 })));
3908 });
3909 return {
3910 filesFixable,
3911 filesToLint: filesForFixRun.length + filesForLintRun.length,
3912 done: (!filesForLintRun.length || !!lintResults) && (!filesForFixRun.length || !!fixResults),
3913 errors
3914 };
3915}
3916
3917const lintingFailed = new Error('ERRORS');
3918class LintCommand extends Command {
3919 constructor(...args) {
3920 super(...args);
3921
3922 _defineProperty(this, "command", 'lint [files...]');
3923
3924 _defineProperty(this, "description", 'Lint files in the current git repository.');
3925
3926 _defineProperty(this, "options", [{
3927 flags: '-f, --fix',
3928 description: 'Fix linting errors automatically if possible.'
3929 }, {
3930 flags: '-v, --verbose',
3931 description: 'Show the source of every linting error.'
3932 }, {
3933 flags: '--summary',
3934 description: 'Show a list of errors and how many times they occur.'
3935 }, {
3936 flags: '--staged',
3937 description: 'Only lint staged files.'
3938 }]);
3939 }
3940
3941 async action(filesToSearch, {
3942 fix,
3943 verbose,
3944 summary,
3945 staged
3946 }) {
3947 if (!projectConfig.lintEnabled) {
3948 console.log(chalk.underline('\n\n\nThe Burst linter is not enabled for this project.\n'));
3949 console.log('Is this a new project, or are you trying to add the linter');
3950 console.log('to a project that is not yet lint-compatible? Then you can');
3951 console.log("use the Gitlab CI Template to enable the linter. If that's");
3952 console.log('not possible, you can add to the .gitlab-ci.yml:\n');
3953 console.log(chalk.grey('variables:'));
3954 console.log(chalk.grey(' BURST_LINT: enable\n'));
3955 console.log('But using the Gitlab CI Template is preferred.\n\n');
3956 console.log(chalk.bold.yellow(`If this is a project where linting was enabled before, you\nprobabily only have to ${chalk.underline('merge from master')}!`));
3957 console.log('\n\nIf you have any questions, please ask Bart.\n\n');
3958 process.exit(1);
3959 }
3960
3961 if (staged) {
3962 // eslint-disable-next-line global-require
3963 const lintStaged = require('lint-staged/src');
3964
3965 if (!filesToSearch.length) {
3966 process.chdir(repoRoot);
3967 }
3968
3969 lintStaged(console, `${__dirname}../../config/lint-staged.js`);
3970 return;
3971 }
3972
3973 const a = ink.render(React__default.createElement(Lint, {
3974 paths: filesToSearch,
3975 fix: !!fix,
3976 verbose: !!verbose,
3977 summary: !!summary,
3978 staged: !!staged
3979 }));
3980
3981 try {
3982 await a.waitUntilExit();
3983 } catch (e) {
3984 if (e.message !== 'ERRORS') throw e;
3985 process.exitCode = 1;
3986 } // @ts-ignore
3987
3988
3989 a.cleanup();
3990 }
3991
3992}
3993
3994function Lint(props) {
3995 const filePaths = useFilePaths(props.paths); // We want to exit with exit code 1 if there were no files found.
3996
3997 useExit(!!filePaths && filePaths.length === 0, lintingFailed);
3998
3999 if (!filePaths || !projectConfig.apps || !repoRoot) {
4000 return React__default.createElement(ink.Text, null, "Listing all files in this repository...");
4001 }
4002
4003 if (filePaths.length === 0) {
4004 return React__default.createElement(ink.Text, null, "We found no files.");
4005 }
4006
4007 const files = filePaths.map(path => ({
4008 path,
4009 absolutePath: `${repoRoot}/${path}`,
4010 filename: path$1.basename(path),
4011 app: projectConfig.apps.find(a => !!a.dir && path.startsWith(`${a.dir}/`)) || projectConfig.apps.find(a => !a.dir)
4012 })).filter(f => !f.app || !f.app.disableLinting);
4013 return React__default.createElement(Lint2, {
4014 files: files,
4015 verbose: props.verbose,
4016 fix: props.fix,
4017 repoRoot: repoRoot,
4018 summary: props.summary
4019 });
4020}
4021
4022function Lint2(props) {
4023 const startTime = React.useMemo(() => new Date(), []);
4024 const eslint = useEslint(props.files, props.fix);
4025 const phpcs = usePHPCS(props.files, props.fix);
4026 const stylelint = useStylelint(props.files, props.fix);
4027 const prettierFiles = React.useMemo(() => props.files.filter(f => !eslint.files.includes(f) && !phpcs.files.includes(f) && !stylelint.filesFixable.includes(f)), [eslint.files, phpcs.files, props.files, stylelint.filesFixable]);
4028 const prettier = usePrettier(prettierFiles, props.fix);
4029 const tsChecker = useTsChecker(props.files); // Build the complete array of found errors.
4030
4031 const allErrors = [...prettier.errors, ...eslint.errors, ...tsChecker.errors, ...phpcs.errors, ...stylelint.errors];
4032 const done = eslint.done && tsChecker.done && phpcs.done && prettier.done && stylelint.done;
4033 const numErrors = allErrors.length;
4034 const numAutofixed = prettier.fixed.length + eslint.filesAutoFixed + phpcs.filesFixed;
4035 const errorsAutofixable = allErrors.filter(e => e.autoFixable).length;
4036 useExit(done, allErrors.length ? lintingFailed : undefined);
4037 useTick();
4038 return React__default.createElement(React__default.Fragment, null, React__default.createElement(ink.Box, {
4039 marginTop: 1,
4040 flexDirection: "column"
4041 }, props.summary ? React__default.createElement(ErrorSummaryList, {
4042 allErrors: allErrors
4043 }) : React__default.createElement(FileErrorList, {
4044 allErrors: allErrors,
4045 repoRoot: props.repoRoot,
4046 verbose: props.verbose
4047 })), React__default.createElement(ink.Box, null, React__default.createElement(ink.Box, {
4048 width: 15
4049 }, React__default.createElement(ink.Text, null, "Git")), React__default.createElement(ink.Text, null, "Found ", React__default.createElement(ink.Text, {
4050 color: "cyan"
4051 }, props.files.length), " files.")), !!eslint.files.length && React__default.createElement(ink.Box, null, React__default.createElement(ink.Box, {
4052 width: 15
4053 }, React__default.createElement(ink.Text, null, "ESLint")), React__default.createElement(ink.Text, null, "Linted", ' ', React__default.createElement(NumberOfTotal, {
4054 number: eslint.reports.length,
4055 total: eslint.files.length
4056 }), ' ', "files, found ", React__default.createElement(ErrorCount, {
4057 errors: eslint.errors.length
4058 }), ".")), !!prettierFiles.length && React__default.createElement(ink.Box, null, React__default.createElement(ink.Box, {
4059 width: 15
4060 }, React__default.createElement(ink.Text, null, "Prettier")), React__default.createElement(ink.Text, null, "Linted", ' ', React__default.createElement(NumberOfTotal, {
4061 number: prettier.linted,
4062 total: prettier.filesToLint
4063 }), ' ', "files, found ", React__default.createElement(ErrorCount, {
4064 errors: prettier.filesNotCorrect.length
4065 }), ".")), !!tsChecker.files.length && React__default.createElement(ink.Box, null, React__default.createElement(ink.Box, {
4066 width: 15
4067 }, React__default.createElement(ink.Text, null, "Typescript")), tsChecker.done ? React__default.createElement(ink.Text, null, "Typechecked projects, found", ' ', React__default.createElement(ErrorCount, {
4068 errors: tsChecker.errors.length
4069 }), ".") : React__default.createElement(ink.Text, null, "Typechecking projects...", !!tsChecker.errors.length && React__default.createElement(React__default.Fragment, null, ' ', "found ", React__default.createElement(ErrorCount, {
4070 errors: tsChecker.errors.length
4071 }), " so far."))), !!phpcs.files.length && projectConfig.lintPhpEnabled && React__default.createElement(ink.Box, null, React__default.createElement(ink.Box, {
4072 width: 15
4073 }, React__default.createElement(ink.Text, null, "PHPCS")), React__default.createElement(ink.Text, null, "Linted", ' ', React__default.createElement(NumberOfTotal, {
4074 number: phpcs.filesLinted,
4075 total: phpcs.files.length
4076 }), ' ', "files", props.fix && React__default.createElement(React__default.Fragment, null, ", fixed", ' ', React__default.createElement(NumberOfTotal, {
4077 number: phpcs.filesFixed,
4078 total: phpcs.filesWithFixes
4079 }), ' ', "files"), ". Found ", React__default.createElement(ErrorCount, {
4080 errors: phpcs.errors.length
4081 }), ".")), projectConfig.lintPhpEnabled || React__default.createElement(ink.Box, null, React__default.createElement(ink.Box, {
4082 width: 15
4083 }, React__default.createElement(ink.Text, null, "PHPCS")), React__default.createElement(ink.Text, {
4084 italic: true
4085 }, "Disabled.")), !!stylelint.filesToLint && React__default.createElement(ink.Box, null, React__default.createElement(ink.Box, {
4086 width: 15
4087 }, React__default.createElement(ink.Text, null, "Stylelint")), React__default.createElement(ink.Text, null, stylelint.done ? 'Linted' : 'Linting', ' ', React__default.createElement(ink.Text, {
4088 color: "cyan"
4089 }, stylelint.filesToLint), " files", stylelint.done ? '.' : '...', " Found", ' ', React__default.createElement(ErrorCount, {
4090 errors: stylelint.errors.length
4091 }), ".")), projectConfig.lintStylesEnabled || React__default.createElement(ink.Box, null, React__default.createElement(ink.Box, {
4092 width: 15
4093 }, React__default.createElement(ink.Text, null, "Stylelint")), React__default.createElement(ink.Text, {
4094 italic: true
4095 }, "Disabled.")), React__default.createElement(ink.Box, null, React__default.createElement(ink.Box, {
4096 width: 15
4097 }, React__default.createElement(ink.Text, null, "Time")), React__default.createElement(ink.Text, null, Math.round((new Date().getTime() - startTime.getTime()) / 1000), "s")), React__default.createElement(ink.Box, {
4098 marginY: 1,
4099 flexDirection: "column"
4100 }, numErrors === 0 && numAutofixed === 0 && done ? React__default.createElement(ink.Text, {
4101 underline: true
4102 }, "No errors found. Perfect!") : numErrors === 0 && numAutofixed === 0 ? React__default.createElement(ink.Text, {
4103 underline: true
4104 }, "No errors found so far...") : numErrors === 0 && numAutofixed > 0 ? React__default.createElement(ink.Text, {
4105 underline: true
4106 }, "Autofixed ", numAutofixed, " file", numAutofixed === 1 ? '' : 's', done ? '' : ' so far', ", found no unfixable errors", done ? '.' : ' yet...') : numErrors > 0 && numAutofixed > 0 ? React__default.createElement(ink.Text, {
4107 underline: true
4108 }, "Autofixed ", numAutofixed, " file", numAutofixed === 1 ? '' : 's', done ? '' : ' so far', ", but also found ", allErrors.length, " error", allErrors.length === 1 ? ' ' : 's ', "that you need to fix manually.") : numErrors > 0 && numAutofixed === 0 ? React__default.createElement(ink.Text, {
4109 underline: true
4110 }, "Found ", allErrors.length, " error", allErrors.length === 1 ? '' : 's', done ? '.' : ' so far...') : null, !props.fix && errorsAutofixable > 0 && React__default.createElement(ink.Box, {
4111 marginTop: 1
4112 }, React__default.createElement(ink.Text, {
4113 color: "grey"
4114 }, "If you run ", React__default.createElement(ink.Text, {
4115 color: "red"
4116 }, "burst lint --fix"), ' ', errorsAutofixable, " error", errorsAutofixable !== 1 && 's', " will be automatically fixed."))));
4117}
4118
4119function useTick() {
4120 const [, setS] = React.useState(0);
4121 React.useEffect(() => {
4122 const t = setTimeout(() => setS(se => se + 1), 1000);
4123 return () => clearTimeout(t);
4124 });
4125}
4126
4127function FileErrorList(props) {
4128 const errorsPerFile = lodash.groupBy(props.allErrors, 'filename');
4129 return React__default.createElement(React__default.Fragment, null, Object.entries(errorsPerFile).map(([file, errors], i1) => React__default.createElement(ink.Box, {
4130 marginBottom: 1,
4131 flexDirection: "column",
4132 key: file
4133 }, React__default.createElement(ink.Text, {
4134 italic: true
4135 }, file.startsWith(props.repoRoot) ? file.substr(props.repoRoot.length + 1) : file), errors.map((e, i2) => React__default.createElement(LintErrorMessage // eslint-disable-next-line react/no-array-index-key
4136 , {
4137 key: `${i1}_${i2}`,
4138 error: e,
4139 verbose: props.verbose
4140 })))));
4141}
4142
4143function ErrorSummaryList(props) {
4144 const errorsPerError = lodash.countBy(props.allErrors, e => e.rule ? `${e.linter} - ${e.rule}` : `${e.linter} - ${e.message}`);
4145 return React__default.createElement(ink.Box, {
4146 marginBottom: 2,
4147 flexDirection: "column"
4148 }, React__default.createElement(ink.Text, {
4149 italic: true
4150 }, "There are ", Object.keys(errorsPerError).length, " different types of errors."), lodash.sortBy(Object.entries(errorsPerError), ['1', '0']).map(([error, errors]) => React__default.createElement(ink.Box, {
4151 key: error
4152 }, React__default.createElement(ink.Box, {
4153 width: 6,
4154 alignItems: "flex-end"
4155 }, React__default.createElement(ink.Text, null, errors)), React__default.createElement(ink.Text, null, error))));
4156}
4157
4158function useFilePaths(paths) {
4159 const [filePaths, setFilePaths] = React.useState(null);
4160 React.useEffect(() => {
4161 getListOfRepoFiles(paths).then(f => setFilePaths(f));
4162 }, [paths]);
4163 return filePaths;
4164}
4165
4166function LintErrorMessage({
4167 error,
4168 verbose
4169}) {
4170 return React__default.createElement(React__default.Fragment, null, React__default.createElement(ink.Box, null, React__default.createElement(ink.Box, {
4171 width: 3
4172 }, React__default.createElement(ink.Text, null, error.autoFixable ? '✨' : '')), React__default.createElement(ink.Box, {
4173 width: 10
4174 }, React__default.createElement(ink.Text, null, error.linter)), React__default.createElement(ink.Box, {
4175 width: 10
4176 }, error.sourceLocation ? React__default.createElement(ink.Text, {
4177 color: "gray"
4178 }, error.sourceLocation.start.line, ":", error.sourceLocation.start.column) : null), React__default.createElement(ink.Box, null, React__default.createElement(ink.Text, null, error.message, ' ', !!error.rule && React__default.createElement(ink.Text, {
4179 color: "grey"
4180 }, error.rule)))), verbose && error.rawlines && error.sourceLocation && React__default.createElement(ink.Text, null, codeFrame.codeFrameColumns(error.rawlines, error.sourceLocation)));
4181}
4182
4183function ErrorCount(props) {
4184 return React__default.createElement(ink.Text, null, React__default.createElement(ink.Text, {
4185 color: props.errors ? 'red' : 'cyan'
4186 }, props.errors), " error", props.errors !== 1 ? 's' : '');
4187}
4188
4189function NumberOfTotal(props) {
4190 return React__default.createElement(React__default.Fragment, null, React__default.createElement(ink.Text, {
4191 color: "cyan"
4192 }, props.number), props.number !== props.total && React__default.createElement(React__default.Fragment, null, ' ', "/ ", React__default.createElement(ink.Text, {
4193 color: "cyan"
4194 }, props.total)));
4195}
4196
4197const {
4198 SLACK_TOKEN,
4199 GITLAB_USER_NAME
4200} = process.env;
4201const token = SLACK_TOKEN;
4202const web = new client.WebClient(token);
4203async function sendStartDeploymentMessage(project, environment) {
4204 if (!token) return;
4205 const attachment = {
4206 color: '#ffff00',
4207 fallback: `Deploy ${project.getDisplayName()}`,
4208 title: `Deploy ${project.getDisplayName()}`,
4209 title_link: project.getLink(),
4210 text: GITLAB_USER_NAME ? `The Gitlab user ${GITLAB_USER_NAME} triggered a deploy.\n` : 'A deploy was triggered.\n',
4211 fields: [{
4212 title: 'Deploy start',
4213 value: new Date().toTimeString(),
4214 short: true
4215 }, {
4216 title: 'Deploy done',
4217 value: 'Not yet...',
4218 short: true
4219 }, {
4220 title: 'URLs',
4221 value: environment.getUrls().join('\n'),
4222 short: false
4223 }]
4224 };
4225 const message = await web.chat.postMessage({
4226 channel: '#deploys',
4227 text: '',
4228 attachments: [attachment]
4229 });
4230 return async (successful, text) => {
4231 attachment.color = successful ? '#00ff00' : '#ff0000';
4232 attachment.fields[1].value = new Date().toTimeString();
4233 if (text) attachment.text += `${text}\n`;
4234 await web.chat.update({
4235 channel: message.channel,
4236 text: '',
4237 attachments: [attachment],
4238 ts: message.ts
4239 });
4240 };
4241}
4242async function sendTestFailedMessage(error) {
4243 await web.chat.postMessage({
4244 channel: '#test-reports',
4245 text: `A test failed to run successfully. \n\nError: \n\n${typeof error.message === 'string' ? error : error}\n\nGitlab CI job: ${process.env.CI_JOB_URL}`
4246 });
4247}
4248
4249const isCI$3 = require('is-ci');
4250
4251class DeployCommand extends Command {
4252 constructor(...args) {
4253 super(...args);
4254
4255 _defineProperty(this, "command", 'deploy');
4256
4257 _defineProperty(this, "description", 'Deploy one or more applications.');
4258
4259 _defineProperty(this, "options", [{
4260 flags: '--all',
4261 description: "Deprecated. Doesn't do anything."
4262 }, {
4263 flags: '--production',
4264 description: 'Deploy to the production environment.'
4265 }, {
4266 flags: '--same-branch',
4267 description: "Deprecated. Doesn't do anything."
4268 }]);
4269 }
4270
4271 async action(command) {
4272 /**
4273 * First, we need to know which apps we need to deploy.
4274 */
4275 const allHostingProvidersPerAppCombination = await getProjectInfo().getHostingProvidersByAppCominations();
4276
4277 if (allHostingProvidersPerAppCombination.length === 0) {
4278 console.error('There are no apps configured for deployment.');
4279 return process.exit(1);
4280 }
4281
4282 let hostingProvidersPerAppCombination = allHostingProvidersPerAppCombination;
4283 /**
4284 * If there is more then one app, we need to ask the user which app they want to
4285 * deploy. If this is in the CI, we always want to deploy all the apps.
4286 */
4287
4288 if (!isCI$3 && allHostingProvidersPerAppCombination.length >= 2) {
4289 const answers = await inquirer.prompt([{
4290 type: 'list',
4291 name: 'h',
4292 message: 'What apps do you want to deploy?',
4293 choices: [...allHostingProvidersPerAppCombination.map(h => ({
4294 name: `Deploy ${h.apps.map(a => a.name).join(' + ')}`,
4295 value: [h]
4296 })), new inquirer.Separator(), {
4297 name: 'All of the above',
4298 value: hostingProvidersPerAppCombination
4299 }]
4300 }]);
4301 hostingProvidersPerAppCombination = answers.h;
4302 }
4303 /**
4304 * Now that we know which apps to deploy, we need to know what environments we
4305 * need to deploy to.
4306 */
4307
4308
4309 const environmentsToDeploy = [];
4310 const branch = await getCurrentBranch(); // If the --production arg was passed, we prefer to deploy to production.
4311 // If the branch is 'master', we prefer to deploy to staging.
4312
4313 const suggestedTarget = command.production ? DeployTarget.Production : branch === 'master' ? DeployTarget.Staging : undefined; // If neither --production or 'master', we prefer to deploy to an environment with
4314 // the same name as the current branch.
4315
4316 const suggestedName = suggestedTarget ? undefined : branch; // Now, we get the environments for all hosting providers.
4317
4318 for (const appCombi of hostingProvidersPerAppCombination) {
4319 const environments = lodash.flatten((await Promise.all(appCombi.hostingProviders.map(async provider => (await provider.getPossibleEnvs({
4320 suggestedTarget,
4321 suggestedName
4322 })).map(environment => ({
4323 provider,
4324 environment,
4325 apps: appCombi.apps
4326 })))))); // When running in the CI, we just always deploy to the suggested environments.
4327 // When interaction is possible, we ask the user what environments to deploy to.
4328
4329 if (isCI$3) {
4330 environmentsToDeploy.push(...environments.filter(e => e.environment.isSuggested()));
4331 } else {
4332 const {
4333 e
4334 } = await inquirer.prompt([{
4335 type: 'list',
4336 name: 'e',
4337 message: `Where do you want to deploy ${appCombi.apps.map(awdt => awdt.name).join(' + ')} to?`,
4338 choices: [// We first want to show suggested environments, then normal environments
4339 // and as last the inactive environments
4340 ...lodash.sortBy(environments, ewa => ewa.environment.isSuggested() ? 0 : ewa.environment.isActive() ? 1 : 2).map(ewa => ({
4341 // If it's a suggested environment, we show a rocket emoji.
4342 name: (ewa.environment.isSuggested() ? '🚀 ' : ' ') + getEnvironmentDisplayName(ewa),
4343 value: ewa
4344 }))],
4345 pageSize: 30
4346 }]);
4347 environmentsToDeploy.push(e);
4348 }
4349 } // If there are no suggestions, die.
4350
4351
4352 if (environmentsToDeploy.length === 0) {
4353 console.error('There are no environments to deploy to.');
4354 return process.exit(1);
4355 }
4356 /**
4357 * Ask for confirmation before deploying. Only ask for real confirmation when
4358 * interaction is possible. On the CI, we still show what we're about to do.
4359 */
4360
4361
4362 console.log("You're about to perform the following actions:");
4363 environmentsToDeploy.forEach(e => console.log(` - ${getEnvironmentDisplayName(e)}`));
4364
4365 if (!isCI$3) {
4366 const {
4367 sure
4368 } = await inquirer.prompt([{
4369 type: 'confirm',
4370 name: 'sure',
4371 message: `Are you sure?`
4372 }]);
4373 if (!sure) return process.exit(1);
4374 }
4375 /**
4376 * Now, deploy!
4377 */
4378
4379
4380 for (const env of environmentsToDeploy) {
4381 // If there are multiple, different hosting provider configurations of the same
4382 // hosting provider we need to only deploy a subfolder.
4383 const hostingProvidersOfSameType = allHostingProvidersPerAppCombination.filter(hppac => hppac.hostingProviders.find(hp => hp.constructor === env.provider.constructor));
4384
4385 if (hostingProvidersOfSameType.length > 1 && env.apps.length !== 1) {
4386 console.error('Impossible to have multiple apps deployed when more then 1 hosting provider config of that type available.');
4387 process.exit(1);
4388 }
4389
4390 const deployOnlySubdirectory = hostingProvidersOfSameType.length > 1 ? env.apps[0].dir : undefined; // Send a message to Slack when deploying to production.
4391
4392 const done = env.environment.getDeployTarget() === DeployTarget.Production ? await sendStartDeploymentMessage(env.provider, env.environment).catch(e => console.error('Slack fail!', e)) : null;
4393
4394 try {
4395 await env.environment.deploy({
4396 deployOnlySubdirectory
4397 });
4398 } catch (e) {
4399 // Notify Slack that the deployment failed.
4400 if (done) {
4401 await done(false, e.message).catch(console.error);
4402 }
4403
4404 throw e;
4405 } // Notify Slack that the deployment is completed.
4406
4407
4408 if (done) {
4409 await done(true).catch(e => console.error('Slack fail!', e));
4410 }
4411 }
4412 }
4413
4414}
4415
4416function getEnvironmentDisplayName(e) {
4417 const displayName = e.apps.map(a => `Deploy ${chalk.magenta(a.name)} to ${chalk.cyan(e.environment.getDisplayName())}`).join(' and ') + chalk.grey(` - ${e.provider.getDisplayName()}`);
4418 if (e.environment.isActive()) return displayName;
4419 return chalk.dim(displayName) + chalk.grey(' (inactive)');
4420}
4421
4422/** Detect free variable `global` from Node.js. */
4423var freeGlobal = typeof commonjsGlobal == 'object' && commonjsGlobal && commonjsGlobal.Object === Object && commonjsGlobal;
4424
4425var _freeGlobal = freeGlobal;
4426
4427/** Detect free variable `self`. */
4428var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
4429
4430/** Used as a reference to the global object. */
4431var root = _freeGlobal || freeSelf || Function('return this')();
4432
4433var _root = root;
4434
4435/** Built-in value references. */
4436var Symbol$2 = _root.Symbol;
4437
4438var _Symbol = Symbol$2;
4439
4440/** Used for built-in method references. */
4441var objectProto = Object.prototype;
4442
4443/** Used to check objects for own properties. */
4444var hasOwnProperty$1 = objectProto.hasOwnProperty;
4445
4446/**
4447 * Used to resolve the
4448 * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
4449 * of values.
4450 */
4451var nativeObjectToString = objectProto.toString;
4452
4453/** Built-in value references. */
4454var symToStringTag = _Symbol ? _Symbol.toStringTag : undefined;
4455
4456/**
4457 * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.
4458 *
4459 * @private
4460 * @param {*} value The value to query.
4461 * @returns {string} Returns the raw `toStringTag`.
4462 */
4463function getRawTag(value) {
4464 var isOwn = hasOwnProperty$1.call(value, symToStringTag),
4465 tag = value[symToStringTag];
4466
4467 try {
4468 value[symToStringTag] = undefined;
4469 var unmasked = true;
4470 } catch (e) {}
4471
4472 var result = nativeObjectToString.call(value);
4473 if (unmasked) {
4474 if (isOwn) {
4475 value[symToStringTag] = tag;
4476 } else {
4477 delete value[symToStringTag];
4478 }
4479 }
4480 return result;
4481}
4482
4483var _getRawTag = getRawTag;
4484
4485/** Used for built-in method references. */
4486var objectProto$1 = Object.prototype;
4487
4488/**
4489 * Used to resolve the
4490 * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
4491 * of values.
4492 */
4493var nativeObjectToString$1 = objectProto$1.toString;
4494
4495/**
4496 * Converts `value` to a string using `Object.prototype.toString`.
4497 *
4498 * @private
4499 * @param {*} value The value to convert.
4500 * @returns {string} Returns the converted string.
4501 */
4502function objectToString(value) {
4503 return nativeObjectToString$1.call(value);
4504}
4505
4506var _objectToString = objectToString;
4507
4508/** `Object#toString` result references. */
4509var nullTag = '[object Null]',
4510 undefinedTag = '[object Undefined]';
4511
4512/** Built-in value references. */
4513var symToStringTag$1 = _Symbol ? _Symbol.toStringTag : undefined;
4514
4515/**
4516 * The base implementation of `getTag` without fallbacks for buggy environments.
4517 *
4518 * @private
4519 * @param {*} value The value to query.
4520 * @returns {string} Returns the `toStringTag`.
4521 */
4522function baseGetTag(value) {
4523 if (value == null) {
4524 return value === undefined ? undefinedTag : nullTag;
4525 }
4526 return (symToStringTag$1 && symToStringTag$1 in Object(value))
4527 ? _getRawTag(value)
4528 : _objectToString(value);
4529}
4530
4531var _baseGetTag = baseGetTag;
4532
4533/**
4534 * Checks if `value` is the
4535 * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
4536 * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
4537 *
4538 * @static
4539 * @memberOf _
4540 * @since 0.1.0
4541 * @category Lang
4542 * @param {*} value The value to check.
4543 * @returns {boolean} Returns `true` if `value` is an object, else `false`.
4544 * @example
4545 *
4546 * _.isObject({});
4547 * // => true
4548 *
4549 * _.isObject([1, 2, 3]);
4550 * // => true
4551 *
4552 * _.isObject(_.noop);
4553 * // => true
4554 *
4555 * _.isObject(null);
4556 * // => false
4557 */
4558function isObject$2(value) {
4559 var type = typeof value;
4560 return value != null && (type == 'object' || type == 'function');
4561}
4562
4563var isObject_1 = isObject$2;
4564
4565/** `Object#toString` result references. */
4566var asyncTag = '[object AsyncFunction]',
4567 funcTag = '[object Function]',
4568 genTag = '[object GeneratorFunction]',
4569 proxyTag = '[object Proxy]';
4570
4571/**
4572 * Checks if `value` is classified as a `Function` object.
4573 *
4574 * @static
4575 * @memberOf _
4576 * @since 0.1.0
4577 * @category Lang
4578 * @param {*} value The value to check.
4579 * @returns {boolean} Returns `true` if `value` is a function, else `false`.
4580 * @example
4581 *
4582 * _.isFunction(_);
4583 * // => true
4584 *
4585 * _.isFunction(/abc/);
4586 * // => false
4587 */
4588function isFunction(value) {
4589 if (!isObject_1(value)) {
4590 return false;
4591 }
4592 // The use of `Object#toString` avoids issues with the `typeof` operator
4593 // in Safari 9 which returns 'object' for typed arrays and other constructors.
4594 var tag = _baseGetTag(value);
4595 return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag;
4596}
4597
4598var isFunction_1 = isFunction;
4599
4600/** Used to detect overreaching core-js shims. */
4601var coreJsData = _root['__core-js_shared__'];
4602
4603var _coreJsData = coreJsData;
4604
4605/** Used to detect methods masquerading as native. */
4606var maskSrcKey = (function() {
4607 var uid = /[^.]+$/.exec(_coreJsData && _coreJsData.keys && _coreJsData.keys.IE_PROTO || '');
4608 return uid ? ('Symbol(src)_1.' + uid) : '';
4609}());
4610
4611/**
4612 * Checks if `func` has its source masked.
4613 *
4614 * @private
4615 * @param {Function} func The function to check.
4616 * @returns {boolean} Returns `true` if `func` is masked, else `false`.
4617 */
4618function isMasked(func) {
4619 return !!maskSrcKey && (maskSrcKey in func);
4620}
4621
4622var _isMasked = isMasked;
4623
4624/** Used for built-in method references. */
4625var funcProto = Function.prototype;
4626
4627/** Used to resolve the decompiled source of functions. */
4628var funcToString = funcProto.toString;
4629
4630/**
4631 * Converts `func` to its source code.
4632 *
4633 * @private
4634 * @param {Function} func The function to convert.
4635 * @returns {string} Returns the source code.
4636 */
4637function toSource(func) {
4638 if (func != null) {
4639 try {
4640 return funcToString.call(func);
4641 } catch (e) {}
4642 try {
4643 return (func + '');
4644 } catch (e) {}
4645 }
4646 return '';
4647}
4648
4649var _toSource = toSource;
4650
4651/**
4652 * Used to match `RegExp`
4653 * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).
4654 */
4655var reRegExpChar = /[\\^$.*+?()[\]{}|]/g;
4656
4657/** Used to detect host constructors (Safari). */
4658var reIsHostCtor = /^\[object .+?Constructor\]$/;
4659
4660/** Used for built-in method references. */
4661var funcProto$1 = Function.prototype,
4662 objectProto$2 = Object.prototype;
4663
4664/** Used to resolve the decompiled source of functions. */
4665var funcToString$1 = funcProto$1.toString;
4666
4667/** Used to check objects for own properties. */
4668var hasOwnProperty$2 = objectProto$2.hasOwnProperty;
4669
4670/** Used to detect if a method is native. */
4671var reIsNative = RegExp('^' +
4672 funcToString$1.call(hasOwnProperty$2).replace(reRegExpChar, '\\$&')
4673 .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
4674);
4675
4676/**
4677 * The base implementation of `_.isNative` without bad shim checks.
4678 *
4679 * @private
4680 * @param {*} value The value to check.
4681 * @returns {boolean} Returns `true` if `value` is a native function,
4682 * else `false`.
4683 */
4684function baseIsNative(value) {
4685 if (!isObject_1(value) || _isMasked(value)) {
4686 return false;
4687 }
4688 var pattern = isFunction_1(value) ? reIsNative : reIsHostCtor;
4689 return pattern.test(_toSource(value));
4690}
4691
4692var _baseIsNative = baseIsNative;
4693
4694/**
4695 * Gets the value at `key` of `object`.
4696 *
4697 * @private
4698 * @param {Object} [object] The object to query.
4699 * @param {string} key The key of the property to get.
4700 * @returns {*} Returns the property value.
4701 */
4702function getValue(object, key) {
4703 return object == null ? undefined : object[key];
4704}
4705
4706var _getValue = getValue;
4707
4708/**
4709 * Gets the native function at `key` of `object`.
4710 *
4711 * @private
4712 * @param {Object} object The object to query.
4713 * @param {string} key The key of the method to get.
4714 * @returns {*} Returns the function if it's native, else `undefined`.
4715 */
4716function getNative(object, key) {
4717 var value = _getValue(object, key);
4718 return _baseIsNative(value) ? value : undefined;
4719}
4720
4721var _getNative = getNative;
4722
4723/* Built-in method references that are verified to be native. */
4724var nativeCreate = _getNative(Object, 'create');
4725
4726var _nativeCreate = nativeCreate;
4727
4728/**
4729 * Removes all key-value entries from the hash.
4730 *
4731 * @private
4732 * @name clear
4733 * @memberOf Hash
4734 */
4735function hashClear() {
4736 this.__data__ = _nativeCreate ? _nativeCreate(null) : {};
4737 this.size = 0;
4738}
4739
4740var _hashClear = hashClear;
4741
4742/**
4743 * Removes `key` and its value from the hash.
4744 *
4745 * @private
4746 * @name delete
4747 * @memberOf Hash
4748 * @param {Object} hash The hash to modify.
4749 * @param {string} key The key of the value to remove.
4750 * @returns {boolean} Returns `true` if the entry was removed, else `false`.
4751 */
4752function hashDelete(key) {
4753 var result = this.has(key) && delete this.__data__[key];
4754 this.size -= result ? 1 : 0;
4755 return result;
4756}
4757
4758var _hashDelete = hashDelete;
4759
4760/** Used to stand-in for `undefined` hash values. */
4761var HASH_UNDEFINED = '__lodash_hash_undefined__';
4762
4763/** Used for built-in method references. */
4764var objectProto$3 = Object.prototype;
4765
4766/** Used to check objects for own properties. */
4767var hasOwnProperty$3 = objectProto$3.hasOwnProperty;
4768
4769/**
4770 * Gets the hash value for `key`.
4771 *
4772 * @private
4773 * @name get
4774 * @memberOf Hash
4775 * @param {string} key The key of the value to get.
4776 * @returns {*} Returns the entry value.
4777 */
4778function hashGet(key) {
4779 var data = this.__data__;
4780 if (_nativeCreate) {
4781 var result = data[key];
4782 return result === HASH_UNDEFINED ? undefined : result;
4783 }
4784 return hasOwnProperty$3.call(data, key) ? data[key] : undefined;
4785}
4786
4787var _hashGet = hashGet;
4788
4789/** Used for built-in method references. */
4790var objectProto$4 = Object.prototype;
4791
4792/** Used to check objects for own properties. */
4793var hasOwnProperty$4 = objectProto$4.hasOwnProperty;
4794
4795/**
4796 * Checks if a hash value for `key` exists.
4797 *
4798 * @private
4799 * @name has
4800 * @memberOf Hash
4801 * @param {string} key The key of the entry to check.
4802 * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
4803 */
4804function hashHas(key) {
4805 var data = this.__data__;
4806 return _nativeCreate ? (data[key] !== undefined) : hasOwnProperty$4.call(data, key);
4807}
4808
4809var _hashHas = hashHas;
4810
4811/** Used to stand-in for `undefined` hash values. */
4812var HASH_UNDEFINED$1 = '__lodash_hash_undefined__';
4813
4814/**
4815 * Sets the hash `key` to `value`.
4816 *
4817 * @private
4818 * @name set
4819 * @memberOf Hash
4820 * @param {string} key The key of the value to set.
4821 * @param {*} value The value to set.
4822 * @returns {Object} Returns the hash instance.
4823 */
4824function hashSet(key, value) {
4825 var data = this.__data__;
4826 this.size += this.has(key) ? 0 : 1;
4827 data[key] = (_nativeCreate && value === undefined) ? HASH_UNDEFINED$1 : value;
4828 return this;
4829}
4830
4831var _hashSet = hashSet;
4832
4833/**
4834 * Creates a hash object.
4835 *
4836 * @private
4837 * @constructor
4838 * @param {Array} [entries] The key-value pairs to cache.
4839 */
4840function Hash(entries) {
4841 var index = -1,
4842 length = entries == null ? 0 : entries.length;
4843
4844 this.clear();
4845 while (++index < length) {
4846 var entry = entries[index];
4847 this.set(entry[0], entry[1]);
4848 }
4849}
4850
4851// Add methods to `Hash`.
4852Hash.prototype.clear = _hashClear;
4853Hash.prototype['delete'] = _hashDelete;
4854Hash.prototype.get = _hashGet;
4855Hash.prototype.has = _hashHas;
4856Hash.prototype.set = _hashSet;
4857
4858var _Hash = Hash;
4859
4860/**
4861 * Removes all key-value entries from the list cache.
4862 *
4863 * @private
4864 * @name clear
4865 * @memberOf ListCache
4866 */
4867function listCacheClear() {
4868 this.__data__ = [];
4869 this.size = 0;
4870}
4871
4872var _listCacheClear = listCacheClear;
4873
4874/**
4875 * Performs a
4876 * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
4877 * comparison between two values to determine if they are equivalent.
4878 *
4879 * @static
4880 * @memberOf _
4881 * @since 4.0.0
4882 * @category Lang
4883 * @param {*} value The value to compare.
4884 * @param {*} other The other value to compare.
4885 * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
4886 * @example
4887 *
4888 * var object = { 'a': 1 };
4889 * var other = { 'a': 1 };
4890 *
4891 * _.eq(object, object);
4892 * // => true
4893 *
4894 * _.eq(object, other);
4895 * // => false
4896 *
4897 * _.eq('a', 'a');
4898 * // => true
4899 *
4900 * _.eq('a', Object('a'));
4901 * // => false
4902 *
4903 * _.eq(NaN, NaN);
4904 * // => true
4905 */
4906function eq(value, other) {
4907 return value === other || (value !== value && other !== other);
4908}
4909
4910var eq_1 = eq;
4911
4912/**
4913 * Gets the index at which the `key` is found in `array` of key-value pairs.
4914 *
4915 * @private
4916 * @param {Array} array The array to inspect.
4917 * @param {*} key The key to search for.
4918 * @returns {number} Returns the index of the matched value, else `-1`.
4919 */
4920function assocIndexOf(array, key) {
4921 var length = array.length;
4922 while (length--) {
4923 if (eq_1(array[length][0], key)) {
4924 return length;
4925 }
4926 }
4927 return -1;
4928}
4929
4930var _assocIndexOf = assocIndexOf;
4931
4932/** Used for built-in method references. */
4933var arrayProto = Array.prototype;
4934
4935/** Built-in value references. */
4936var splice = arrayProto.splice;
4937
4938/**
4939 * Removes `key` and its value from the list cache.
4940 *
4941 * @private
4942 * @name delete
4943 * @memberOf ListCache
4944 * @param {string} key The key of the value to remove.
4945 * @returns {boolean} Returns `true` if the entry was removed, else `false`.
4946 */
4947function listCacheDelete(key) {
4948 var data = this.__data__,
4949 index = _assocIndexOf(data, key);
4950
4951 if (index < 0) {
4952 return false;
4953 }
4954 var lastIndex = data.length - 1;
4955 if (index == lastIndex) {
4956 data.pop();
4957 } else {
4958 splice.call(data, index, 1);
4959 }
4960 --this.size;
4961 return true;
4962}
4963
4964var _listCacheDelete = listCacheDelete;
4965
4966/**
4967 * Gets the list cache value for `key`.
4968 *
4969 * @private
4970 * @name get
4971 * @memberOf ListCache
4972 * @param {string} key The key of the value to get.
4973 * @returns {*} Returns the entry value.
4974 */
4975function listCacheGet(key) {
4976 var data = this.__data__,
4977 index = _assocIndexOf(data, key);
4978
4979 return index < 0 ? undefined : data[index][1];
4980}
4981
4982var _listCacheGet = listCacheGet;
4983
4984/**
4985 * Checks if a list cache value for `key` exists.
4986 *
4987 * @private
4988 * @name has
4989 * @memberOf ListCache
4990 * @param {string} key The key of the entry to check.
4991 * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
4992 */
4993function listCacheHas(key) {
4994 return _assocIndexOf(this.__data__, key) > -1;
4995}
4996
4997var _listCacheHas = listCacheHas;
4998
4999/**
5000 * Sets the list cache `key` to `value`.
5001 *
5002 * @private
5003 * @name set
5004 * @memberOf ListCache
5005 * @param {string} key The key of the value to set.
5006 * @param {*} value The value to set.
5007 * @returns {Object} Returns the list cache instance.
5008 */
5009function listCacheSet(key, value) {
5010 var data = this.__data__,
5011 index = _assocIndexOf(data, key);
5012
5013 if (index < 0) {
5014 ++this.size;
5015 data.push([key, value]);
5016 } else {
5017 data[index][1] = value;
5018 }
5019 return this;
5020}
5021
5022var _listCacheSet = listCacheSet;
5023
5024/**
5025 * Creates an list cache object.
5026 *
5027 * @private
5028 * @constructor
5029 * @param {Array} [entries] The key-value pairs to cache.
5030 */
5031function ListCache(entries) {
5032 var index = -1,
5033 length = entries == null ? 0 : entries.length;
5034
5035 this.clear();
5036 while (++index < length) {
5037 var entry = entries[index];
5038 this.set(entry[0], entry[1]);
5039 }
5040}
5041
5042// Add methods to `ListCache`.
5043ListCache.prototype.clear = _listCacheClear;
5044ListCache.prototype['delete'] = _listCacheDelete;
5045ListCache.prototype.get = _listCacheGet;
5046ListCache.prototype.has = _listCacheHas;
5047ListCache.prototype.set = _listCacheSet;
5048
5049var _ListCache = ListCache;
5050
5051/* Built-in method references that are verified to be native. */
5052var Map = _getNative(_root, 'Map');
5053
5054var _Map = Map;
5055
5056/**
5057 * Removes all key-value entries from the map.
5058 *
5059 * @private
5060 * @name clear
5061 * @memberOf MapCache
5062 */
5063function mapCacheClear() {
5064 this.size = 0;
5065 this.__data__ = {
5066 'hash': new _Hash,
5067 'map': new (_Map || _ListCache),
5068 'string': new _Hash
5069 };
5070}
5071
5072var _mapCacheClear = mapCacheClear;
5073
5074/**
5075 * Checks if `value` is suitable for use as unique object key.
5076 *
5077 * @private
5078 * @param {*} value The value to check.
5079 * @returns {boolean} Returns `true` if `value` is suitable, else `false`.
5080 */
5081function isKeyable(value) {
5082 var type = typeof value;
5083 return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')
5084 ? (value !== '__proto__')
5085 : (value === null);
5086}
5087
5088var _isKeyable = isKeyable;
5089
5090/**
5091 * Gets the data for `map`.
5092 *
5093 * @private
5094 * @param {Object} map The map to query.
5095 * @param {string} key The reference key.
5096 * @returns {*} Returns the map data.
5097 */
5098function getMapData(map, key) {
5099 var data = map.__data__;
5100 return _isKeyable(key)
5101 ? data[typeof key == 'string' ? 'string' : 'hash']
5102 : data.map;
5103}
5104
5105var _getMapData = getMapData;
5106
5107/**
5108 * Removes `key` and its value from the map.
5109 *
5110 * @private
5111 * @name delete
5112 * @memberOf MapCache
5113 * @param {string} key The key of the value to remove.
5114 * @returns {boolean} Returns `true` if the entry was removed, else `false`.
5115 */
5116function mapCacheDelete(key) {
5117 var result = _getMapData(this, key)['delete'](key);
5118 this.size -= result ? 1 : 0;
5119 return result;
5120}
5121
5122var _mapCacheDelete = mapCacheDelete;
5123
5124/**
5125 * Gets the map value for `key`.
5126 *
5127 * @private
5128 * @name get
5129 * @memberOf MapCache
5130 * @param {string} key The key of the value to get.
5131 * @returns {*} Returns the entry value.
5132 */
5133function mapCacheGet(key) {
5134 return _getMapData(this, key).get(key);
5135}
5136
5137var _mapCacheGet = mapCacheGet;
5138
5139/**
5140 * Checks if a map value for `key` exists.
5141 *
5142 * @private
5143 * @name has
5144 * @memberOf MapCache
5145 * @param {string} key The key of the entry to check.
5146 * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
5147 */
5148function mapCacheHas(key) {
5149 return _getMapData(this, key).has(key);
5150}
5151
5152var _mapCacheHas = mapCacheHas;
5153
5154/**
5155 * Sets the map `key` to `value`.
5156 *
5157 * @private
5158 * @name set
5159 * @memberOf MapCache
5160 * @param {string} key The key of the value to set.
5161 * @param {*} value The value to set.
5162 * @returns {Object} Returns the map cache instance.
5163 */
5164function mapCacheSet(key, value) {
5165 var data = _getMapData(this, key),
5166 size = data.size;
5167
5168 data.set(key, value);
5169 this.size += data.size == size ? 0 : 1;
5170 return this;
5171}
5172
5173var _mapCacheSet = mapCacheSet;
5174
5175/**
5176 * Creates a map cache object to store key-value pairs.
5177 *
5178 * @private
5179 * @constructor
5180 * @param {Array} [entries] The key-value pairs to cache.
5181 */
5182function MapCache(entries) {
5183 var index = -1,
5184 length = entries == null ? 0 : entries.length;
5185
5186 this.clear();
5187 while (++index < length) {
5188 var entry = entries[index];
5189 this.set(entry[0], entry[1]);
5190 }
5191}
5192
5193// Add methods to `MapCache`.
5194MapCache.prototype.clear = _mapCacheClear;
5195MapCache.prototype['delete'] = _mapCacheDelete;
5196MapCache.prototype.get = _mapCacheGet;
5197MapCache.prototype.has = _mapCacheHas;
5198MapCache.prototype.set = _mapCacheSet;
5199
5200var _MapCache = MapCache;
5201
5202/** Used to stand-in for `undefined` hash values. */
5203var HASH_UNDEFINED$2 = '__lodash_hash_undefined__';
5204
5205/**
5206 * Adds `value` to the array cache.
5207 *
5208 * @private
5209 * @name add
5210 * @memberOf SetCache
5211 * @alias push
5212 * @param {*} value The value to cache.
5213 * @returns {Object} Returns the cache instance.
5214 */
5215function setCacheAdd(value) {
5216 this.__data__.set(value, HASH_UNDEFINED$2);
5217 return this;
5218}
5219
5220var _setCacheAdd = setCacheAdd;
5221
5222/**
5223 * Checks if `value` is in the array cache.
5224 *
5225 * @private
5226 * @name has
5227 * @memberOf SetCache
5228 * @param {*} value The value to search for.
5229 * @returns {number} Returns `true` if `value` is found, else `false`.
5230 */
5231function setCacheHas(value) {
5232 return this.__data__.has(value);
5233}
5234
5235var _setCacheHas = setCacheHas;
5236
5237/**
5238 *
5239 * Creates an array cache object to store unique values.
5240 *
5241 * @private
5242 * @constructor
5243 * @param {Array} [values] The values to cache.
5244 */
5245function SetCache(values) {
5246 var index = -1,
5247 length = values == null ? 0 : values.length;
5248
5249 this.__data__ = new _MapCache;
5250 while (++index < length) {
5251 this.add(values[index]);
5252 }
5253}
5254
5255// Add methods to `SetCache`.
5256SetCache.prototype.add = SetCache.prototype.push = _setCacheAdd;
5257SetCache.prototype.has = _setCacheHas;
5258
5259var _SetCache = SetCache;
5260
5261/**
5262 * The base implementation of `_.findIndex` and `_.findLastIndex` without
5263 * support for iteratee shorthands.
5264 *
5265 * @private
5266 * @param {Array} array The array to inspect.
5267 * @param {Function} predicate The function invoked per iteration.
5268 * @param {number} fromIndex The index to search from.
5269 * @param {boolean} [fromRight] Specify iterating from right to left.
5270 * @returns {number} Returns the index of the matched value, else `-1`.
5271 */
5272function baseFindIndex(array, predicate, fromIndex, fromRight) {
5273 var length = array.length,
5274 index = fromIndex + (fromRight ? 1 : -1);
5275
5276 while ((fromRight ? index-- : ++index < length)) {
5277 if (predicate(array[index], index, array)) {
5278 return index;
5279 }
5280 }
5281 return -1;
5282}
5283
5284var _baseFindIndex = baseFindIndex;
5285
5286/**
5287 * The base implementation of `_.isNaN` without support for number objects.
5288 *
5289 * @private
5290 * @param {*} value The value to check.
5291 * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.
5292 */
5293function baseIsNaN(value) {
5294 return value !== value;
5295}
5296
5297var _baseIsNaN = baseIsNaN;
5298
5299/**
5300 * A specialized version of `_.indexOf` which performs strict equality
5301 * comparisons of values, i.e. `===`.
5302 *
5303 * @private
5304 * @param {Array} array The array to inspect.
5305 * @param {*} value The value to search for.
5306 * @param {number} fromIndex The index to search from.
5307 * @returns {number} Returns the index of the matched value, else `-1`.
5308 */
5309function strictIndexOf(array, value, fromIndex) {
5310 var index = fromIndex - 1,
5311 length = array.length;
5312
5313 while (++index < length) {
5314 if (array[index] === value) {
5315 return index;
5316 }
5317 }
5318 return -1;
5319}
5320
5321var _strictIndexOf = strictIndexOf;
5322
5323/**
5324 * The base implementation of `_.indexOf` without `fromIndex` bounds checks.
5325 *
5326 * @private
5327 * @param {Array} array The array to inspect.
5328 * @param {*} value The value to search for.
5329 * @param {number} fromIndex The index to search from.
5330 * @returns {number} Returns the index of the matched value, else `-1`.
5331 */
5332function baseIndexOf(array, value, fromIndex) {
5333 return value === value
5334 ? _strictIndexOf(array, value, fromIndex)
5335 : _baseFindIndex(array, _baseIsNaN, fromIndex);
5336}
5337
5338var _baseIndexOf = baseIndexOf;
5339
5340/**
5341 * A specialized version of `_.includes` for arrays without support for
5342 * specifying an index to search from.
5343 *
5344 * @private
5345 * @param {Array} [array] The array to inspect.
5346 * @param {*} target The value to search for.
5347 * @returns {boolean} Returns `true` if `target` is found, else `false`.
5348 */
5349function arrayIncludes$1(array, value) {
5350 var length = array == null ? 0 : array.length;
5351 return !!length && _baseIndexOf(array, value, 0) > -1;
5352}
5353
5354var _arrayIncludes = arrayIncludes$1;
5355
5356/**
5357 * This function is like `arrayIncludes` except that it accepts a comparator.
5358 *
5359 * @private
5360 * @param {Array} [array] The array to inspect.
5361 * @param {*} target The value to search for.
5362 * @param {Function} comparator The comparator invoked per element.
5363 * @returns {boolean} Returns `true` if `target` is found, else `false`.
5364 */
5365function arrayIncludesWith(array, value, comparator) {
5366 var index = -1,
5367 length = array == null ? 0 : array.length;
5368
5369 while (++index < length) {
5370 if (comparator(value, array[index])) {
5371 return true;
5372 }
5373 }
5374 return false;
5375}
5376
5377var _arrayIncludesWith = arrayIncludesWith;
5378
5379/**
5380 * Checks if a `cache` value for `key` exists.
5381 *
5382 * @private
5383 * @param {Object} cache The cache to query.
5384 * @param {string} key The key of the entry to check.
5385 * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
5386 */
5387function cacheHas(cache, key) {
5388 return cache.has(key);
5389}
5390
5391var _cacheHas = cacheHas;
5392
5393/* Built-in method references that are verified to be native. */
5394var Set = _getNative(_root, 'Set');
5395
5396var _Set = Set;
5397
5398/**
5399 * This method returns `undefined`.
5400 *
5401 * @static
5402 * @memberOf _
5403 * @since 2.3.0
5404 * @category Util
5405 * @example
5406 *
5407 * _.times(2, _.noop);
5408 * // => [undefined, undefined]
5409 */
5410function noop() {
5411 // No operation performed.
5412}
5413
5414var noop_1 = noop;
5415
5416/**
5417 * Converts `set` to an array of its values.
5418 *
5419 * @private
5420 * @param {Object} set The set to convert.
5421 * @returns {Array} Returns the values.
5422 */
5423function setToArray(set) {
5424 var index = -1,
5425 result = Array(set.size);
5426
5427 set.forEach(function(value) {
5428 result[++index] = value;
5429 });
5430 return result;
5431}
5432
5433var _setToArray = setToArray;
5434
5435/** Used as references for various `Number` constants. */
5436var INFINITY = 1 / 0;
5437
5438/**
5439 * Creates a set object of `values`.
5440 *
5441 * @private
5442 * @param {Array} values The values to add to the set.
5443 * @returns {Object} Returns the new set.
5444 */
5445var createSet = !(_Set && (1 / _setToArray(new _Set([,-0]))[1]) == INFINITY) ? noop_1 : function(values) {
5446 return new _Set(values);
5447};
5448
5449var _createSet = createSet;
5450
5451/** Used as the size to enable large array optimizations. */
5452var LARGE_ARRAY_SIZE = 200;
5453
5454/**
5455 * The base implementation of `_.uniqBy` without support for iteratee shorthands.
5456 *
5457 * @private
5458 * @param {Array} array The array to inspect.
5459 * @param {Function} [iteratee] The iteratee invoked per element.
5460 * @param {Function} [comparator] The comparator invoked per element.
5461 * @returns {Array} Returns the new duplicate free array.
5462 */
5463function baseUniq(array, iteratee, comparator) {
5464 var index = -1,
5465 includes = _arrayIncludes,
5466 length = array.length,
5467 isCommon = true,
5468 result = [],
5469 seen = result;
5470
5471 if (comparator) {
5472 isCommon = false;
5473 includes = _arrayIncludesWith;
5474 }
5475 else if (length >= LARGE_ARRAY_SIZE) {
5476 var set = iteratee ? null : _createSet(array);
5477 if (set) {
5478 return _setToArray(set);
5479 }
5480 isCommon = false;
5481 includes = _cacheHas;
5482 seen = new _SetCache;
5483 }
5484 else {
5485 seen = iteratee ? [] : result;
5486 }
5487 outer:
5488 while (++index < length) {
5489 var value = array[index],
5490 computed = iteratee ? iteratee(value) : value;
5491
5492 value = (comparator || value !== 0) ? value : 0;
5493 if (isCommon && computed === computed) {
5494 var seenIndex = seen.length;
5495 while (seenIndex--) {
5496 if (seen[seenIndex] === computed) {
5497 continue outer;
5498 }
5499 }
5500 if (iteratee) {
5501 seen.push(computed);
5502 }
5503 result.push(value);
5504 }
5505 else if (!includes(seen, computed, comparator)) {
5506 if (seen !== result) {
5507 seen.push(computed);
5508 }
5509 result.push(value);
5510 }
5511 }
5512 return result;
5513}
5514
5515var _baseUniq = baseUniq;
5516
5517/**
5518 * Creates a duplicate-free version of an array, using
5519 * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
5520 * for equality comparisons, in which only the first occurrence of each element
5521 * is kept. The order of result values is determined by the order they occur
5522 * in the array.
5523 *
5524 * @static
5525 * @memberOf _
5526 * @since 0.1.0
5527 * @category Array
5528 * @param {Array} array The array to inspect.
5529 * @returns {Array} Returns the new duplicate free array.
5530 * @example
5531 *
5532 * _.uniq([2, 1, 2]);
5533 * // => [2, 1]
5534 */
5535function uniq(array) {
5536 return (array && array.length) ? _baseUniq(array) : [];
5537}
5538
5539var uniq_1 = uniq;
5540
5541const access = util.promisify(fs__default.access);
5542async function exists(somePath) {
5543 return access(somePath).then(() => true).catch(() => false);
5544}
5545
5546const defaultGitignoreRules = `
5547
5548# Created by https://www.gitignore.io/api/node,code,linux,macos,windows,composer,phpstorm+all
5549# Edit at https://www.gitignore.io/?templates=node,code,linux,macos,windows,composer,phpstorm+all
5550
5551### Code ###
5552.vscode/*
5553!.vscode/settings.json
5554!.vscode/tasks.json
5555!.vscode/launch.json
5556!.vscode/extensions.json
5557
5558### Composer ###
5559composer.phar
5560/vendor/
5561
5562# Commit your application's lock file https://getcomposer.org/doc/01-basic-usage.md#commit-your-composer-lock-file-to-version-control
5563# You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file
5564# composer.lock
5565
5566### Linux ###
5567*~
5568
5569# temporary files which can be created if a process still has a handle open of a deleted file
5570.fuse_hidden*
5571
5572# KDE directory preferences
5573.directory
5574
5575# Linux trash folder which might appear on any partition or disk
5576.Trash-*
5577
5578# .nfs files are created when an open file is removed but is still being accessed
5579.nfs*
5580
5581### macOS ###
5582# General
5583.DS_Store
5584.AppleDouble
5585.LSOverride
5586
5587# Icon must end with two \r
5588Icon
5589
5590# Thumbnails
5591._*
5592
5593# Files that might appear in the root of a volume
5594.DocumentRevisions-V100
5595.fseventsd
5596.Spotlight-V100
5597.TemporaryItems
5598.Trashes
5599.VolumeIcon.icns
5600.com.apple.timemachine.donotpresent
5601
5602# Directories potentially created on remote AFP share
5603.AppleDB
5604.AppleDesktop
5605Network Trash Folder
5606Temporary Items
5607.apdisk
5608
5609### Node ###
5610# Logs
5611logs
5612*.log
5613npm-debug.log*
5614yarn-debug.log*
5615yarn-error.log*
5616lerna-debug.log*
5617
5618# Diagnostic reports (https://nodejs.org/api/report.html)
5619report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
5620
5621# Runtime data
5622pids
5623*.pid
5624*.seed
5625*.pid.lock
5626
5627# Directory for instrumented libs generated by jscoverage/JSCover
5628lib-cov
5629
5630# Coverage directory used by tools like istanbul
5631coverage
5632*.lcov
5633
5634# nyc test coverage
5635.nyc_output
5636
5637# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
5638.grunt
5639
5640# Bower dependency directory (https://bower.io/)
5641bower_components
5642
5643# node-waf configuration
5644.lock-wscript
5645
5646# Compiled binary addons (https://nodejs.org/api/addons.html)
5647build/Release
5648
5649# Dependency directories
5650node_modules/
5651jspm_packages/
5652
5653# TypeScript v1 declaration files
5654typings/
5655
5656# TypeScript cache
5657*.tsbuildinfo
5658
5659# Optional npm cache directory
5660.npm
5661
5662# Optional eslint cache
5663.eslintcache
5664
5665# Optional REPL history
5666.node_repl_history
5667
5668# Output of 'npm pack'
5669*.tgz
5670
5671# Yarn Integrity file
5672.yarn-integrity
5673
5674# dotenv environment variables file
5675.env
5676.env.test
5677
5678# parcel-bundler cache (https://parceljs.org/)
5679.cache
5680
5681# next.js build output
5682.next
5683
5684# nuxt.js build output
5685.nuxt
5686
5687# rollup.js default build output
5688dist/
5689
5690# Uncomment the public line if your project uses Gatsby
5691# https://nextjs.org/blog/next-9-1#public-directory-support
5692# https://create-react-app.dev/docs/using-the-public-folder/#docsNav
5693# public
5694
5695# Storybook build outputs
5696.out
5697.storybook-out
5698
5699# vuepress build output
5700.vuepress/dist
5701
5702# Serverless directories
5703.serverless/
5704
5705# FuseBox cache
5706.fusebox/
5707
5708# DynamoDB Local files
5709.dynamodb/
5710
5711# Temporary folders
5712tmp/
5713temp/
5714
5715### PhpStorm+all ###
5716# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
5717# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
5718
5719# User-specific stuff
5720.idea/**/workspace.xml
5721.idea/**/tasks.xml
5722.idea/**/usage.statistics.xml
5723.idea/**/dictionaries
5724.idea/**/shelf
5725
5726# Generated files
5727.idea/**/contentModel.xml
5728
5729# Sensitive or high-churn files
5730.idea/**/dataSources/
5731.idea/**/dataSources.ids
5732.idea/**/dataSources.local.xml
5733.idea/**/sqlDataSources.xml
5734.idea/**/dynamic.xml
5735.idea/**/uiDesigner.xml
5736.idea/**/dbnavigator.xml
5737
5738# Gradle
5739.idea/**/gradle.xml
5740.idea/**/libraries
5741
5742# Gradle and Maven with auto-import
5743# When using Gradle or Maven with auto-import, you should exclude module files,
5744# since they will be recreated, and may cause churn. Uncomment if using
5745# auto-import.
5746# .idea/modules.xml
5747# .idea/*.iml
5748# .idea/modules
5749# *.iml
5750# *.ipr
5751
5752# CMake
5753cmake-build-*/
5754
5755# Mongo Explorer plugin
5756.idea/**/mongoSettings.xml
5757
5758# File-based project format
5759*.iws
5760
5761# IntelliJ
5762out/
5763
5764# mpeltonen/sbt-idea plugin
5765.idea_modules/
5766
5767# JIRA plugin
5768atlassian-ide-plugin.xml
5769
5770# Cursive Clojure plugin
5771.idea/replstate.xml
5772
5773# Crashlytics plugin (for Android Studio and IntelliJ)
5774com_crashlytics_export_strings.xml
5775crashlytics.properties
5776crashlytics-build.properties
5777fabric.properties
5778
5779# Editor-based Rest Client
5780.idea/httpRequests
5781
5782# Android studio 3.1+ serialized cache file
5783.idea/caches/build_file_checksums.ser
5784
5785### PhpStorm+all Patch ###
5786# Ignores the whole .idea folder and all .iml files
5787# See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360
5788
5789.idea/
5790
5791# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023
5792
5793*.iml
5794modules.xml
5795.idea/misc.xml
5796*.ipr
5797
5798# Sonarlint plugin
5799.idea/sonarlint
5800
5801### Windows ###
5802# Windows thumbnail cache files
5803Thumbs.db
5804Thumbs.db:encryptable
5805ehthumbs.db
5806ehthumbs_vista.db
5807
5808# Dump file
5809*.stackdump
5810
5811# Folder config file
5812[Dd]esktop.ini
5813
5814# Recycle Bin used on file shares
5815$RECYCLE.BIN/
5816
5817# Windows Installer files
5818*.cab
5819*.msi
5820*.msix
5821*.msm
5822*.msp
5823
5824# Windows shortcuts
5825*.lnk
5826
5827# End of https://www.gitignore.io/api/node,code,linux,macos,windows,composer,phpstorm+all
5828
5829`;
5830/**
5831 * These are all the gitignore rules that are added on top of all Burst
5832 * projects.
5833 */
5834
5835const projectGitignore = [// Files that are scaffolded
5836'.vscode', '.idea', 'phpcs.xml', // Platform.sh dump files
5837'*--dump.sql', '*--dump.sql.gz', // DDev configuration
5838'.ddev', // Various other rules, as defined by .gitignore templates
5839...defaultGitignoreRules.split('\n').map(s => s.trim()).filter(s => s !== '' && !s.startsWith('#'))];
5840
5841/**
5842 * This file should be scaffolded into .vscode/extensions.json.
5843 */
5844const vscodeExtensions = `
5845{
5846 "recommendations": [
5847 // This shows PHP lint validation errors while editing PHP files, and fixes them on save.
5848 "wongjn.php-sniffer",
5849
5850 // Show the right styntax highlighting for Drupal-specific file extensions.
5851 "marcostazi.vs-code-drupal",
5852
5853 // Shows and autofixes ESLint errors (including Prettier errors).
5854 "dbaeumer.vscode-eslint",
5855
5856 // Shows and autofixes Stylelint errors (including Prettier errors).
5857 "stylelint.vscode-stylelint",
5858
5859 // Applies prettier fixes to all supported files.
5860 "esbenp.prettier-vscode"
5861 ]
5862}
5863`;
5864
5865class SyncPlatformToDdevCommand extends Command {
5866 constructor(...args) {
5867 super(...args);
5868
5869 _defineProperty(this, "command", 'sync-platform-to-ddev');
5870
5871 _defineProperty(this, "description", 'Synchronizes a platform.sh database to a local ddev database.');
5872
5873 _defineProperty(this, "action", async () => {
5874 const ddevConfigurations = getDdevConfigurations();
5875
5876 if (!ddevConfigurations.length) {
5877 console.error('There are no ddev configurations available.');
5878 return;
5879 }
5880
5881 const ddevProjects = await getDdevProjects();
5882 const ddevs = ddevConfigurations.map(configuration => ({
5883 configuration,
5884 project: ddevProjects.find(p => p.approot === configuration.projectRoot)
5885 }));
5886
5887 if (!ddevs.some(d => d.project)) {
5888 console.error('There are no ddev projects running.');
5889 return;
5890 }
5891
5892 for (const ddev of ddevs) {
5893 // eslint-disable-next-line no-continue
5894 if (!ddev.project) continue;
5895 const dbFile = `${repoRoot}/ddev--dump.sql.gz`;
5896
5897 try {
5898 console.log(`Downloading database from the Platform.sh app ${ddev.configuration.platformApp}...`);
5899 await execa('platform', ['db:dump', '--project', ddev.configuration.platformProject, '--app', ddev.configuration.platformApp, '--file', 'ddev--dump.sql.gz', '--gzip'], {
5900 cwd: repoRoot,
5901 stdio: 'inherit'
5902 });
5903 console.log('Importing database into ddev...');
5904 await execa('ddev', ['import-db', '--src', dbFile], {
5905 cwd: ddev.project.approot,
5906 stdio: 'inherit'
5907 });
5908 } finally {
5909 fs__default.unlinkSync(dbFile);
5910 }
5911 }
5912 });
5913 }
5914
5915}
5916function getDdevConfigurations() {
5917 const projects = [];
5918 projectConfig.apps.forEach(async app => {
5919 try {
5920 const hosting = app.hosting.find(h => h.type === 'platform');
5921 if (!hosting) return;
5922 const platformFile = yaml__default.load(fs__default.readFileSync(`${app.path}/.platform.app.yaml`, {
5923 encoding: 'utf8'
5924 }));
5925 const webroot = platformFile.web.locations['/'].root;
5926 const forceRoot = !projectConfig.apps.some(a => !a.dir) && app.dir === 'drupal';
5927 projects.push({
5928 app,
5929 docroot: forceRoot ? `${app.dir}/${webroot}` : webroot,
5930 projectName: `burst--${path$1__default.basename(repoRoot)}--${app.name}`,
5931 projectRoot: forceRoot ? repoRoot : app.path,
5932 platformApp: platformFile.name,
5933 platformProject: hosting.id,
5934 phpVersion: platformFile.type.split(':')[1]
5935 });
5936 } catch (_unused) {// Don't add project.
5937 }
5938 });
5939 return projects;
5940}
5941
5942async function getDdevProjects() {
5943 try {
5944 const ddevList = await execa.command('ddev list -j');
5945 const ddevProjects = JSON.parse(ddevList.stdout).raw;
5946 return ddevProjects.filter(p => p.status === 'running');
5947 } catch (_unused2) {
5948 return [];
5949 }
5950}
5951
5952const prettierConfig = require('@burst/prettier-config');
5953
5954const write = util.promisify(fs__default.writeFile);
5955const read = util.promisify(fs__default.readFile);
5956const unlink = util.promisify(fs__default.unlink);
5957const mkdir = util.promisify(fs__default.mkdir);
5958const parseXml = util.promisify(new xml2js.Parser().parseString);
5959const buildXml = new xml2js.Builder();
5960const {
5961 apps
5962} = projectConfig;
5963class ScaffoldCommand extends Command {
5964 constructor(...args) {
5965 super(...args);
5966
5967 _defineProperty(this, "command", 'scaffold');
5968
5969 _defineProperty(this, "description", 'Scaffolds various configuration files into the root of the git repository.');
5970
5971 _defineProperty(this, "action", async () => {
5972 // Delete all files that were created in previous versions of the scaffold
5973 // command. They can conflict with the other settings written to the file
5974 // system.
5975 const filesToDelete = ['.eslintrc.yaml', '.prettierrc.yaml', 'tslint.yaml'];
5976 await Promise.all(filesToDelete.map(async filename => {
5977 if (await exists(`${repoRoot}/${filename}`)) {
5978 await unlink(`${repoRoot}/${filename}`);
5979 console.log(`💣 Deleted ${filename} because it isn't used anymore.`);
5980 }
5981 }));
5982 const composerHelperDir = path$1__default.join(__dirname, '../composer-helper'); // The primary app type is any app type other then 'other' when available.
5983
5984 const primaryAppType = apps.map(a => a.type).filter(t => t !== 'other')[0] || 'other';
5985 const phpcsRuleset = ['<?xml version="1.0"?>', '<ruleset name="Auto-generated ruleset for this project by the Burst CLI" namespace="Burst">', ` <config name="installed_paths" value="${composerHelperDir}/vendor/wp-coding-standards/wpcs" />`, ...appTypes.map(type => apps.some(app => app.type === type) ? type === primaryAppType ? ` <rule ref="${composerHelperDir}/${type}_ruleset.xml" />` : ` <!--rule ref="${composerHelperDir}/${type}_ruleset.xml" /-->` : ` <!-- No ${type} apps -->`), '</ruleset>'];
5986 await write(`${repoRoot}/phpcs.xml`, phpcsRuleset.join('\n'));
5987 console.log('🔥 Written to phpcs.xml');
5988 const eslintModuleFolder = `${require.resolve('eslint').split('/node_modules/eslint/')[0]}/node_modules`;
5989 const eslintFolder = `${eslintModuleFolder}/eslint`;
5990
5991 if (!(await exists(`${repoRoot}/.idea`))) {
5992 console.log("⛔ The .idea folder doesn't exist, so IntelliJ won't be configured.");
5993 } else {
5994 // PHPStorm reads from a eslint.xml file. Because it only contains eslint
5995 // settings we can just overwrite it.
5996 if (!(await exists(`${repoRoot}/.idea/jsLinters`))) {
5997 await mkdir(`${repoRoot}/.idea/jsLinters`);
5998 console.log('🔥 Created .idea/jsLinters');
5999 }
6000
6001 await write(`${repoRoot}/.idea/jsLinters/eslint.xml`, `<?xml version="1.0" encoding="UTF-8"?>
6002 <project version="4">
6003 <component name="EslintConfiguration">
6004 <custom-configuration-file used="true" path="${require.resolve('@burst/eslint-config')}" />
6005 </component>
6006 </project>
6007 `);
6008 console.log('🔥 Written to .idea/jsLinters/eslint.xml');
6009 const phpXmlPath = `${repoRoot}/.idea/php.xml`;
6010
6011 if (!(await exists(phpXmlPath))) {
6012 await write(`${repoRoot}/.idea/php.xml`, `<?xml version="1.0" encoding="UTF-8"?>
6013 <project version="4">
6014 <component name="PhpCodeSniffer">
6015 <phpcs_settings>
6016 <PhpCSConfiguration standards="Drupal;DrupalPractice;MySource;PEAR;PHPCS;PSR1;PSR2;Squiz;Zend" tool_path="${composerHelperDir}/vendor/bin/phpcs" timeout="30000" />
6017 </phpcs_settings>
6018 </component>
6019 </project>
6020 `);
6021 console.log('🔥 Created .idea/php.xml');
6022 } else {
6023 try {
6024 const phpXml = await parseXml((await read(phpXmlPath)));
6025 phpXml.project.component = phpXml.project.component ? phpXml.project.component.filter(c => c.$.name !== 'PhpCodeSniffer') : [];
6026 phpXml.project.component.push({
6027 $: {
6028 name: 'PhpCodeSniffer'
6029 },
6030 phpcs_settings: [{
6031 PhpCSConfiguration: [{
6032 $: {
6033 standards: 'Drupal;DrupalPractice;MySource;PEAR;PHPCS;PSR1;PSR2;Squiz;Zend',
6034 tool_path: `${composerHelperDir}/vendor/bin/phpcs`,
6035 beautifier_path: `${composerHelperDir}/vendor/bin/phpcbf`,
6036 timeout: 30000
6037 }
6038 }]
6039 }]
6040 });
6041 await write(phpXmlPath, buildXml.buildObject(phpXml));
6042 console.log('🔥 Adjusted .idea/php.xml');
6043 } catch (e) {
6044 console.error(e);
6045 console.error();
6046 console.log('⛔ Writing to .idea/php.xml not possible. Please configure the following phpcs package:');
6047 console.error(` ${composerHelperDir}/vendor/bin/phpcs`);
6048 }
6049 }
6050
6051 try {
6052 const workspacePath = `${repoRoot}/.idea/workspace.xml`;
6053 const workspaceXml = await parseXml((await read(workspacePath)));
6054 const properties = workspaceXml.project.component.find(c => c.$.name === 'PropertiesComponent').property;
6055 Object.entries({
6056 'node.js.detected.package.eslint': 'true',
6057 'node.js.path.for.package.eslint': 'project',
6058 'node.js.selected.package.eslint': eslintFolder,
6059 'node.js.detected.package.standard': 'true',
6060 'node.js.path.for.package.standard': 'project',
6061 'node.js.selected.package.standard': eslintFolder
6062 }).forEach(([name, value]) => {
6063 const property = properties.find(p => p.$.name === name);
6064 if (property) property.$.value = value;else properties.push({
6065 $: {
6066 name,
6067 value
6068 }
6069 });
6070 });
6071 await write(workspacePath, buildXml.buildObject(workspaceXml));
6072 console.log('🔥 Written to .idea/workspace.xml');
6073 } catch (e) {
6074 console.error(e);
6075 console.error();
6076 console.log('⛔ Writing to .idea/workspace.xml not possible. Please configure the following eslint package:');
6077 console.log(` ${eslintFolder}`);
6078 }
6079
6080 try {
6081 const inspectionPath = `${repoRoot}/.idea/inspectionProfiles/Project_Default.xml`;
6082
6083 if (!(await exists(`${repoRoot}/.idea/inspectionProfiles`))) {
6084 await mkdir(`${repoRoot}/.idea/inspectionProfiles`);
6085 console.log('🔥 Created .idea/inspectionProfiles');
6086 }
6087
6088 if (!(await exists(inspectionPath))) {
6089 await write(inspectionPath, `<component name="InspectionProjectProfileManager">
6090 <profile version="1.0">
6091 <option name="myName" value="Project Default" />
6092 <inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
6093 </profile>
6094 </component>`);
6095 console.log('🔥 Created .idea/inspectionProfiles/Project_Default.xml');
6096 } else {
6097 const inspectionXml = await parseXml((await read(inspectionPath)));
6098 const profile = inspectionXml.component.profile[0];
6099
6100 if (!profile.inspection_tool) {
6101 profile.inspection_tool = [];
6102 }
6103
6104 profile.inspection_tool = profile.inspection_tool.filter(i => i.$.class !== 'Eslint' && i.$.class !== 'PhpCSValidationInspection');
6105 profile.inspection_tool.push({
6106 $: {
6107 class: 'Eslint',
6108 enabled: true,
6109 level: 'WARNING',
6110 enabled_by_default: 'true'
6111 }
6112 });
6113 profile.inspection_tool.push({
6114 $: {
6115 class: 'PhpCSValidationInspection',
6116 enabled: true,
6117 level: 'WARNING',
6118 enabled_by_default: 'true'
6119 },
6120 option: [{
6121 $: {
6122 name: 'CODING_STANDARD',
6123 value: 'Custom'
6124 }
6125 }, {
6126 $: {
6127 name: 'CUSTOM_RULESET_PATH',
6128 value: `${repoRoot}/phpcs.xml`
6129 }
6130 }, {
6131 $: {
6132 name: 'EXTENSIONS',
6133 value: 'php'
6134 }
6135 }]
6136 });
6137 await write(inspectionPath, buildXml.buildObject(inspectionXml));
6138 console.log('🔥 Adjusted .idea/inspectionProfiles/Project_Default.xml');
6139 }
6140 } catch (e) {
6141 console.error(e);
6142 console.error();
6143 console.log('⛔ Writing to .idea/inspectionProfiles/Project_Default.xml not possible. You need to enable eslint in the project settings yourself.');
6144 }
6145 } // VSCode reads its settings from .vscode/settings.json. We write to this
6146 // file to configure VSCode to automatically fix all linting errors.
6147
6148
6149 const vscode = this.json(_objectSpread({
6150 // Prettier uses 80 as the max line length, so we want to show that in the
6151 // editor too.
6152 'editor.rulers': [80],
6153 // This adds eslint configs to reflect the burst lint command.
6154 'editor.codeActionsOnSave': {
6155 'source.fixAll.eslint': true
6156 },
6157 'eslint.nodePath': `${eslintModuleFolder}/`,
6158 'eslint.options': {
6159 configFile: require.resolve('@burst/eslint-config'),
6160 useEslintRc: false,
6161 reportUnusedDisaleDirectives: true
6162 }
6163 }, Object.entries(prettierConfig).reduce((c, [k, v]) => _objectSpread({}, c, {
6164 [`prettier.${k}`]: v
6165 }), {}), {
6166 // We want to run Prettier every time someone saves a file.
6167 'editor.formatOnSave': true,
6168 // Because ESLint already fixes all JS and TS files, we need to disable
6169 // prettier on these file types.
6170 '[javascript]': {
6171 'editor.formatOnSave': false
6172 },
6173 '[javascriptreact]': {
6174 'editor.formatOnSave': false
6175 },
6176 '[typescript]': {
6177 'editor.formatOnSave': false
6178 },
6179 '[typescriptreact]': {
6180 'editor.formatOnSave': false
6181 },
6182 // This configures PHP linting for the 'wongjn.php-sniffer' extension.
6183 'phpSniffer.executablesFolder': `${composerHelperDir}/vendor/bin/`,
6184 'phpSniffer.standard': `${repoRoot}/phpcs.xml`,
6185 'phpSniffer.run': 'onType',
6186 'css.validate': false,
6187 'stylelint.config': {
6188 extends: require.resolve('@burst/stylelint-config')
6189 }
6190 })).trim().split('\n').slice(1, -1); // Create .vscode/settings.json if it doesn't exist yet.
6191
6192 if (!(await exists(`${repoRoot}/.vscode`))) {
6193 await mkdir(`${repoRoot}/.vscode`);
6194 console.log('🔥 Created .vscode');
6195 }
6196
6197 if (!(await exists(`${repoRoot}/.vscode/settings.json`))) {
6198 await write(`${repoRoot}/.vscode/settings.json`, `{\n}`);
6199 console.log('🔥 Created .vscode/settings.json');
6200 }
6201
6202 const vscodeFile = (await read(`${repoRoot}/.vscode/settings.json`, {
6203 encoding: 'utf8'
6204 })).trim().split('\n');
6205 const startScaffoldL = ' // @start-burst-cli-scaffold';
6206 const endScaffoldL = ' // @end-burst-cli-scaffold';
6207 const startScaffoldI = vscodeFile.findIndex(l => l.trim() === startScaffoldL.trim());
6208 const endScaffoldI = vscodeFile.findIndex(l => l.trim() === endScaffoldL.trim());
6209 const newVscodeFile = startScaffoldI !== -1 && endScaffoldI !== -1 ? [// Only replace the parts between the start and end scaffold lines.
6210 // All other lines are kept intact.
6211 ...vscodeFile.slice(0, startScaffoldI + 1), ...vscode, ...vscodeFile.slice(endScaffoldI), ''] : [// Always start with our own settings.
6212 '{', startScaffoldL, ...vscode, endScaffoldL, // Then output the original contents, but without the brackets.
6213 ...vscodeFile.slice(1, -1), '}', ''];
6214 await write(`${repoRoot}/.vscode/settings.json`, newVscodeFile.join('\n'));
6215 console.log('🔥 Written to .vscode/settings.json');
6216 await write(`${repoRoot}/.vscode/extensions.json`, vscodeExtensions);
6217 console.log('🔥 Written to .vscode/extensions.json'); // Write to the .gitignore file.
6218
6219 const gitignoreLines = ['# @start-burst-cli-gitignore', ...['', `# DON'T ADD ANY RULES BEFORE THIS BLOCK.`, `# These rules are automatically generated by the 'burst scaffold' command.`, '# Add your own rules after this block, or they will be overwritten.', ...projectGitignore.map(p => `${p}\n#${' 👇 ONLY EDIT BELOW THIS BLOCK 👇'.padStart(79, '#')}`)], '# YOU CAN ADD RULES AFTER THE NEXT LINE.', '# @end-burst-cli-gitignore'];
6220 const giS = gitignoreLines[0];
6221 const giE = gitignoreLines[gitignoreLines.length - 1];
6222 const gitignore = await read(`${repoRoot}/.gitignore`, {
6223 encoding: 'utf8'
6224 });
6225
6226 if (gitignore.startsWith(giS)) {
6227 await write(`${repoRoot}/.gitignore`, `${gitignoreLines.join('\n')}${gitignore.split(giE, 2)[1]}`);
6228 console.log('🔥 Adjusted .gitignore rules');
6229 } else {
6230 await write(`${repoRoot}/.gitignore`, `${gitignoreLines.join('\n')}\n\n${gitignore}`);
6231 console.log('🔥 Added new .gitignore rules');
6232 }
6233
6234 const ddevVersionCheck = await execa.command('ddev --version', {
6235 reject: false
6236 });
6237
6238 if (!ddevVersionCheck.failed) {
6239 await Promise.all(getDdevConfigurations().map(async project => {
6240 try {
6241 const additionalHostnames = await getPlatformRoutes(project.platformProject, project.platformApp).catch(() => []);
6242 await execa('ddev', ['config', '--project-name', project.projectName, '--project-tld', 'localhost', '--docroot', project.docroot, '--php-version', project.phpVersion, ...(additionalHostnames.length ? ['--additional-hostnames', additionalHostnames.join(',')] : [])], {
6243 cwd: project.projectRoot
6244 });
6245 console.log(`🔥 Initialized ddev for Platform.sh app ${project.platformApp}`);
6246 } catch (_unused) {
6247 console.log(`⛔ Could not initialize ddev for Platform.sh app ${project.platformApp}`);
6248 }
6249 }));
6250 }
6251 });
6252 }
6253
6254 json(data) {
6255 return JSON.stringify(data, null, 2);
6256 }
6257
6258}
6259
6260async function getPlatformRoutes(projectId, projectApp) {
6261 const {
6262 stdout
6263 } = await execa('platform', ['route:list', '--project', projectId, '--environment', 'master', '--format', 'csv']);
6264 let routes = stdout.split('\n').map(route => route.match(/https:\/\/(.*)\/,upstream,(.*)/)).filter(route => route && route[2] === projectApp).map(route => route[1]); // Replace the {default} placeholder with the default domain on platform.sh
6265
6266 try {
6267 if (routes.some(r => r.includes('{default}'))) {
6268 const {
6269 stdout: defaultDomain
6270 } = await execa('platform', ['project:info', 'default_domain', '--project', projectId]);
6271 routes = routes.map(r => r.replace('{default}', defaultDomain));
6272 }
6273 } catch (_unused2) {} // We can ignore any errors, as we will remove all hostnames that
6274 // still contain placeholders.
6275 // Replace the {all} placeholder with all domains on platform.sh
6276
6277
6278 try {
6279 const routesWithAll = routes.filter(r => r.includes('{all}'));
6280
6281 if (routesWithAll.length) {
6282 const {
6283 stdout: allDomains
6284 } = await execa('platform', ['domain:list', '--project', projectId, '--columns=name', '--format=csv', '--no-header']); // We can just append the newly formatted domains, as they will be removed
6285 // anyway.
6286
6287 routesWithAll.forEach(route => {
6288 allDomains.split('\n').forEach(domain => {
6289 routes.push(route.replace('{all}', domain));
6290 });
6291 });
6292 }
6293 } catch (_unused3) {} // We can ignore any errors, as we will remove all hostnames that
6294 // still contain placeholders.
6295 // Remove all hostnames that still contain placeholders.
6296
6297
6298 routes = routes.filter(r => !r.includes('{'));
6299 return uniq_1(routes);
6300}
6301
6302class InstallCommand extends Command {
6303 constructor(...args) {
6304 super(...args);
6305
6306 _defineProperty(this, "command", 'install');
6307
6308 _defineProperty(this, "description", 'Installs all dependencies of a repository.');
6309
6310 _defineProperty(this, "action", async () => {
6311 // With these parameters, the CI job can be parallized. This means that in
6312 // this script, we only have to execute a part of the installations.
6313 const index = parseInt(process.env.CI_NODE_INDEX || '0', 10) - 1;
6314 const total = parseInt(process.env.CI_NODE_TOTAL || '1', 10); // Get all package manager files.
6315
6316 const lockfiles = await getListOfRepoFiles(['package-lock.json', '*/package-lock.json', 'yarn.lock', '*/yarn.lock', 'composer.lock', '*/composer.lock'], true); // Take the lockfiles we're going to install this time.
6317 // Let's take this example:
6318 // - lockfiles.length = 8
6319 // - index = 2 (shows up as 3/5)
6320 // - total = 5
6321 // That means that we want to execute the install of the third and the
6322 // eighth lockfile. The following formula does that:
6323
6324 const lockfilesToInstall = lockfiles.filter(({}, i) => (i - index) % total === 0);
6325
6326 if (lockfilesToInstall.length === 0) {
6327 console.log("This job doesn't do anything.");
6328 console.log("That's completely fine, and you don't have to change anything about that.");
6329
6330 if (lockfiles.length > 0) {
6331 console.log(`Please look at the first ${lockfiles.length !== 1 ? `${lockfiles.length} jobs` : 'job'}.`);
6332 }
6333
6334 return;
6335 }
6336
6337 console.log('===================================');
6338 console.log('INSTALLING THE FOLLOWING LOCKFILES:\n');
6339 lockfilesToInstall.forEach(l => console.log(l));
6340 console.log('===================================\n\n');
6341 const root = await getRepoRoot(); // eslint-disable-next-line no-restricted-syntax
6342
6343 for (const lockfile of lockfilesToInstall) {
6344 const absolutePath = `${root}/${lockfile}`;
6345 console.log('===================================');
6346 console.log('Starting installation of:');
6347 console.log(absolutePath);
6348 console.log('===================================\n');
6349
6350 if (absolutePath.endsWith('/package-lock.json')) {
6351 await exec('npm install', absolutePath);
6352 } else if (absolutePath.endsWith('/yarn.lock')) {
6353 // Make sure that there is not a package-lock.json file in the same
6354 // directory.
6355 if (lockfiles.includes(lockfile.replace('yarn.lock', 'package-lock.json'))) {
6356 console.log('There is both a yarn.lock and package-lock.json in the same folder.');
6357 console.log('Please delete one of them.');
6358 process.exit(1);
6359 }
6360
6361 await exec('yarn', absolutePath);
6362 } else if (absolutePath.endsWith('/composer.lock')) {
6363 await exec('composer validate', absolutePath);
6364 await exec('composer install --no-interaction', absolutePath);
6365 } else {
6366 console.log('Unexpected file.');
6367 process.exit(1);
6368 }
6369 }
6370
6371 const {
6372 stdout: status
6373 } = await execa('git', ['status', '--porcelain']);
6374
6375 if (status) {
6376 console.log("\n\nAfter installations, some files were changed. That shouldn't happen.");
6377 console.log("It's about these files:");
6378 console.log(status);
6379 process.exit(1);
6380 }
6381 });
6382 }
6383
6384}
6385
6386function exec(cmd, path) {
6387 console.log(`\n\n$ ${cmd}\n\n`);
6388 const [bin, ...args] = cmd.split(' ');
6389 return execa(bin, args, {
6390 cwd: path$1.dirname(path),
6391 stdio: 'inherit',
6392 preferLocal: false,
6393 env: {
6394 NODE_ENV: 'development'
6395 }
6396 });
6397}
6398
6399const rimraf = util.promisify(rimrafWithCallback);
6400const stagedFiles = util.promisify(stagedFilesWithCallback);
6401const read$1 = util.promisify(fs.readFile);
6402const write$1 = util.promisify(fs.writeFile);
6403const append = util.promisify(fs.appendFile);
6404const removeFile = util.promisify(fs.unlink); // Always run Composer commands without memory limit.
6405
6406process.env.COMPOSER_MEMORY_LIMIT = '-1';
6407const databaseSettingsToAppend = `
6408$databases['default']['default'] = [
6409 'database' => getenv('MYSQL_DATABASE'),
6410 'username' => 'root',
6411 'password' => getenv('MYSQL_ROOT_PASSWORD'),
6412 'host' => 'mariadb',
6413 'port' => getenv('MARIADB_PORT_3306_TCP_PORT'),
6414 'driver' => 'mysql',
6415 'prefix' => '',
6416 'collation' => 'utf8mb4_general_ci',
6417];
6418`;
6419class UpdateDrupalCommand extends Command {
6420 constructor(...args) {
6421 super(...args);
6422
6423 _defineProperty(this, "command", 'update-drupal');
6424
6425 _defineProperty(this, "description", 'Updates a Drupal project to the latest versions of all modules');
6426
6427 _defineProperty(this, "options", [{
6428 flags: '--no-db',
6429 description: 'Do not download a fresh database and import it.'
6430 }, {
6431 flags: '--no-config',
6432 description: 'Only run composer requires and updates.'
6433 }]);
6434
6435 _defineProperty(this, "action", async ({
6436 db,
6437 config
6438 }) => {
6439 const apps = projectConfig.apps.filter(a => a.type === 'drupal');
6440
6441 if (!apps.length) {
6442 console.log('There were no Drupal apps found in the burst.yaml file.');
6443 }
6444
6445 for (const app of apps) {
6446 // We change the working directory to the directory of this app. This
6447 // way, all commands executed will be automatically executed in this
6448 // directory.
6449 process.chdir(app.path); // Get the Platform.sh project ID.
6450
6451 const platformHosting = app.hosting.find(h => h.type === 'platform');
6452 const platform = platformHosting ? platformHosting.id : undefined;
6453
6454 if (!platform) {
6455 console.log(`The Drupal app ${app.name} doesn't have a Platform hosting configured in the burst.yaml file.`);
6456 continue;
6457 } // Get the name of this Drupal app in Platform.
6458
6459
6460 const platformApp = yaml.safeLoad((await read$1(`${app.path}/.platform.app.yaml`, 'utf8'))).name;
6461
6462 if (typeof platformApp !== 'string') {
6463 throw new Error("Platform app yaml doesn't contain a valid name.");
6464 }
6465
6466 console.log(`
6467
6468 UPDATING DRUPAL
6469
6470 Path: ${app.path}
6471 Platform project: ${platform}
6472 Platform app name: ${platformApp}
6473
6474 `);
6475
6476 try {
6477 const composerLock = await this.readJsonFile(`${process.cwd()}/composer.lock`);
6478
6479 if (!composerLock.packages.some(p => p.name === 'drupal/core')) {
6480 throw new Error('The drupal/core package was not found.');
6481 }
6482 } catch (error) {
6483 console.log('We will not update this Drupal install, because:', error.message || error);
6484 continue;
6485 } // Unstage all changes, start with a clean slate. This is only for local stuff, in
6486 // Gitlab CI the slate should always be clean.
6487
6488
6489 await execa.command('git reset');
6490 await this.cleanComposer(); // There are some best practices that we want to have in every composer.json file.
6491
6492 await this.applyComposerConfig();
6493 await this.commit('build(drupal): change composer config', 'composer.json composer.lock'); // Now, install the whole site with Composer!
6494
6495 await this.cleanComposer();
6496 await this.logPromise('composer install', this.composer('install')); // At this phase, there should be nothing to commit. But if there is, it should be
6497 // in git. Probabily some scaffolded files that aren't committed.
6498
6499 await this.commit('build(drupal): add missing files');
6500 const devtool = process.env.MYSQL_DATABASE ? null : (await execa.command('ddev describe').catch(() => false)) ? 'ddev' : 'lando';
6501
6502 if (config) {
6503 // We need to start the Lando containers, if we're not in the CI.
6504 if (devtool) {
6505 await this.logPromise(`${devtool} start`, execa.command(`${devtool} start`));
6506 } else {
6507 // If we are in the CI, we need to add the database connection to the
6508 // settings.php file.
6509 const {
6510 all: statusString
6511 } = await this.drush(devtool, 'status --format=json');
6512 const status = JSON.parse(statusString);
6513 const settingsPath = `${status.root}/${status.site}/settings.php`;
6514 await append(settingsPath, databaseSettingsToAppend);
6515 this.actionsBeforeCommit.push(async () => write$1(settingsPath, (await read$1(settingsPath, 'utf8')).replace(databaseSettingsToAppend, '')));
6516 this.actionsAfterCommit.push(() => append(settingsPath, databaseSettingsToAppend));
6517 } // For debugging purposes, show the status.
6518
6519
6520 await this.logPromise('Logging result of "drush status"', this.drush(devtool, 'status', true));
6521
6522 if (db) {
6523 // We need a database! Get the latest datbase from Platform.
6524 await this.downloadDatabase(platform, platformApp); // Import the database, and remove the datbase from the file system. This
6525 // way, it's not accidentely committed.
6526
6527 await this.importDatabase(devtool);
6528 await rimraf(`${process.cwd()}/drupal--dump.sql`);
6529 } // We re-export the config. This shouldn't present any changes, but if it does, we
6530 // need to commit that first.
6531
6532
6533 await this.clearCache(devtool);
6534
6535 try {
6536 await this.exportConfig(devtool);
6537 await this.commit('fix(drupal): update config with latest production data');
6538 } catch (e) {
6539 console.log(e.all || e);
6540 console.log(`${chalk.bgRed('ERROR')} Re-exporting config failed. Let's just ignore this for now.`); // Reset the config folder to the latest git version.
6541
6542 await execa.command('git checkout -- config');
6543 }
6544 }
6545
6546 await this.logPromise('Changing php version in composer.json to the one defined in .platform.app.yaml', this.setPhpVersionsInComposer());
6547 await this.commit('Set php version to the version defined in .platform.app.yaml.');
6548 await this.logPromise('Removing legacy Burst distribution', this.removeLegacyBurstDistribution());
6549 await this.commit('refactor(drupal): remove legacy Burst distribution');
6550 await this.logPromise('Updating references to legacy Drupal distribution', this.upgradeReferencesToOldDrupalDistribution());
6551 await this.commit('refactor(drupal): update references to legacy Burst distribution');
6552 await this.addBurstDrupalDistribution(); // Now, we're going to do the actual updating.
6553
6554 await this.logPromise('updating drupal modules with composer', this.composer('update burst/drupal-distribution drupal/* --with-all-dependencies'));
6555
6556 if (config) {
6557 await this.clearCache(devtool);
6558 await this.accountForSlowDocker(devtool, () => this.logPromise('update database', this.drush(devtool, 'updb')));
6559
6560 try {
6561 await this.clearCache(devtool);
6562 await this.exportConfig(devtool);
6563 } catch (_unused) {
6564 await this.exportConfig(devtool);
6565 }
6566
6567 await this.commit('fix(drupal): update all drupal-related packages');
6568
6569 if (devtool) {
6570 await this.logPromise(`${devtool} stop`, execa.command(`${devtool} stop`));
6571 }
6572 }
6573 }
6574
6575 console.log('Done with all sites.');
6576 });
6577
6578 _defineProperty(this, "actionsBeforeCommit", []);
6579
6580 _defineProperty(this, "actionsAfterCommit", []);
6581
6582 _defineProperty(this, "log", {
6583 start(label) {
6584 console.time(label);
6585 console.log(chalk.bgYellow('START'), label);
6586 return () => {
6587 process.stdout.write(`${chalk.bgGreen('DONE')} `);
6588 console.timeEnd(label);
6589 };
6590 }
6591
6592 });
6593 }
6594
6595 async applyComposerConfig() {
6596 const l = this.log.start('Applying composer best practices');
6597 await this.composer('config minimum-stability dev');
6598 await this.composer('config prefer-stable true');
6599 await this.composer('config discard-changes true');
6600 await this.composer('config sort-packages true');
6601 await this.composer('config extra.enable-patching true');
6602 await this.composer('config extra.composer-exit-on-patch-failure true');
6603 await this.composer('config extra.drupal-scaffold.locations web-root.web');
6604 const composerFile = `${process.cwd()}/composer.json`;
6605 await write$1(composerFile, (await read$1(composerFile, 'utf8')).replace(`"enable-patching": "true"`, `"enable-patching": true`).replace(`"composer-exit-on-patch-failure": "true"`, `"composer-exit-on-patch-failure": true`).replace(`"locations": "web-root.web"`, `"locations": {"web-root": "web"}`));
6606 await this.composer('update --lock');
6607 l();
6608 }
6609
6610 async downloadDatabase(project, app, schema) {
6611 try {
6612 await this.logPromise('database download', execa.command(`platform db:dump --project ${project} --environment master --directory . --file drupal--dump.sql --app ${app}${schema ? ` --schema ${schema}` : ''} --yes`));
6613 } catch (error) {
6614 if (schema) throw error;
6615
6616 if (typeof error.stderr === 'string') {
6617 const errMatch = error.stderr.match(/Available schemas: ([^ ]*), /);
6618
6619 if (errMatch) {
6620 console.log(`There is not a default database configured. Using database ${errMatch[1]}.`);
6621 await this.downloadDatabase(project, app, errMatch[1]);
6622 return;
6623 }
6624 }
6625
6626 throw error;
6627 }
6628 }
6629
6630 async importDatabase(devtool) {
6631 if (devtool) {
6632 await this.logPromise('database import', execa.command(devtool === 'lando' ? 'lando db-import drupal--dump.sql' : 'ddev import-db --src=drupal--dump.sql'));
6633 } else {
6634 const connectionCommand = await this.drush(devtool, 'sql-connect');
6635 await this.logPromise('database import', execa.command(`${connectionCommand.all} < drupal--dump.sql`, {
6636 shell: true
6637 }));
6638 }
6639 }
6640
6641 async setPhpVersionsInComposer() {
6642 const composerJson = await this.readJsonFile(`${process.cwd()}/composer.json`);
6643
6644 try {
6645 const platformYaml = await read$1(`${process.cwd()}/.platform.app.yaml`, 'utf8');
6646 const platform = yaml.safeLoad(platformYaml);
6647 if (typeof platform.type !== 'string' || !platform.type.startsWith('php:')) throw new Error();
6648 const phpVersion = `${platform.type.substr(4)}.999`;
6649 let somethingChanged = false;
6650 if (!composerJson.config) composerJson.config = {};
6651 if (!composerJson.config.platform) composerJson.config.platform = {};
6652
6653 if (composerJson.config.platform.php !== phpVersion) {
6654 somethingChanged = true;
6655 composerJson.config.platform.php = phpVersion;
6656 }
6657
6658 Object.entries(composerJson.config.platform).forEach(([d, v]) => {
6659 if (d.startsWith('ext-') && typeof v === 'string' && v.startsWith('7.') && composerJson.config.platform[d] !== phpVersion) {
6660 somethingChanged = true;
6661 composerJson.config.platform[d] = phpVersion;
6662 }
6663 });
6664
6665 if (somethingChanged) {
6666 await write$1(`${process.cwd()}/composer.json`, JSON.stringify(composerJson));
6667 await this.composer('update --lock');
6668 }
6669 } catch (e) {
6670 console.log('Could not detect php version in .platform.app.yaml and set it in composer.json.');
6671 console.log(e);
6672 }
6673 }
6674
6675 async removeLegacyBurstDistribution() {
6676 const composerJson = await this.readJsonFile(`${process.cwd()}/composer.json`);
6677 const composerLock = await this.readJsonFile(`${process.cwd()}/composer.lock`);
6678 const burstDistribution = composerLock.packages.find(p => p.name === 'burst/drupal-distribution');
6679 const hnDistribution = composerLock.packages.find(p => p.name === 'headless-ninja/drupal-distribution');
6680
6681 if (burstDistribution && !hnDistribution) {
6682 console.log('There was not a legacy version of the Burst distribution found that needs migration.');
6683 return;
6684 }
6685
6686 if (burstDistribution) {
6687 console.log('Found a legacy version of the Burst distribution that will be removed.');
6688 const requiredPackagesByDists = [...Object.entries(burstDistribution.require), ...Object.entries(hnDistribution.require)]; // This requires all packages to the root composer.json that are
6689 // already required by one of the distributions, but do not exist
6690 // in the root composer.json already.
6691
6692 await this.logPromise('Adding packages of legacy Burst distribution to the root composer.json', this.composer(`require ${requiredPackagesByDists.filter(([p]) => p !== 'headless-ninja/drupal-distribution' && !Object.keys(composerJson.require).includes(p)).map(([p, v]) => `"${p}:${v}"`).join(' ')} --no-update`, {
6693 shell: true
6694 })); // This removes the old distribution.
6695
6696 await this.composer('remove burst/drupal-distribution');
6697 await this.applyComposerConfig();
6698 }
6699 }
6700
6701 async upgradeReferencesToOldDrupalDistribution() {
6702 let composerJson = await this.readJsonFile(`${process.cwd()}/composer.json`);
6703 const composerLock = await this.readJsonFile(`${process.cwd()}/composer.lock`);
6704 await this.upgradeDistributionSettingsCall();
6705
6706 if (composerLock.packages.some(p => p.name === 'drupal-composer/drupal-scaffold')) {
6707 composerJson = await this.readJsonFile(`${process.cwd()}/composer.json`);
6708
6709 if (typeof composerJson.scripts === 'object') {
6710 let removedScripts = ['__NONE_YET__'];
6711
6712 while (removedScripts.length) {
6713 const removeScripts = removedScripts;
6714 removedScripts = [];
6715 Object.entries(composerJson.scripts).forEach(([key, value]) => {
6716 const newValue = (Array.isArray(value) ? value : [value]).filter(s => !s.startsWith('DrupalProject\\') && !s.startsWith('DrupalComposer\\') && !(s.includes('drupal') && s.includes('scaffold')) && !removeScripts.some(r => s === `@${r}`)); // eslint-disable-next-line prefer-destructuring
6717
6718 if (newValue.length === 1) composerJson.scripts[key] = newValue[0];else if (newValue.length) composerJson.scripts[key] = newValue;else {
6719 delete composerJson.scripts[key];
6720 removedScripts.push(key);
6721 }
6722 });
6723 }
6724 }
6725
6726 if (composerJson.autoload && Array.isArray(composerJson.autoload.classmap)) {
6727 composerJson.autoload.classmap = composerJson.autoload.classmap.filter(c => c !== 'scripts/composer/ScriptHandler.php');
6728 if (composerJson.autoload.classmap.length === 0) delete composerJson.autoload.classmap;
6729 if (Object.keys(composerJson.autoload).length === 0) delete composerJson.autoload;
6730 }
6731
6732 if (!composerJson.extra) composerJson.extra = {};
6733 composerJson.extra['drupal-scaffold'] = {
6734 locations: {
6735 'web-root': 'web'
6736 }
6737 };
6738 await write$1(`${process.cwd()}/composer.json`, JSON.stringify(composerJson));
6739 }
6740 }
6741
6742 async getLatestDrupalDistribution() {
6743 const {
6744 data
6745 } = await axios.get('https://repo.packagist.org/p/burst/drupal-distribution.json');
6746 const lastVersion = Object.keys(data.packages['burst/drupal-distribution']).filter(v => semver__default.valid(v) && !semver__default.prerelease(v)).sort(semver__default.rcompare)[0];
6747 return data.packages['burst/drupal-distribution'][lastVersion];
6748 }
6749
6750 async addBurstDrupalDistribution() {
6751 const latest = await this.getLatestDrupalDistribution();
6752 const packagesInLatest = [// In the last version of the Burst distribution
6753 ...Object.keys(latest.require), // Not needed anymore
6754 'drupal-composer/drupal-scaffold', 'drupal/console'];
6755 const composerJson = await this.readJsonFile(`${process.cwd()}/composer.json`);
6756 const rootRequirements = Object.keys(composerJson.require);
6757 const packagesThatShouldBeRemoved = rootRequirements.filter(pkg => packagesInLatest.includes(pkg));
6758
6759 if (!packagesThatShouldBeRemoved.length) {
6760 console.log('There are no packages that are part of the latest Burst distribution, that are currently a requirement and should be removed.');
6761 } else {
6762 try {
6763 await this.logPromise('Remove packages that are part of the latest Burst distribution', this.composer(`remove ${packagesThatShouldBeRemoved.join(' ')}`));
6764 } catch (_unused2) {
6765 console.log("Couldn't remove these packages using the 'remove' command. Trying again with --no-update-with-dependencies");
6766
6767 try {
6768 await this.logPromise('Remove packages that are part of the latest Burst distribution', this.composer(`remove ${packagesThatShouldBeRemoved.join(' ')} --no-update-with-dependencies`));
6769 } catch (_unused3) {
6770 console.log("Couldn't remove these packages using the 'remove --no-update-with-dependencies' command. Trying again with --no-update");
6771 await this.logPromise('Remove packages that are part of the latest Burst distribution', this.composer(`remove ${packagesThatShouldBeRemoved.join(' ')} --no-update`));
6772 }
6773 }
6774 }
6775
6776 const burstDistIsInstalled = rootRequirements.includes('burst/drupal-distribution');
6777
6778 try {
6779 await this.logPromise('Require latest Burst distribution', this.composer(`require burst/drupal-distribution:^${latest.version} --update-with-all-dependencies`));
6780
6781 if (!burstDistIsInstalled) {
6782 await this.commit('feat(drupal): add Burst distribution');
6783 }
6784 } catch (error) {
6785 if (!burstDistIsInstalled) throw error;
6786 console.log('Could not require latest burst/drupal-distribution. But just updating the current one could suffice.');
6787 }
6788 }
6789
6790 async upgradeDistributionSettingsCall() {
6791 // Find all calls to burst_distribution_settings();
6792 const files = await execa.command('git grep -l burst_distribution_settings', {
6793 reject: false
6794 });
6795 await Promise.all(files.stdout.split('\n').filter(Boolean).map(relativeFile => `${process.cwd()}/${relativeFile}`).map(async absoluteFile => this.logPromise(`Rewriting burst_distribution_settings() call in file ${absoluteFile}`, write$1(absoluteFile, (await read$1(absoluteFile, 'utf8')).replace(/burst_distribution_settings\([^)]*\)/g, `require_once __DIR__ . '/${path$1.relative(path$1.dirname(absoluteFile), `${process.cwd()}/web/profiles/contrib/burst-drupal-distribution/includes/settings.php`)}'`))).catch(() => {// The error will be logged, and we will continue.
6796 })));
6797 }
6798
6799 async drush(devtool, drushCommand, echo = false) {
6800 const drush = devtool === 'ddev' ? 'ddev . drush' : devtool === 'lando' ? 'lando drush' : `drush --root=${process.cwd()}`;
6801 const cmd = `${drush} -y ${drushCommand}`;
6802
6803 if (echo) {
6804 await execa.command(cmd, {
6805 stdio: 'inherit'
6806 });
6807 return null;
6808 }
6809
6810 return execa.command(cmd);
6811 }
6812
6813 cleanComposer() {
6814 return Promise.all([rimraf(`${process.cwd()}/vendor`), rimraf(`${process.cwd()}/web/composer.json`), rimraf(`${process.cwd()}/web/composer.lock`), rimraf(`${process.cwd()}/web/core`), rimraf(`${process.cwd()}/web/modules/contrib`), rimraf(`${process.cwd()}/web/themes/contrib`), rimraf(`${process.cwd()}/web/profiles/contrib`), rimraf(`${process.cwd()}/drush/contrib`)]);
6815 }
6816
6817 async composer(command, options = {}, retryCount = 0) {
6818 try {
6819 const res = await execa.command(`composer ${command} --ansi${command.startsWith('install') || command.startsWith('require') || command.startsWith('update') ? ' --no-progress --no-suggest' : ''}`, options);
6820
6821 if (retryCount > 0) {
6822 console.log('This time, the command succeeded.');
6823 }
6824
6825 return res;
6826 } catch (err) {
6827 const log = err && err.all;
6828 if (!log) throw err; // Match this log: https://github.com/cweagans/composer-patches/blob/9a08b4defec6f7fefed0d56051fe710d60e99652/src/Plugin/Patches.php#L338
6829
6830 const cannotApplyMatch = log.match(/Cannot apply patch .* \(([^)]*)\)!/);
6831
6832 if (cannotApplyMatch && retryCount > 0) {
6833 console.log(`Composer fails to apply patch ${cannotApplyMatch[1]}`);
6834 const composerJson = await this.readJsonFile(`${process.cwd()}/composer.json`);
6835 let composerJsonChanged = false;
6836
6837 if (typeof composerJson === 'object' && typeof composerJson.extra === 'object' && typeof composerJson.extra.patches === 'object') {
6838 const {
6839 patches
6840 } = composerJson.extra;
6841 Object.keys(patches).forEach(module => {
6842 if (typeof patches[module] === 'object') {
6843 Object.keys(patches[module]).forEach(patchName => {
6844 if (patches[module][patchName] === cannotApplyMatch[1]) {
6845 composerJsonChanged = true;
6846 delete patches[module][patchName];
6847 }
6848 });
6849
6850 if (Object.keys(patches[module]).length === 0) {
6851 delete patches[module];
6852 }
6853 }
6854 });
6855 }
6856
6857 if (composerJsonChanged) {
6858 await write$1(`${process.cwd()}/composer.json`, JSON.stringify(composerJson));
6859 console.log(`Removed patch ${cannotApplyMatch[1]}`); // This makes sure that every package will be re-installed the next run.
6860
6861 await this.cleanComposer(); // Something changed, so reset the retryCount.
6862
6863 return this.composer(command, options);
6864 }
6865
6866 console.log(`Could not find patch ${cannotApplyMatch[1]}, so can't fix.`);
6867 }
6868
6869 if (retryCount < 3 && (cannotApplyMatch || log.includes("Uncaught Error: Class 'cweagans\\Composer\\PatchEvent' not found") || log.includes('Could not scan for classes inside '))) {
6870 console.log("Composer command failed because of a common error (so we don't show the full output).");
6871 } else {
6872 // Show the formatted output that Composer generated.
6873 console.log(log);
6874 console.log(`\n\n\nThe composer command failed: ${command}`);
6875 }
6876
6877 if (retryCount < 3) {
6878 console.log('Deleting all composer folders...');
6879 await this.cleanComposer();
6880 console.log(`Re-running command (retry ${retryCount + 1})...`);
6881 return this.composer(command, options, retryCount + 1);
6882 }
6883
6884 if (command.startsWith('require') && (await this.readJsonFile(`${process.cwd()}/composer.lock`).catch(() => null))) {
6885 console.log('Taking drastic measures... deleting composer.lock..');
6886 await removeFile(`${process.cwd()}/composer.lock`);
6887 return this.composer(command, options);
6888 }
6889
6890 throw err;
6891 }
6892 }
6893
6894 async accountForSlowDocker(devtool, promise) {
6895 try {
6896 return await promise();
6897 } catch (e) {
6898 if (!devtool) throw e;
6899 console.log('Retry in 40 seconds (could be slow Docker sync)');
6900 await new Promise(r => setTimeout(r, 40 * 1000));
6901 return promise();
6902 }
6903 }
6904
6905 async clearCache(devtool) {
6906 await this.accountForSlowDocker(devtool, () => this.logPromise('cache clear', this.drush(devtool, 'cache-rebuild')));
6907 }
6908
6909 async commit(msg, filesToAdd = '--all') {
6910 await Promise.all(this.actionsBeforeCommit.map(a => a()));
6911
6912 try {
6913 await execa.command(`git add ${filesToAdd}`);
6914
6915 if (!(await stagedFiles()).length) {
6916 throw new Error('Nothing to commit');
6917 }
6918
6919 await this.logPromise('Linting & fixing changed files', execa.command(`${process.argv0} ${process.argv[1]} lint --fix --staged`, {
6920 reject: false
6921 }));
6922
6923 if (!(await stagedFiles()).length) {
6924 throw new Error('Nothing to commit');
6925 }
6926
6927 const {
6928 all
6929 } = await execa('git', ['commit', `-m ${msg}`, '--author="Bart Langelaan <bart@burst-digital.com>"', '--no-verify']);
6930 console.log(`\n\n${chalk.bgBlue('COMMIT')} ${all}\n\n`);
6931 } catch (err) {
6932 console.log(chalk.bgBlue('SKIPPED COMMIT'), err.all || err.message || err);
6933 }
6934
6935 await Promise.all(this.actionsAfterCommit.map(a => a()));
6936 }
6937
6938 async exportConfig(devtool) {
6939 await rimraf(`${process.cwd()}/config/**/*.yml`);
6940 await this.logPromise('config export', this.drush(devtool, 'config-export'));
6941 }
6942
6943 async readJsonFile(file) {
6944 return JSON.parse((await read$1(file, 'utf8')));
6945 }
6946
6947 async logPromise(label, promise) {
6948 const promiseDone = this.log.start(label);
6949
6950 try {
6951 const p = await promise;
6952 promiseDone();
6953 return p;
6954 } catch (e) {
6955 process.stdout.write(`${chalk.bgRed('ERROR')} `);
6956 console.timeEnd(label);
6957 throw e;
6958 }
6959 }
6960
6961}
6962
6963const isCI$4 = require('is-ci');
6964
6965class TestCommand extends Command {
6966 constructor(...args) {
6967 super(...args);
6968
6969 _defineProperty(this, "command", 'test');
6970
6971 _defineProperty(this, "description", 'Uses testcafe to execute all tests in this repository');
6972
6973 _defineProperty(this, "options", [{
6974 flags: '--browsers <browserlist>',
6975 description: 'Define a comma separated list of browsers to run tests on. Will default to all installed browsers.'
6976 }]);
6977
6978 _defineProperty(this, "action", async ({
6979 browsers = ''
6980 }) => {
6981 try {
6982 console.log('\n\n');
6983 const root = getRepoRoot();
6984
6985 if (!(await exists(`${root}/tests/testcafe`))) {
6986 throw new Error('There does not exist a directory /tests/testcafe in the root of this reporitory. This is currently the only place where tests can be placed.');
6987 }
6988
6989 if (isCI$4) {
6990 console.log('INSTALLING NPM DEPENDENCIES');
6991 console.log('(should contain testcafe)');
6992 await execa.command('npm i', {
6993 cwd: root,
6994 stdio: 'inherit'
6995 });
6996 }
6997
6998 let testBrowsers = browsers || isCI$4 && 'firefox:headless,chromium:headless';
6999
7000 if (!testBrowsers) {
7001 console.log('Checking installed browsers...');
7002 testBrowsers = (await execa.command('testcafe --list-browsers', {
7003 preferLocal: true
7004 })).stdout.split('\n').join(',');
7005 }
7006
7007 console.log(`Will test on these browsers: ${testBrowsers}`);
7008 const extraArgs = isCI$4 ? ' --reporter slack-errors-only' : '';
7009 await execa.command(`testcafe ${testBrowsers} tests/testcafe/**/* ${extraArgs}`, {
7010 preferLocal: true,
7011 stdio: 'inherit',
7012 env: {
7013 TESTCAFE_SLACK_CHANNEL: 'test-reports',
7014 TESTCAFE_SLACK_BOT: 'TestCafé Bot'
7015 }
7016 });
7017 } catch (error) {
7018 if (isCI$4) {
7019 console.log('A fatal error occured. Alerting in Slack...');
7020 await sendTestFailedMessage(error).catch(e => console.error(e));
7021 }
7022
7023 throw error;
7024 }
7025 });
7026 }
7027
7028}
7029
7030class StartCommand extends Command {
7031 constructor(...args) {
7032 super(...args);
7033
7034 _defineProperty(this, "command", 'start');
7035
7036 _defineProperty(this, "description", 'Start apps on your local environment.');
7037 }
7038
7039 async action() {
7040 const one = ink.render(React__default.createElement(StartInstall, null));
7041 await one.waitUntilExit();
7042 one.cleanup();
7043 const two = ink.render(React__default.createElement(ink.Box, {
7044 marginTop: 1
7045 }, React__default.createElement(ink.Text, {
7046 bold: true
7047 }, "Step 2 - Scaffold project")));
7048 two.unmount();
7049 await new ScaffoldCommand().action();
7050 const three = ink.render(React__default.createElement(DownloadMounts, null));
7051 await three.waitUntilExit();
7052 three.cleanup();
7053 const four = ink.render(React__default.createElement(StartDdevs, null));
7054 await four.waitUntilExit();
7055 four.cleanup();
7056 const five = ink.render(React__default.createElement(ink.Box, {
7057 marginTop: 1
7058 }, React__default.createElement(ink.Text, {
7059 bold: true
7060 }, "Step 5 - Sync database from Platform.sh")));
7061 five.unmount();
7062 await new SyncPlatformToDdevCommand().action();
7063 const six = ink.render(React__default.createElement(ink.Box, {
7064 marginTop: 1
7065 }, React__default.createElement(ink.Text, {
7066 bold: true
7067 }, "Step 6 - Profit!")));
7068 six.unmount();
7069 }
7070
7071}
7072
7073function StartInstall() {
7074 const [lockfiles, setLockfiles] = React.useState();
7075 React.useEffect(() => {
7076 getListOfRepoFiles(['package-lock.json', '*/package-lock.json', 'yarn.lock', '*/yarn.lock', 'composer.lock', '*/composer.lock'], true).then(f => setLockfiles(f));
7077 }, []);
7078 const [lockfileResults, setLockfileResults] = React.useState([]);
7079 const onLockfileComplete = React.useCallback(success => {
7080 setLockfileResults(r => [...r, success]);
7081 }, []);
7082 useExit(!!lockfiles && lockfileResults.length === lockfiles.length);
7083 return React__default.createElement(ink.Box, {
7084 flexDirection: "column"
7085 }, React__default.createElement(ink.Text, {
7086 bold: true
7087 }, "Step 1 - Install dependencies"), !lockfiles ? React__default.createElement(ink.Text, {
7088 italic: true
7089 }, "Finding lockfiles in repository...") : lockfiles.map(file => React__default.createElement(InstallLockfile, {
7090 file: file,
7091 key: file,
7092 onComplete: onLockfileComplete
7093 })));
7094}
7095
7096function InstallLockfile(props) {
7097 const absolutePath = `${repoRoot}/${props.file}`;
7098 const command = absolutePath.endsWith('/package-lock.json') ? 'npm i' : absolutePath.endsWith('/yarn.lock') ? 'yarn' : 'composer install --no-interaction';
7099 const [install, setInstall] = React.useState();
7100 React.useEffect(() => {
7101 execa.command(command, {
7102 cwd: path$1.dirname(absolutePath),
7103 env: {
7104 NODE_ENV: 'development'
7105 },
7106 reject: false
7107 }).then(r => setInstall(r));
7108 }, [absolutePath, command]);
7109 const {
7110 onComplete
7111 } = props;
7112 React.useEffect(() => {
7113 if (install) onComplete(!install.failed);
7114 }, [install, onComplete]);
7115 return React__default.createElement(ink.Text, null, "Running ", React__default.createElement(ink.Text, {
7116 color: "cyan"
7117 }, command), " for", ' ', React__default.createElement(ink.Text, {
7118 color: "cyan"
7119 }, props.file), !install ? React__default.createElement(ink.Text, null, "...") : install.failed ? ' failed.' : ' completed.');
7120}
7121
7122function DownloadMounts() {
7123 const ddevConfig = React.useMemo(() => getDdevConfigurations(), []);
7124 const [downloadResults, setDownloadResults] = React.useState([]);
7125 const onDownloadComplete = React.useCallback(success => {
7126 setDownloadResults(r => [...r, success]);
7127 }, []);
7128 useExit(downloadResults.length === ddevConfig.length);
7129 return React__default.createElement(ink.Box, {
7130 flexDirection: "column",
7131 marginTop: 1
7132 }, React__default.createElement(ink.Text, {
7133 bold: true
7134 }, "Step 3 - Download files from Platform.sh"), ddevConfig.map((c, i) => // eslint-disable-next-line react/no-array-index-key
7135 React__default.createElement(DownloadMount, {
7136 config: c,
7137 key: i,
7138 onComplete: onDownloadComplete
7139 })));
7140}
7141
7142function DownloadMount(props) {
7143 const cmd = `platform mount:download --project=${props.config.platformProject} --environment=master --app=${props.config.platformApp} --all --target=${props.config.app.path}`;
7144 const download = useExeca(cmd);
7145 const {
7146 onComplete
7147 } = props;
7148 React.useEffect(() => {
7149 if (download) onComplete(!download.failed);
7150 }, [download, onComplete]);
7151 return React__default.createElement(ink.Text, null, "Files of app ", React__default.createElement(ink.Text, {
7152 color: "cyan"
7153 }, props.config.platformApp), " are", ' ', !download ? 'downloading...' : download.failed ? `not downloaded, because of a failure.\nYou can try to run this command manually:\n${cmd}\n` : 'downloaded!');
7154}
7155
7156function StartDdevs() {
7157 const ddevConfig = React.useMemo(() => getDdevConfigurations(), []);
7158 const [downloadResults, setDownloadResults] = React.useState([]);
7159 const onDownloadComplete = React.useCallback(success => {
7160 setDownloadResults(r => [...r, success]);
7161 }, []);
7162 useExit(downloadResults.length === ddevConfig.length);
7163 return React__default.createElement(ink.Box, {
7164 flexDirection: "column",
7165 marginTop: 1
7166 }, React__default.createElement(ink.Text, {
7167 bold: true
7168 }, "Step 4 - Start ddev apps"), ddevConfig.map((c, i) => React__default.createElement(StartDdev, {
7169 cwd: c.projectRoot // eslint-disable-next-line react/no-array-index-key
7170 ,
7171 key: i,
7172 onComplete: onDownloadComplete
7173 })));
7174}
7175
7176function StartDdev(props) {
7177 const download = useExeca('ddev start', React.useMemo(() => ({
7178 cwd: props.cwd
7179 }), [props.cwd]));
7180 const {
7181 onComplete
7182 } = props;
7183 React.useEffect(() => {
7184 if (download) onComplete(!download.failed);
7185 }, [download, onComplete]);
7186 return React__default.createElement(ink.Text, null, "Ddev in ", React__default.createElement(ink.Text, {
7187 color: "cyan"
7188 }, props.cwd), !download ? ' starting...' : download.failed ? ` did not start, because of a failure.\nYou can try to run 'ddev start' manually.` : ' started!');
7189}
7190
7191/**
7192 * All available commands are listed here.
7193 */
7194
7195const commands = [CheckCommand, LintCommand, DeployCommand, ScaffoldCommand, PrepareCICommand, InstallCommand, UpdateDrupalCommand, TestCommand, SyncPlatformToDdevCommand, StartCommand];
7196/**
7197 * This registers all commands to commander.
7198 */
7199
7200function registerCommands(commander) {
7201 commands.forEach(CommandClass => {
7202 // Create an instance of the command class.
7203 const command = new CommandClass(); // Declare the command and it's description from the instance.
7204
7205 const commanderCommand = commander.command(command.command).description(command.description); // All commands should execute the 'checkFirst' function, except the 'check' command.
7206
7207 if (command.command === 'check') {
7208 commanderCommand.action(command.action);
7209 } else {
7210 commanderCommand.action(checkFirst(command.action));
7211 } // Add all options to the command.
7212
7213
7214 command.options.forEach(opt => commanderCommand.option(opt.flags, opt.description));
7215 });
7216}
7217
7218/* eslint-disable no-console */
7219process.stdout.columns = process.stdout.columns || 80; // Add the current version to the commander instance. This is used when
7220// running `burst --version`.
7221
7222const pkg = require('../package.json');
7223
7224commander.version(pkg.version); // Add all available commands to the commander.
7225// You can see all available commands in ./commands/index.tsx.
7226
7227registerCommands(commander); // When the command isn't found, show an error.
7228
7229commander.on('command:*', checkFirst(() => {
7230 console.log(chalk`Command {magenta ${commander.args.join(' ')}} not found.`);
7231 process.exit(1);
7232})); // Parse the argumens passed to the process. This actually executes the
7233// registered commands.
7234
7235commander.parse(process.argv); // If there was no command entered (just 'burst'), show help.
7236
7237if (!process.argv.slice(2).length) {
7238 commander.help();
7239}