UNPKG

9.82 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, '__esModule', { value: true });
4
5function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
6
7var consola = _interopDefault(require('consola'));
8var child_process = require('child_process');
9var chalk = _interopDefault(require('chalk'));
10var path = _interopDefault(require('path'));
11var fs = _interopDefault(require('fs'));
12var fetch = _interopDefault(require('node-fetch'));
13
14const reportAndThrowError = msg => {
15 report(msg);
16 throw new Error(msg);
17};
18const report = message => {
19 consola.fatal({
20 message: String(message),
21 tag: 'opencollective'
22 });
23};
24const hideMessage = (env = process.env) => {
25 // Show message if it is forced
26 if (env.OPENCOLLECTIVE_FORCE) {
27 return false;
28 } // Don't show after oracle postinstall
29
30
31 if (env.OC_POSTINSTALL_TEST) {
32 return true;
33 } // Don't show if opted-out
34
35
36 if (env.OPENCOLLECTIVE_HIDE) {
37 return true;
38 } // Don't show if on CI
39
40
41 if (env.CI || env.CONTINUOUS_INTEGRATION) {
42 return true;
43 } // Only show in dev environment
44
45
46 return Boolean(env.NODE_ENV) && !['dev', 'development'].includes(env.NODE_ENV);
47};
48const formatMoney = currency => amount => {
49 amount = amount / 100; // converting cents
50
51 const precision = 0;
52 return amount.toLocaleString(currency, {
53 style: 'currency',
54 currency: currency,
55 minimumFractionDigits: precision,
56 maximumFractionDigits: precision
57 });
58};
59const isWin32 = process.platform === 'win32';
60const stripLeadingSlash = s => s.startsWith('/') ? s.substring(1) : s;
61const stripTrailingSlash = s => s.endsWith('/') ? s.slice(0, -1) : s;
62
63/* eslint-disable no-console */
64const print = (color = null) => (str = '') => {
65 const terminalCols = retrieveCols();
66 const strLength = str.replace(/\u001b\[[0-9]{2}m/g, '').length;
67 const leftPaddingLength = Math.floor((terminalCols - strLength) / 2);
68 const leftPadding = ' '.repeat(Math.max(leftPaddingLength, 0));
69
70 if (color) {
71 str = chalk[color](str);
72 }
73
74 console.log(leftPadding, str);
75};
76const retrieveCols = (() => {
77 let result = false;
78 return () => {
79 if (result) {
80 return result;
81 }
82
83 const defaultCols = 80;
84
85 try {
86 const terminalCols = child_process.execSync(`tput cols`, {
87 stdio: ['pipe', 'pipe', 'ignore']
88 });
89 result = parseInt(terminalCols.toString()) || defaultCols;
90 } catch (e) {
91 result = defaultCols;
92 }
93
94 return result;
95 };
96})();
97const printStats = (stats, color) => {
98 if (!stats) {
99 return;
100 }
101
102 const colored = print(color);
103 const bold = print('bold');
104 const formatWithCurrency = formatMoney(stats.currency);
105 colored(`Number of contributors: ${stats.contributorsCount}`);
106 colored(`Number of backers: ${stats.backersCount}`);
107 colored(`Annual budget: ${formatWithCurrency(stats.yearlyIncome)}`);
108 bold(`Current balance: ${formatWithCurrency(stats.balance)}`, 'bold');
109};
110const printLogo = logoText => {
111 if (!logoText) {
112 return;
113 }
114
115 logoText.split('\n').forEach(print('blue'));
116};
117/**
118 * Only show emoji on OSx (Windows shell doesn't like them that much ¯\_(ツ)_/¯ )
119 * @param {*} emoji
120 */
121
122const emoji = emoji => process.stdout.isTTY && !isWin32 ? emoji : '';
123function printFooter(collective) {
124 const dim = print('dim');
125 const yellow = print('yellow');
126 const emptyLine = print();
127 yellow(`Thanks for installing ${collective.slug} ${emoji('🙏')}`);
128 dim(`Please consider donating to our open collective`);
129 dim(`to help us maintain this package.`);
130 emptyLine();
131 printStats(collective.stats);
132 emptyLine();
133 print()(`${chalk.bold(`${emoji('👉 ')} ${collective.donationText}`)} ${chalk.underline(collective.donationUrl)}`);
134 emptyLine();
135}
136
137function _slicedToArray(arr, i) {
138 return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest();
139}
140
141function _arrayWithHoles(arr) {
142 if (Array.isArray(arr)) return arr;
143}
144
145function _iterableToArrayLimit(arr, i) {
146 var _arr = [];
147 var _n = true;
148 var _d = false;
149 var _e = undefined;
150
151 try {
152 for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
153 _arr.push(_s.value);
154
155 if (i && _arr.length === i) break;
156 }
157 } catch (err) {
158 _d = true;
159 _e = err;
160 } finally {
161 try {
162 if (!_n && _i["return"] != null) _i["return"]();
163 } finally {
164 if (_d) throw _e;
165 }
166 }
167
168 return _arr;
169}
170
171function _nonIterableRest() {
172 throw new TypeError("Invalid attempt to destructure non-iterable instance");
173}
174
175const fetchJson = url => new Promise(function ($return, $error) {
176 var $Try_1_Post = function () {
177 try {
178 return $return();
179 } catch ($boundEx) {
180 return $error($boundEx);
181 }
182 };
183
184 var $Try_1_Catch = function (e) {
185 try {
186 report(e);
187 reportAndThrowError(`Could not fetch ${url}.json`);
188 return $Try_1_Post();
189 } catch ($boundEx) {
190 return $error($boundEx);
191 }
192 };
193
194 try {
195 return Promise.resolve(global.fetch(`${url}.json`)).then(function ($await_5) {
196 try {
197 return $return($await_5.json());
198 } catch ($boundEx) {
199 return $Try_1_Catch($boundEx);
200 }
201 }, $Try_1_Catch);
202 } catch (e) {
203 $Try_1_Catch(e);
204 }
205});
206
207const fetchStats = collectiveUrl$$1 => new Promise(function ($return, $error) {
208 var $Try_2_Post = function () {
209 try {
210 return $return();
211 } catch ($boundEx) {
212 return $error($boundEx);
213 }
214 };
215
216 var $Try_2_Catch = function (e) {
217 try {
218 report(e);
219 report(`Could not load the stats for ${collectiveSlugFromUrl(collectiveUrl$$1)}`);
220 return $Try_2_Post();
221 } catch ($boundEx) {
222 return $error($boundEx);
223 }
224 };
225
226 try {
227 return Promise.resolve(fetchJson(collectiveUrl$$1)).then($return, $Try_2_Catch);
228 } catch (e) {
229 $Try_2_Catch(e);
230 }
231});
232const fetchLogo = logoUrl => new Promise(function ($return, $error) {
233 if (!logoUrl) {
234 // Silent return if no logo has been provided
235 return $return();
236 }
237
238 if (!logoUrl.match(/^https?:\/\//)) {
239 reportAndThrowError(`Your logo URL isn't well-formatted - ${logoUrl}`);
240 }
241
242 var $Try_3_Post = function () {
243 try {
244 return $return();
245 } catch ($boundEx) {
246 return $error($boundEx);
247 }
248 };
249
250 var $Try_3_Catch = function (e) {
251 try {
252 report(`Error while fetching logo from ${logoUrl}`);
253 return $Try_3_Post();
254 } catch ($boundEx) {
255 return $error($boundEx);
256 }
257 };
258
259 try {
260 let res;
261 return Promise.resolve(global.fetch(logoUrl)).then(function ($await_7) {
262 try {
263 res = $await_7;
264
265 if (isLogoResponseWellFormatted(res)) {
266 return $return(res.text());
267 }
268
269 report(`Error while fetching logo from ${logoUrl}. The response wasn't well-formatted`);
270 return $Try_3_Post();
271 } catch ($boundEx) {
272 return $Try_3_Catch($boundEx);
273 }
274 }, $Try_3_Catch);
275 } catch (e) {
276 $Try_3_Catch(e);
277 }
278});
279
280const isLogoResponseWellFormatted = res => res.status === 200 && res.headers.get('content-type').match(/^text\/plain/);
281
282const fetchPkg = pathToPkg => {
283 const fullPathToPkg = path.resolve(`${pathToPkg}/package.json`);
284
285 try {
286 return JSON.parse(fs.readFileSync(fullPathToPkg, 'utf8'));
287 } catch (e) {
288 reportAndThrowError(`Could not find package.json at ${fullPathToPkg}`);
289 }
290};
291
292const collectiveSlugFromUrl = url => url.substr(url.lastIndexOf('/') + 1).toLowerCase().replace(/\.json/g, '');
293const collectiveUrl = pkg => {
294 const url = pkg.collective && pkg.collective.url;
295
296 if (!url) {
297 reportAndThrowError('No collective URL set!');
298 }
299
300 return stripTrailingSlash(url);
301}; // use pkg.collective.logo for "legacy"/compatibility reasons
302
303const collectiveLogoUrl = pkg => pkg.collective.logo || pkg.collective.logoUrl || false;
304const collectiveDonationText = pkg => pkg.collective.donation && pkg.collective.donation.text || 'Donate:';
305const getCollective = pkgPath => new Promise(function ($return, $error) {
306 let pkg, url, baseCollective, logoUrl, promises, _ref, _ref2, stats, logo;
307
308 pkg = fetchPkg(pkgPath);
309 url = collectiveUrl(pkg);
310 baseCollective = {
311 url,
312 slug: collectiveSlugFromUrl(url),
313 logoUrl: collectiveLogoUrl(pkg),
314 donationUrl: collectiveDonationUrl(pkg),
315 donationText: collectiveDonationText(pkg)
316 };
317 logoUrl = baseCollective.logoUrl;
318 promises = [fetchStats(url)].concat(logoUrl ? fetchLogo(logoUrl) : []);
319 return Promise.resolve(Promise.all(promises)).then(function ($await_1) {
320 try {
321 _ref = $await_1, _ref2 = _slicedToArray(_ref, 2), stats = _ref2[0], logo = _ref2[1];
322 return $return(Object.assign(baseCollective, {
323 stats,
324 logo
325 }));
326 } catch ($boundEx) {
327 return $error($boundEx);
328 }
329 }, $error);
330});
331const collectiveDonationUrl = pkg => {
332 const defaultDonationAmount = pkg.collective.donation && pkg.collective.donation.amount;
333 let donateUrl = `${collectiveUrl(pkg)}/${retrieveDonationSlug(pkg)}`;
334
335 if (defaultDonationAmount) {
336 return `${donateUrl}/${defaultDonationAmount}`;
337 }
338
339 return donateUrl;
340};
341const retrieveDonationSlug = pkg => {
342 const rawDonationSlug = pkg.collective.donation && pkg.collective.donation.slug;
343
344 if (!rawDonationSlug) {
345 return 'donate';
346 }
347
348 return stripLeadingSlash(rawDonationSlug);
349};
350
351function init(path$$1, hide = hideMessage()) {
352 return new Promise(function ($return, $error) {
353 let collective;
354 global.fetch = global.fetch || fetch;
355 return Promise.resolve(getCollective(path$$1)).then(function ($await_1) {
356 try {
357 collective = $await_1;
358 printLogo(collective.logo);
359 printFooter(collective);
360 return $return();
361 } catch ($boundEx) {
362 return $error($boundEx);
363 }
364 }, $error);
365 });
366}
367
368exports.init = init;