1 | 'use strict';
|
2 |
|
3 | const validateProjectName = require('validate-npm-package-name');
|
4 | const chalk = require('chalk');
|
5 | const commander = require('commander');
|
6 | const fs = require('fs-extra');
|
7 | const path = require('path');
|
8 | const execSync = require('child_process').execSync;
|
9 | const spawn = require('cross-spawn');
|
10 | const semver = require('semver');
|
11 | const dns = require('dns');
|
12 | const tmp = require('tmp');
|
13 | const unpack = require('tar-pack').unpack;
|
14 | const url = require('url');
|
15 | const hyperquest = require('hyperquest');
|
16 | const envinfo = require('envinfo');
|
17 | const os = require('os');
|
18 | const packageJson = require('./package.json');
|
19 |
|
20 |
|
21 |
|
22 | const errorLogFilePatterns = [
|
23 | 'npm-debug.log',
|
24 | 'yarn-error.log',
|
25 | 'yarn-debug.log',
|
26 | ];
|
27 |
|
28 | let projectName;
|
29 |
|
30 | const program = new commander.Command(packageJson.name)
|
31 | .version(packageJson.version)
|
32 | .arguments('<project-directory>')
|
33 | .usage(`${chalk.green('<project-directory>')} [options]`)
|
34 | .action(name => {
|
35 | projectName = name;
|
36 | })
|
37 | .option('--verbose', 'print additional logs')
|
38 | .option('--info', 'print environment debug info')
|
39 | .option(
|
40 | '--scripts-version <alternative-package>',
|
41 | 'use a non-standard version of react-scripts'
|
42 | )
|
43 | .option('--use-npm')
|
44 | .allowUnknownOption()
|
45 | .on('--help', () => {
|
46 | console.log(` Only ${chalk.green('<project-directory>')} is required.`);
|
47 | console.log();
|
48 | console.log(
|
49 | ` A custom ${chalk.cyan('--scripts-version')} can be one of:`
|
50 | );
|
51 | console.log(` - a specific npm version: ${chalk.green('0.8.2')}`);
|
52 | console.log(` - a specific npm tag: ${chalk.green('@next')}`);
|
53 | console.log(
|
54 | ` - a custom fork published on npm: ${chalk.green(
|
55 | 'my-react-scripts'
|
56 | )}`
|
57 | );
|
58 | console.log(
|
59 | ` - a local path relative to the current working directory: ${chalk.green(
|
60 | 'file:../my-react-scripts'
|
61 | )}`
|
62 | );
|
63 | console.log(
|
64 | ` - a .tgz archive: ${chalk.green(
|
65 | 'https://mysite.com/my-react-scripts-0.8.2.tgz'
|
66 | )}`
|
67 | );
|
68 | console.log(
|
69 | ` - a .tar.gz archive: ${chalk.green(
|
70 | 'https://mysite.com/my-react-scripts-0.8.2.tar.gz'
|
71 | )}`
|
72 | );
|
73 | console.log(
|
74 | ` It is not needed unless you specifically want to use a fork.`
|
75 | );
|
76 | console.log();
|
77 | console.log(
|
78 | ` If you have any problems, do not hesitate to file an issue:`
|
79 | );
|
80 | console.log(
|
81 | ` ${chalk.cyan(
|
82 | 'https://github.com/facebook/create-react-app/issues/new'
|
83 | )}`
|
84 | );
|
85 | console.log();
|
86 | })
|
87 | .parse(process.argv);
|
88 |
|
89 | if (program.info) {
|
90 | console.log(chalk.bold('\nEnvironment Info:'));
|
91 | return envinfo
|
92 | .run(
|
93 | {
|
94 | System: ['OS', 'CPU'],
|
95 | Binaries: ['Node', 'npm', 'Yarn'],
|
96 | Browsers: ['Chrome', 'Edge', 'Internet Explorer', 'Firefox', 'Safari'],
|
97 | npmPackages: ['react', 'react-dom', 'react-scripts'],
|
98 | npmGlobalPackages: ['create-react-app'],
|
99 | },
|
100 | {
|
101 | clipboard: true,
|
102 | duplicates: true,
|
103 | showNotFound: true,
|
104 | }
|
105 | )
|
106 | .then(console.log)
|
107 | .then(() => console.log(chalk.green('Copied To Clipboard!\n')));
|
108 | }
|
109 |
|
110 | if (typeof projectName === 'undefined') {
|
111 | console.error('Please specify the project directory:');
|
112 | console.log(
|
113 | ` ${chalk.cyan(program.name())} ${chalk.green('<project-directory>')}`
|
114 | );
|
115 | console.log();
|
116 | console.log('For example:');
|
117 | console.log(` ${chalk.cyan(program.name())} ${chalk.green('my-react-app')}`);
|
118 | console.log();
|
119 | console.log(
|
120 | `Run ${chalk.cyan(`${program.name()} --help`)} to see all options.`
|
121 | );
|
122 | process.exit(1);
|
123 | }
|
124 |
|
125 | function printValidationResults(results) {
|
126 | if (typeof results !== 'undefined') {
|
127 | results.forEach(error => {
|
128 | console.error(chalk.red(` * ${error}`));
|
129 | });
|
130 | }
|
131 | }
|
132 |
|
133 | const hiddenProgram = new commander.Command()
|
134 | .option(
|
135 | '--internal-testing-template <path-to-template>',
|
136 | '(internal usage only, DO NOT RELY ON THIS) ' +
|
137 | 'use a non-standard application template'
|
138 | )
|
139 | .parse(process.argv);
|
140 |
|
141 | createApp(
|
142 | projectName,
|
143 | program.verbose,
|
144 | program.scriptsVersion,
|
145 | program.useNpm,
|
146 | hiddenProgram.internalTestingTemplate
|
147 | );
|
148 |
|
149 | function createApp(name, verbose, version, useNpm, template) {
|
150 | const root = path.resolve(name);
|
151 | const appName = path.basename(root);
|
152 |
|
153 | checkAppName(appName);
|
154 | fs.ensureDirSync(name);
|
155 | if (!isSafeToCreateProjectIn(root, name)) {
|
156 | process.exit(1);
|
157 | }
|
158 |
|
159 | console.log(`Creating a new mogul app in ${chalk.green(root)}.`);
|
160 | console.log();
|
161 |
|
162 | const packageJson = {
|
163 | name: appName,
|
164 | version: '0.1.0',
|
165 | private: true,
|
166 | };
|
167 | fs.writeFileSync(
|
168 | path.join(root, 'package.json'),
|
169 | JSON.stringify(packageJson, null, 2) + os.EOL
|
170 | );
|
171 |
|
172 | const useYarn = useNpm ? false : shouldUseYarn(root);
|
173 | const originalDirectory = process.cwd();
|
174 | process.chdir(root);
|
175 | if (!useYarn && !checkThatNpmCanReadCwd()) {
|
176 | process.exit(1);
|
177 | }
|
178 |
|
179 | run(root, appName, version, verbose, originalDirectory, template, useYarn);
|
180 | }
|
181 |
|
182 | function isYarnAvailable() {
|
183 | try {
|
184 | execSync('yarnpkg --version', { stdio: 'ignore' });
|
185 | return true;
|
186 | } catch (e) {
|
187 | return false;
|
188 | }
|
189 | }
|
190 |
|
191 | function shouldUseYarn(appDir) {
|
192 | return isYarnAvailable()
|
193 | }
|
194 |
|
195 | function install(root, useYarn, dependencies, verbose, isOnline) {
|
196 | return new Promise((resolve, reject) => {
|
197 | let command;
|
198 | let args;
|
199 | if (useYarn) {
|
200 | command = 'yarnpkg';
|
201 | args = ['add', '--exact'];
|
202 | if (!isOnline) {
|
203 | args.push('--offline');
|
204 | }
|
205 | [].push.apply(args, dependencies);
|
206 |
|
207 |
|
208 |
|
209 |
|
210 |
|
211 |
|
212 | args.push('--cwd');
|
213 | args.push(root);
|
214 |
|
215 | if (!isOnline) {
|
216 | console.log(chalk.yellow('You appear to be offline.'));
|
217 | console.log(chalk.yellow('Falling back to the local Yarn cache.'));
|
218 | console.log();
|
219 | }
|
220 | } else {
|
221 | command = 'npm';
|
222 | args = [
|
223 | 'install',
|
224 | '--save',
|
225 | '--save-exact',
|
226 | '--loglevel',
|
227 | 'error',
|
228 | ].concat(dependencies);
|
229 | }
|
230 |
|
231 | if (verbose) {
|
232 | args.push('--verbose');
|
233 | }
|
234 |
|
235 | const child = spawn(command, args, { stdio: 'inherit' });
|
236 | child.on('close', code => {
|
237 | if (code !== 0) {
|
238 | reject({
|
239 | command: `${command} ${args.join(' ')}`,
|
240 | });
|
241 | return;
|
242 | }
|
243 | resolve();
|
244 | });
|
245 | });
|
246 | }
|
247 |
|
248 | function run(
|
249 | root,
|
250 | appName,
|
251 | version,
|
252 | verbose,
|
253 | originalDirectory,
|
254 | template,
|
255 | useYarn
|
256 | ) {
|
257 | const packageToInstall = getInstallPackage(version, originalDirectory);
|
258 | const allDependencies = ['react', 'react-dom', packageToInstall];
|
259 |
|
260 | console.log('Installing packages. This might take a couple of minutes.');
|
261 | getPackageName(packageToInstall)
|
262 | .then(packageName =>
|
263 | checkIfOnline(useYarn).then(isOnline => ({
|
264 | isOnline: isOnline,
|
265 | packageName: packageName,
|
266 | }))
|
267 | )
|
268 | .then(info => {
|
269 | const isOnline = info.isOnline;
|
270 | const packageName = info.packageName;
|
271 | console.log(
|
272 | `Installing ${chalk.cyan('react')}, ${chalk.cyan(
|
273 | 'react-dom'
|
274 | )}, and ${chalk.cyan(packageName)}...`
|
275 | );
|
276 | console.log();
|
277 |
|
278 | return install(root, useYarn, allDependencies, verbose, isOnline).then(
|
279 | () => packageName
|
280 | );
|
281 | })
|
282 | .then(packageName => {
|
283 | checkNodeVersion(packageName);
|
284 | setCaretRangeForRuntimeDeps(packageName);
|
285 |
|
286 | const scriptsPath = path.resolve(
|
287 | process.cwd(),
|
288 | 'node_modules',
|
289 | packageName,
|
290 | 'scripts',
|
291 | 'init.js'
|
292 | );
|
293 | const init = require(scriptsPath);
|
294 | init(root, appName, verbose, originalDirectory, template);
|
295 |
|
296 | })
|
297 | .catch(reason => {
|
298 | console.log();
|
299 | console.log('Aborting installation.');
|
300 | if (reason.command) {
|
301 | console.log(` ${chalk.cyan(reason.command)} has failed.`);
|
302 | } else {
|
303 | console.log(chalk.red('Unexpected error. Please report it as a bug:'));
|
304 | console.log(reason);
|
305 | }
|
306 | console.log();
|
307 |
|
308 |
|
309 | const knownGeneratedFiles = ['package.json', 'node_modules'];
|
310 | const currentFiles = fs.readdirSync(path.join(root));
|
311 | currentFiles.forEach(file => {
|
312 | knownGeneratedFiles.forEach(fileToMatch => {
|
313 |
|
314 | if (file === fileToMatch) {
|
315 | console.log(`Deleting generated file... ${chalk.cyan(file)}`);
|
316 | fs.removeSync(path.join(root, file));
|
317 | }
|
318 | });
|
319 | });
|
320 | const remainingFiles = fs.readdirSync(path.join(root));
|
321 | if (!remainingFiles.length) {
|
322 |
|
323 | console.log(
|
324 | `Deleting ${chalk.cyan(`${appName}/`)} from ${chalk.cyan(
|
325 | path.resolve(root, '..')
|
326 | )}`
|
327 | );
|
328 | process.chdir(path.resolve(root, '..'));
|
329 | fs.removeSync(path.join(root));
|
330 | }
|
331 | console.log('Done.');
|
332 | process.exit(1);
|
333 | });
|
334 | }
|
335 |
|
336 | function getInstallPackage(version, originalDirectory) {
|
337 |
|
338 | return "@mogul/mogul-scripts"
|
339 |
|
340 |
|
341 |
|
342 |
|
343 |
|
344 |
|
345 |
|
346 |
|
347 |
|
348 |
|
349 |
|
350 |
|
351 |
|
352 |
|
353 |
|
354 |
|
355 |
|
356 |
|
357 | }
|
358 |
|
359 | function getTemporaryDirectory() {
|
360 | return new Promise((resolve, reject) => {
|
361 |
|
362 |
|
363 | tmp.dir({ unsafeCleanup: true }, (err, tmpdir, callback) => {
|
364 | if (err) {
|
365 | reject(err);
|
366 | } else {
|
367 | resolve({
|
368 | tmpdir: tmpdir,
|
369 | cleanup: () => {
|
370 | try {
|
371 | callback();
|
372 | } catch (ignored) {
|
373 |
|
374 |
|
375 | }
|
376 | },
|
377 | });
|
378 | }
|
379 | });
|
380 | });
|
381 | }
|
382 |
|
383 | function extractStream(stream, dest) {
|
384 | return new Promise((resolve, reject) => {
|
385 | stream.pipe(
|
386 | unpack(dest, err => {
|
387 | if (err) {
|
388 | reject(err);
|
389 | } else {
|
390 | resolve(dest);
|
391 | }
|
392 | })
|
393 | );
|
394 | });
|
395 | }
|
396 |
|
397 |
|
398 | function getPackageName(installPackage) {
|
399 | if (installPackage.match(/^.+\.(tgz|tar\.gz)$/)) {
|
400 | return getTemporaryDirectory()
|
401 | .then(obj => {
|
402 | let stream;
|
403 | if (/^http/.test(installPackage)) {
|
404 | stream = hyperquest(installPackage);
|
405 | } else {
|
406 | stream = fs.createReadStream(installPackage);
|
407 | }
|
408 | return extractStream(stream, obj.tmpdir).then(() => obj);
|
409 | })
|
410 | .then(obj => {
|
411 | const packageName = require(path.join(obj.tmpdir, 'package.json')).name;
|
412 | obj.cleanup();
|
413 | return packageName;
|
414 | })
|
415 | .catch(err => {
|
416 |
|
417 |
|
418 | console.log(
|
419 | `Could not extract the package name from the archive: ${err.message}`
|
420 | );
|
421 | const assumedProjectName = installPackage.match(
|
422 | /^.+\/(.+?)(?:-\d+.+)?\.(tgz|tar\.gz)$/
|
423 | )[1];
|
424 | console.log(
|
425 | `Based on the filename, assuming it is "${chalk.cyan(
|
426 | assumedProjectName
|
427 | )}"`
|
428 | );
|
429 | return Promise.resolve(assumedProjectName);
|
430 | });
|
431 | } else if (installPackage.indexOf('git+') === 0) {
|
432 |
|
433 |
|
434 |
|
435 | return Promise.resolve(installPackage.match(/([^/]+)\.git(#.*)?$/)[1]);
|
436 | } else if (installPackage.match(/.+@/)) {
|
437 |
|
438 | return Promise.resolve(
|
439 | installPackage.charAt(0) + installPackage.substr(1).split('@')[0]
|
440 | );
|
441 | } else if (installPackage.match(/^file:/)) {
|
442 | const installPackagePath = installPackage.match(/^file:(.*)?$/)[1];
|
443 | const installPackageJson = require(path.join(
|
444 | installPackagePath,
|
445 | 'package.json'
|
446 | ));
|
447 | return Promise.resolve(installPackageJson.name);
|
448 | }
|
449 | return Promise.resolve(installPackage);
|
450 | }
|
451 |
|
452 | function checkNpmVersion() {
|
453 | let hasMinNpm = false;
|
454 | let npmVersion = null;
|
455 | try {
|
456 | npmVersion = execSync('npm --version')
|
457 | .toString()
|
458 | .trim();
|
459 | hasMinNpm = semver.gte(npmVersion, '3.0.0');
|
460 | } catch (err) {
|
461 |
|
462 | }
|
463 | return {
|
464 | hasMinNpm: hasMinNpm,
|
465 | npmVersion: npmVersion,
|
466 | };
|
467 | }
|
468 |
|
469 | function checkNodeVersion(packageName) {
|
470 | const packageJsonPath = path.resolve(
|
471 | process.cwd(),
|
472 | 'node_modules',
|
473 | packageName,
|
474 | 'package.json'
|
475 | );
|
476 | const packageJson = require(packageJsonPath);
|
477 | if (!packageJson.engines || !packageJson.engines.node) {
|
478 | return;
|
479 | }
|
480 |
|
481 | if (!semver.satisfies(process.version, packageJson.engines.node)) {
|
482 | console.error(
|
483 | chalk.red(
|
484 | 'You are running Node %s.\n' +
|
485 | 'Create React App requires Node %s or higher. \n' +
|
486 | 'Please update your version of Node.'
|
487 | ),
|
488 | process.version,
|
489 | packageJson.engines.node
|
490 | );
|
491 | process.exit(1);
|
492 | }
|
493 | }
|
494 |
|
495 | function checkAppName(appName) {
|
496 | const validationResult = validateProjectName(appName);
|
497 | if (!validationResult.validForNewPackages) {
|
498 | console.error(
|
499 | `Could not create a project called ${chalk.red(
|
500 | `"${appName}"`
|
501 | )} because of npm naming restrictions:`
|
502 | );
|
503 | printValidationResults(validationResult.errors);
|
504 | printValidationResults(validationResult.warnings);
|
505 | process.exit(1);
|
506 | }
|
507 |
|
508 |
|
509 | const dependencies = ['react', 'react-dom', 'react-scripts'].sort();
|
510 | if (dependencies.indexOf(appName) >= 0) {
|
511 | console.error(
|
512 | chalk.red(
|
513 | `We cannot create a project called ${chalk.green(
|
514 | appName
|
515 | )} because a dependency with the same name exists.\n` +
|
516 | `Due to the way npm works, the following names are not allowed:\n\n`
|
517 | ) +
|
518 | chalk.cyan(dependencies.map(depName => ` ${depName}`).join('\n')) +
|
519 | chalk.red('\n\nPlease choose a different project name.')
|
520 | );
|
521 | process.exit(1);
|
522 | }
|
523 | }
|
524 |
|
525 | function makeCaretRange(dependencies, name) {
|
526 | const version = dependencies[name];
|
527 |
|
528 | if (typeof version === 'undefined') {
|
529 | console.error(chalk.red(`Missing ${name} dependency in package.json`));
|
530 | process.exit(1);
|
531 | }
|
532 |
|
533 | let patchedVersion = `^${version}`;
|
534 |
|
535 | if (!semver.validRange(patchedVersion)) {
|
536 | console.error(
|
537 | `Unable to patch ${name} dependency version because version ${chalk.red(
|
538 | version
|
539 | )} will become invalid ${chalk.red(patchedVersion)}`
|
540 | );
|
541 | patchedVersion = version;
|
542 | }
|
543 |
|
544 | dependencies[name] = patchedVersion;
|
545 | }
|
546 |
|
547 | function setCaretRangeForRuntimeDeps(packageName) {
|
548 | const packagePath = path.join(process.cwd(), 'package.json');
|
549 | const packageJson = require(packagePath);
|
550 |
|
551 | if (typeof packageJson.dependencies === 'undefined') {
|
552 | console.error(chalk.red('Missing dependencies in package.json'));
|
553 | process.exit(1);
|
554 | }
|
555 |
|
556 | const packageVersion = packageJson.dependencies[packageName];
|
557 | if (typeof packageVersion === 'undefined') {
|
558 | console.error(chalk.red(`Unable to find ${packageName} in package.json`));
|
559 | process.exit(1);
|
560 | }
|
561 |
|
562 | makeCaretRange(packageJson.dependencies, 'react');
|
563 | makeCaretRange(packageJson.dependencies, 'react-dom');
|
564 |
|
565 | fs.writeFileSync(packagePath, JSON.stringify(packageJson, null, 2) + os.EOL);
|
566 | }
|
567 |
|
568 |
|
569 |
|
570 |
|
571 |
|
572 |
|
573 | function isSafeToCreateProjectIn(root, name) {
|
574 | const validFiles = [
|
575 | '.DS_Store',
|
576 | 'Thumbs.db',
|
577 | '.git',
|
578 | '.gitignore',
|
579 | '.idea',
|
580 | 'README.md',
|
581 | 'LICENSE',
|
582 | 'web.iml',
|
583 | '.hg',
|
584 | '.hgignore',
|
585 | '.hgcheck',
|
586 | '.npmignore',
|
587 | 'mkdocs.yml',
|
588 | 'docs',
|
589 | '.travis.yml',
|
590 | '.gitlab-ci.yml',
|
591 | '.gitattributes',
|
592 | ];
|
593 | console.log();
|
594 |
|
595 | const conflicts = fs
|
596 | .readdirSync(root)
|
597 | .filter(file => !validFiles.includes(file))
|
598 |
|
599 | .filter(
|
600 | file => !errorLogFilePatterns.some(pattern => file.indexOf(pattern) === 0)
|
601 | );
|
602 |
|
603 | if (conflicts.length > 0) {
|
604 | console.log(
|
605 | `The directory ${chalk.green(name)} contains files that could conflict:`
|
606 | );
|
607 | console.log();
|
608 | for (const file of conflicts) {
|
609 | console.log(` ${file}`);
|
610 | }
|
611 | console.log();
|
612 | console.log(
|
613 | 'Either try using a new directory name, or remove the files listed above.'
|
614 | );
|
615 |
|
616 | return false;
|
617 | }
|
618 |
|
619 |
|
620 | const currentFiles = fs.readdirSync(path.join(root));
|
621 | currentFiles.forEach(file => {
|
622 | errorLogFilePatterns.forEach(errorLogFilePattern => {
|
623 |
|
624 | if (file.indexOf(errorLogFilePattern) === 0) {
|
625 | fs.removeSync(path.join(root, file));
|
626 | }
|
627 | });
|
628 | });
|
629 | return true;
|
630 | }
|
631 |
|
632 | function getProxy() {
|
633 | if (process.env.https_proxy) {
|
634 | return process.env.https_proxy;
|
635 | } else {
|
636 | try {
|
637 |
|
638 | let httpsProxy = execSync('npm config get https-proxy')
|
639 | .toString()
|
640 | .trim();
|
641 | return httpsProxy !== 'null' ? httpsProxy : undefined;
|
642 | } catch (e) {
|
643 | return;
|
644 | }
|
645 | }
|
646 | }
|
647 | function checkThatNpmCanReadCwd() {
|
648 | const cwd = process.cwd();
|
649 | let childOutput = null;
|
650 | try {
|
651 |
|
652 |
|
653 |
|
654 |
|
655 |
|
656 | childOutput = spawn.sync('npm', ['config', 'list']).output.join('');
|
657 | } catch (err) {
|
658 |
|
659 |
|
660 |
|
661 | return true;
|
662 | }
|
663 | if (typeof childOutput !== 'string') {
|
664 | return true;
|
665 | }
|
666 | const lines = childOutput.split('\n');
|
667 |
|
668 |
|
669 |
|
670 | const prefix = '; cwd = ';
|
671 | const line = lines.find(line => line.indexOf(prefix) === 0);
|
672 | if (typeof line !== 'string') {
|
673 |
|
674 | return true;
|
675 | }
|
676 | const npmCWD = line.substring(prefix.length);
|
677 | if (npmCWD === cwd) {
|
678 | return true;
|
679 | }
|
680 | console.error(
|
681 | chalk.red(
|
682 | `Could not start an npm process in the right directory.\n\n` +
|
683 | `The current directory is: ${chalk.bold(cwd)}\n` +
|
684 | `However, a newly started npm process runs in: ${chalk.bold(
|
685 | npmCWD
|
686 | )}\n\n` +
|
687 | `This is probably caused by a misconfigured system terminal shell.`
|
688 | )
|
689 | );
|
690 | if (process.platform === 'win32') {
|
691 | console.error(
|
692 | chalk.red(`On Windows, this can usually be fixed by running:\n\n`) +
|
693 | ` ${chalk.cyan(
|
694 | 'reg'
|
695 | )} delete "HKCU\\Software\\Microsoft\\Command Processor" /v AutoRun /f\n` +
|
696 | ` ${chalk.cyan(
|
697 | 'reg'
|
698 | )} delete "HKLM\\Software\\Microsoft\\Command Processor" /v AutoRun /f\n\n` +
|
699 | chalk.red(`Try to run the above two lines in the terminal.\n`) +
|
700 | chalk.red(
|
701 | `To learn more about this problem, read: https://blogs.msdn.microsoft.com/oldnewthing/20071121-00/?p=24433/`
|
702 | )
|
703 | );
|
704 | }
|
705 | return false;
|
706 | }
|
707 |
|
708 | function checkIfOnline(useYarn) {
|
709 | if (!useYarn) {
|
710 |
|
711 |
|
712 | return Promise.resolve(true);
|
713 | }
|
714 |
|
715 | return new Promise(resolve => {
|
716 | dns.lookup('registry.yarnpkg.com', err => {
|
717 | let proxy;
|
718 | if (err != null && (proxy = getProxy())) {
|
719 |
|
720 |
|
721 | dns.lookup(url.parse(proxy).hostname, proxyErr => {
|
722 | resolve(proxyErr == null);
|
723 | });
|
724 | } else {
|
725 | resolve(err == null);
|
726 | }
|
727 | });
|
728 | });
|
729 | }
|