1 | 'use strict';
|
2 |
|
3 | Object.defineProperty(exports, '__esModule', { value: true });
|
4 |
|
5 | function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
|
6 |
|
7 | var consola = _interopDefault(require('consola'));
|
8 | var child_process = require('child_process');
|
9 | var chalk = _interopDefault(require('chalk'));
|
10 | var path = _interopDefault(require('path'));
|
11 | var fs = _interopDefault(require('fs'));
|
12 | var fetch = _interopDefault(require('node-fetch'));
|
13 |
|
14 | const reportAndThrowError = msg => {
|
15 | report(msg);
|
16 | throw new Error(msg);
|
17 | };
|
18 | const report = message => {
|
19 | consola.fatal({
|
20 | message: String(message),
|
21 | tag: 'opencollective'
|
22 | });
|
23 | };
|
24 | const hideMessage = (env = process.env) => {
|
25 |
|
26 | if (env.OPENCOLLECTIVE_FORCE) {
|
27 | return false;
|
28 | }
|
29 |
|
30 |
|
31 | if (env.OC_POSTINSTALL_TEST) {
|
32 | return true;
|
33 | }
|
34 |
|
35 |
|
36 | if (env.OPENCOLLECTIVE_HIDE) {
|
37 | return true;
|
38 | }
|
39 |
|
40 |
|
41 | if (env.CI || env.CONTINUOUS_INTEGRATION) {
|
42 | return true;
|
43 | }
|
44 |
|
45 |
|
46 | return Boolean(env.NODE_ENV) && !['dev', 'development'].includes(env.NODE_ENV);
|
47 | };
|
48 | const formatMoney = currency => amount => {
|
49 | amount = amount / 100;
|
50 |
|
51 | const precision = 0;
|
52 | return amount.toLocaleString(currency, {
|
53 | style: 'currency',
|
54 | currency: currency,
|
55 | minimumFractionDigits: precision,
|
56 | maximumFractionDigits: precision
|
57 | });
|
58 | };
|
59 | const isWin32 = process.platform === 'win32';
|
60 | const stripLeadingSlash = s => s.startsWith('/') ? s.substring(1) : s;
|
61 | const stripTrailingSlash = s => s.endsWith('/') ? s.slice(0, -1) : s;
|
62 |
|
63 |
|
64 | const 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 | };
|
76 | const 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 | })();
|
97 | const 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 | };
|
110 | const printLogo = logoText => {
|
111 | if (!logoText) {
|
112 | return;
|
113 | }
|
114 |
|
115 | logoText.split('\n').forEach(print('blue'));
|
116 | };
|
117 |
|
118 |
|
119 |
|
120 |
|
121 |
|
122 | const emoji = emoji => process.stdout.isTTY && !isWin32 ? emoji : '';
|
123 | function 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 |
|
137 | function _slicedToArray(arr, i) {
|
138 | return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest();
|
139 | }
|
140 |
|
141 | function _arrayWithHoles(arr) {
|
142 | if (Array.isArray(arr)) return arr;
|
143 | }
|
144 |
|
145 | function _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 |
|
171 | function _nonIterableRest() {
|
172 | throw new TypeError("Invalid attempt to destructure non-iterable instance");
|
173 | }
|
174 |
|
175 | const 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 |
|
207 | const 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 | });
|
232 | const fetchLogo = logoUrl => new Promise(function ($return, $error) {
|
233 | if (!logoUrl) {
|
234 |
|
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 |
|
280 | const isLogoResponseWellFormatted = res => res.status === 200 && res.headers.get('content-type').match(/^text\/plain/);
|
281 |
|
282 | const 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 |
|
292 | const collectiveSlugFromUrl = url => url.substr(url.lastIndexOf('/') + 1).toLowerCase().replace(/\.json/g, '');
|
293 | const 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 | };
|
302 |
|
303 | const collectiveLogoUrl = pkg => pkg.collective.logo || pkg.collective.logoUrl || false;
|
304 | const collectiveDonationText = pkg => pkg.collective.donation && pkg.collective.donation.text || 'Donate:';
|
305 | const 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 | });
|
331 | const 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 | };
|
341 | const 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 |
|
351 | function 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 |
|
368 | exports.init = init;
|