diff --git a/fixtures/package-helper/empty/.gitkeep b/fixtures/package-helper/empty/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/fixtures/package-helper/npm/package-lock.json b/fixtures/package-helper/npm/package-lock.json new file mode 100644 index 00000000..c47b6301 --- /dev/null +++ b/fixtures/package-helper/npm/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "foo", + "version": "1.0.0", + "lockfileVersion": 1 +} \ No newline at end of file diff --git a/fixtures/package-helper/yarn-npm/package-lock.json b/fixtures/package-helper/yarn-npm/package-lock.json new file mode 100644 index 00000000..c47b6301 --- /dev/null +++ b/fixtures/package-helper/yarn-npm/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "foo", + "version": "1.0.0", + "lockfileVersion": 1 +} \ No newline at end of file diff --git a/fixtures/package-helper/yarn-npm/yarn.lock b/fixtures/package-helper/yarn-npm/yarn.lock new file mode 100644 index 00000000..4a580188 --- /dev/null +++ b/fixtures/package-helper/yarn-npm/yarn.lock @@ -0,0 +1,2 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 diff --git a/fixtures/package-helper/yarn/yarn.lock b/fixtures/package-helper/yarn/yarn.lock new file mode 100644 index 00000000..4a580188 --- /dev/null +++ b/fixtures/package-helper/yarn/yarn.lock @@ -0,0 +1,2 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 diff --git a/lib/friendly-errors/formatters/missing-loader.js b/lib/friendly-errors/formatters/missing-loader.js index d8575060..2a10207c 100644 --- a/lib/friendly-errors/formatters/missing-loader.js +++ b/lib/friendly-errors/formatters/missing-loader.js @@ -32,7 +32,7 @@ function formatErrors(errors) { ); if (packageRecommendations) { - fixes.push(`${packageRecommendations.message}\n ${packageRecommendations.yarnInstall}`); + fixes.push(`${packageRecommendations.message}\n ${packageRecommendations.installCommand}`); } } else { fixes.push('You may need to install and configure a special loader for this file type.'); diff --git a/lib/package-helper.js b/lib/package-helper.js index b5013d88..9da404f4 100644 --- a/lib/package-helper.js +++ b/lib/package-helper.js @@ -10,6 +10,7 @@ 'use strict'; const chalk = require('chalk'); +const fs = require('fs'); function ensurePackagesExist(packageNames, requestedFeature) { const recommendation = getPackageRecommendations(packageNames, requestedFeature); @@ -20,10 +21,21 @@ function ensurePackagesExist(packageNames, requestedFeature) { throw new Error(` ${recommendation.message} - ${recommendation.yarnInstall} + ${recommendation.installCommand} `); } +function getInstallCommand(packages) { + const hasYarnLockfile = fs.existsSync('yarn.lock'); + const hasNpmLockfile = fs.existsSync('package-lock.json'); + + if (hasNpmLockfile && !hasYarnLockfile) { + return chalk.yellow(`npm install ${packages.join(' ')} --save-dev`); + } + + return chalk.yellow(`yarn add ${packages.join(' ')} --dev`); +} + function getPackageRecommendations(packageNames, requestedFeature = null) { let missingPackageNames = []; @@ -48,11 +60,11 @@ function getPackageRecommendations(packageNames, requestedFeature = null) { message += ` to use ${chalk.green(requestedFeature)}`; } - let yarnInstall = chalk.yellow(`yarn add ${missingPackageNames.join(' ')} --dev`); + const installCommand = getInstallCommand(missingPackageNames); return { message, - yarnInstall + installCommand }; } diff --git a/test/package-helper.js b/test/package-helper.js new file mode 100644 index 00000000..dbf9fdb1 --- /dev/null +++ b/test/package-helper.js @@ -0,0 +1,49 @@ +/* + * This file is part of the Symfony Webpack Encore package. + * + * (c) Fabien Potencier + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +'use strict'; + +const expect = require('chai').expect; +const packageHelper = require('../lib/package-helper'); +const path = require('path'); +const process = require('process'); + +describe('package-helper', () => { + const baseCwd = process.cwd(); + + describe('recommended install command is based on the existing lock files', () => { + after(() => { + process.chdir(baseCwd); + }); + + it('missing packages without any lock file', () => { + process.chdir(path.join(__dirname , '../fixtures/package-helper/empty')); + const packageRecommendations = packageHelper.getPackageRecommendations(['foo', 'webpack', 'bar']); + expect(packageRecommendations.installCommand).to.contain('yarn add foo bar'); + }); + + it('missing packages with package-lock.json only', () => { + process.chdir(path.join(__dirname, '../fixtures/package-helper/npm')); + const packageRecommendations = packageHelper.getPackageRecommendations(['foo', 'webpack', 'bar']); + expect(packageRecommendations.installCommand).to.contain('npm install foo bar'); + }); + + it('missing packages with yarn.lock only', () => { + process.chdir(path.join(__dirname, '../fixtures/package-helper/yarn')); + const packageRecommendations = packageHelper.getPackageRecommendations(['foo', 'webpack', 'bar']); + expect(packageRecommendations.installCommand).to.contain('yarn add foo bar'); + }); + + it('missing packages with both package-lock.json and yarn.lock', () => { + process.chdir(path.join(__dirname, '../fixtures/package-helper/yarn-npm')); + const packageRecommendations = packageHelper.getPackageRecommendations(['foo', 'webpack', 'bar']); + expect(packageRecommendations.installCommand).to.contain('yarn add foo bar'); + }); + }); +});