New upgrading process, relying on Git
Summary:
The upgrading process based on Yeoman is a pain. For each file, Yeoman (or the brand new copyAndReplace solution a477aec
) compares the newly generated content with the existing one and prompts the user if it differs, with very basic options: overwrite or skip.
I have digged into this problem and came with [rn-diff](https://github.com/ncuillery/rn-diff) (you may have read [this article](https://medium.com/ncuillery/easier-react-native-upgrades-with-rn-diff-5020b5c3de2d#.llvy2dym5)). This repository helps people to upgrade RN on their projects. An alternative upgrading process using `git apply` instead of Yeoman is described [here](https://github.com/ncuillery/rn-diff/blob/master/USAGE.md).
This PR is the integration of this process into the core. I got rid of the drawbacks mentioned in the link below in order to make it a clean, elegant, one-step operation.
This process is based on some Shell operations that:
- Generate the blank sources of both old and new versions
Closes https://github.com/facebook/react-native/pull/11110
Differential Revision: D4237107
Pulled By: mkonicek
fbshipit-source-id: 15e82e030b762415c925ccb2a62ddb354a6e18b9
This commit is contained in:
parent
f520bb9a66
commit
7d89b773a7
|
@ -14,7 +14,80 @@ iOS project and a JavaScript project, all combined under an npm package, upgradi
|
|||
tricky. But we try to make it easy for you. Here's what you need to do to upgrade from an older
|
||||
version of React Native:
|
||||
|
||||
## 1. Upgrade the `react-native` dependency
|
||||
## Upgrade based on Git
|
||||
|
||||
**IMPORTANT:** You don't have to install the new version of React Native, it will be installed automatically.
|
||||
|
||||
The module `react-native-git-upgrade` provides a one-step operation to upgrade the source files with
|
||||
a minimum of conflicts. Under the hood, it consists in 2 phases:
|
||||
|
||||
* First, it computes a Git patch between both old and new template files,
|
||||
* Then, the patch is applied on the user's sources.
|
||||
|
||||
### 1. Install Git
|
||||
Your project doesn't have to be handled by the Git versioning sytem (could be Mercurial, SVN or none)
|
||||
but Git has to be installed and available in the `PATH`. You can download Git here:
|
||||
https://git-scm.com/downloads
|
||||
|
||||
### 2. Install the `react-native-git-upgrade` module
|
||||
|
||||
It's a CLI tool and must be installed globally:
|
||||
|
||||
```sh
|
||||
$ npm install -g react-native-git-upgrade
|
||||
```
|
||||
|
||||
### 3. Run the command
|
||||
|
||||
Run the command to start the process:
|
||||
|
||||
```sh
|
||||
$ react-native-git-upgrade
|
||||
# Upgrade React Native to the latest version
|
||||
|
||||
# Or:
|
||||
|
||||
$ react-native-git-upgrade X.Y.Z
|
||||
# Upgrade React Native to the X.Y.Z version
|
||||
```
|
||||
|
||||
The templates are upgraded in a optimized way. You still may encounter conflicts but only where the Git
|
||||
3-way merge have failed, depending on the version and how you modified your sources.
|
||||
|
||||
### 4. Resolve the conflicts
|
||||
|
||||
Conflicted files include delimiters which make very clear where the changes come from. For example:
|
||||
|
||||
```
|
||||
13B07F951A680F5B00A75B9A /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
<<<<<<< ours
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/HockeySDK.embeddedframework",
|
||||
"$(PROJECT_DIR)/HockeySDK-iOS/HockeySDK.embeddedframework",
|
||||
);
|
||||
=======
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
>>>>>>> theirs
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
|
||||
"$(SRCROOT)/../node_modules/react-native/React/**",
|
||||
"$(SRCROOT)/../node_modules/react-native-code-push/ios/CodePush/**",
|
||||
);
|
||||
```
|
||||
|
||||
You can think of "ours" as "your team" and "theirs" as "the React Native dev team".
|
||||
|
||||
## Alternative
|
||||
|
||||
Use this only in case the above didn't work.
|
||||
|
||||
### 1. Upgrade the `react-native` dependency
|
||||
|
||||
Note the latest version of the `react-native` npm package from here (or use `npm info react-native` to check):
|
||||
|
||||
|
@ -23,7 +96,7 @@ Note the latest version of the `react-native` npm package from here (or use `npm
|
|||
Now install that version of `react-native` in your project with `npm install --save`:
|
||||
|
||||
```sh
|
||||
$ npm install --save react-native@X.Y
|
||||
$ npm install --save react-native@X.Y
|
||||
# where X.Y is the semantic version you are upgrading to
|
||||
npm WARN peerDependencies The peer dependency react@~R included from react-native...
|
||||
```
|
||||
|
@ -34,7 +107,7 @@ $ npm install --save react@R
|
|||
# where R is the new version of react from the peerDependency warning you saw
|
||||
```
|
||||
|
||||
## 2. Upgrade your project templates
|
||||
### 2. Upgrade your project templates
|
||||
|
||||
The new npm package may contain updates to the files that are normally generated when you
|
||||
run `react-native init`, like the iOS and the Android sub-projects.
|
||||
|
@ -53,8 +126,7 @@ This will check your files against the latest template and perform the following
|
|||
* If there is a new file in the template, it is simply created.
|
||||
* If a file in the template is identical to your file, it is skipped.
|
||||
* If a file is different in your project than the template, you will be prompted; you have options
|
||||
to view a diff between your file and the template file, keep your file or overwrite it with the
|
||||
template version. If you are unsure, press `h` to get a list of possible commands.
|
||||
to keep your file or overwrite it with the template version.
|
||||
|
||||
|
||||
# Manual Upgrades
|
||||
|
|
|
@ -32,6 +32,16 @@ function validateAndUpgrade() {
|
|||
fs.readFileSync(path.resolve(projectDir, 'package.json'), 'utf8')
|
||||
);
|
||||
|
||||
warn(
|
||||
'You should consider using the new upgrade tool based on Git. It ' +
|
||||
'makes upgrades easier by resolving most conflicts automatically.\n' +
|
||||
'To use it:\n' +
|
||||
'- Go back to the old version of React Native\n' +
|
||||
'- Run "npm install -g react-native-git-upgrade"\n' +
|
||||
'- Run "react-native-git-upgrade"\n' +
|
||||
'See https://facebook.github.io/react-native/docs/upgrading.html'
|
||||
);
|
||||
|
||||
const projectName = packageJSON.name;
|
||||
if (!projectName) {
|
||||
warn(
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const {execSync} = require('child_process');
|
||||
const semver = require('semver');
|
||||
|
||||
function checkDeclaredVersion(declaredVersion) {
|
||||
if (!declaredVersion) {
|
||||
throw new Error(
|
||||
'Your "package.json" file doesn\'t seem to have "react-native" as a dependency.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function checkMatchingVersions(currentVersion, declaredVersion) {
|
||||
if (!semver.satisfies(currentVersion, declaredVersion)) {
|
||||
throw new Error(
|
||||
'react-native version in "package.json" doesn\'t match ' +
|
||||
'the installed version in "node_modules".\n' +
|
||||
'Try running "npm install" to fix this.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function checkReactPeerDependency(currentVersion, declaredReactVersion) {
|
||||
if (semver.lt(currentVersion, '0.21.0') && !declaredReactVersion) {
|
||||
throw new Error(
|
||||
'Your "package.json" file doesn\'t seem to have "react" as a dependency.\n' +
|
||||
'"react" was changed from a dependency to a peer dependency in react-native v0.21.0.\n' +
|
||||
'Therefore, it\'s necessary to include "react" in your project\'s dependencies.\n' +
|
||||
'Please run "npm install --save react", then re-run ' +
|
||||
'"react-native upgrade".'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function checkGitAvailable() {
|
||||
try {
|
||||
execSync('git --version');
|
||||
} catch (error) {
|
||||
throw new Error(
|
||||
'"react-native-git-upgrade" requires "git" to be available in path. ' +
|
||||
'Please install Git (https://git-scm.com)"'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function checkNewVersion(newVersion, requiredVersion) {
|
||||
if (!semver.valid(newVersion) && requiredVersion) {
|
||||
throw new Error(
|
||||
'The specified version of React Native ' + requiredVersion + ' doesn\'t exist.\n' +
|
||||
'Re-run the react-native-git-upgrade command with an existing version,\n' +
|
||||
'for example: "react-native-git-upgrade 0.38.0",\n' +
|
||||
'or without arguments to upgrade to the latest: "react-native-git-upgrade".'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
checkDeclaredVersion,
|
||||
checkMatchingVersions,
|
||||
checkReactPeerDependency,
|
||||
checkGitAvailable,
|
||||
checkNewVersion,
|
||||
};
|
|
@ -0,0 +1,22 @@
|
|||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
require('babel-register')({
|
||||
presets: [
|
||||
require('babel-preset-es2015-node'),
|
||||
require('babel-preset-stage-3')
|
||||
],
|
||||
// Enable transpiling for react-native-git-upgrade AND the generator, just like the upgrade CLI command does
|
||||
only: /(react-native-git-upgrade\/(?!(node_modules)))|(local-cli\/generator)/
|
||||
});
|
||||
|
||||
var cliEntry = require('./cliEntry');
|
||||
|
||||
module.exports = cliEntry;
|
|
@ -0,0 +1,283 @@
|
|||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const os = require('os');
|
||||
const path = require('path');
|
||||
const shell = require('shelljs');
|
||||
const Promise = require('promise');
|
||||
const yeoman = require('yeoman-environment');
|
||||
const TerminalAdapter = require('yeoman-environment/lib/adapter');
|
||||
const log = require('npmlog');
|
||||
const rimraf = require('rimraf');
|
||||
const semver = require('semver');
|
||||
|
||||
const {
|
||||
checkDeclaredVersion,
|
||||
checkMatchingVersions,
|
||||
checkReactPeerDependency,
|
||||
checkGitAvailable,
|
||||
checkNewVersion
|
||||
} = require('./checks');
|
||||
|
||||
log.heading = 'git-upgrade';
|
||||
|
||||
/**
|
||||
* Promisify the callback-based shelljs function exec
|
||||
* @param command
|
||||
* @param logOutput
|
||||
* @returns {Promise}
|
||||
*/
|
||||
function exec(command, logOutput) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let stderr, stdout = '';
|
||||
const child = shell.exec(command, {async: true, silent: true});
|
||||
|
||||
child.stdout.on('data', data => {
|
||||
stdout += data;
|
||||
if (logOutput) {
|
||||
process.stdout.write(data);
|
||||
}
|
||||
});
|
||||
|
||||
child.stderr.on('data', data => {
|
||||
stderr += data;
|
||||
process.stderr.write(data);
|
||||
});
|
||||
|
||||
child.on('exit', code => {
|
||||
(code === 0)
|
||||
? resolve(stdout)
|
||||
: reject(new Error(`Command '${command}' exited with code ${code}:
|
||||
stderr: ${stderr}
|
||||
stdout: ${stdout}`));
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
function readPackageFiles() {
|
||||
const rnPakPath = path.resolve(
|
||||
process.cwd(),
|
||||
'node_modules',
|
||||
'react-native',
|
||||
'package.json'
|
||||
);
|
||||
|
||||
const pakPath = path.resolve(
|
||||
process.cwd(),
|
||||
'package.json'
|
||||
);
|
||||
|
||||
try {
|
||||
const rnPak = JSON.parse(fs.readFileSync(rnPakPath, 'utf8'));
|
||||
const pak = JSON.parse(fs.readFileSync(pakPath, 'utf8'));
|
||||
|
||||
return {rnPak, pak};
|
||||
} catch (err) {
|
||||
throw new Error(
|
||||
'Unable to find "' + pakPath + '" or "' + rnPakPath + '". Make sure that you have run ' +
|
||||
'"npm install" and that you are inside a React Native project.'
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function setupWorkingDir(tmpDir) {
|
||||
return new Promise((resolve, reject) => {
|
||||
rimraf(tmpDir, err => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
fs.mkdirSync(tmpDir);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function configureGitEnv(tmpDir) {
|
||||
/*
|
||||
* The workflow inits a temporary Git repository. We don't want to interfere
|
||||
* with an existing user's Git repository.
|
||||
* Thanks to Git env vars, we could address an different directory from the
|
||||
* default ".git". See https://git-scm.com/book/tr/v2/Git-Internals-Environment-Variables
|
||||
*/
|
||||
process.env.GIT_DIR = path.resolve(tmpDir, '.gitrn');
|
||||
process.env.GIT_WORK_TREE = '.';
|
||||
}
|
||||
|
||||
function generateTemplates(generatorDir, appName, verbose) {
|
||||
try {
|
||||
const yeomanGeneratorEntryPoint = path.resolve(generatorDir, 'index.js');
|
||||
// Try requiring the index.js (entry-point of Yeoman generators)
|
||||
fs.accessSync(yeomanGeneratorEntryPoint);
|
||||
return runYeomanGenerators(generatorDir, appName, verbose);
|
||||
} catch(err) {
|
||||
return runCopyAndReplace(generatorDir, appName);
|
||||
}
|
||||
}
|
||||
|
||||
function runCopyAndReplace(generatorDir, appName) {
|
||||
const copyProjectTemplateAndReplacePath = path.resolve(generatorDir, 'copyProjectTemplateAndReplace');
|
||||
/*
|
||||
* This module is required twice during the process: for both old and new version
|
||||
* of React Native.
|
||||
* This file could have changed between these 2 versions. When generating the new template,
|
||||
* we don't want to load the old version of the generator from the cache
|
||||
*/
|
||||
delete require.cache[copyProjectTemplateAndReplacePath];
|
||||
const copyProjectTemplateAndReplace = require(copyProjectTemplateAndReplacePath);
|
||||
copyProjectTemplateAndReplace(
|
||||
path.resolve(generatorDir, '..', 'templates', 'HelloWorld'),
|
||||
process.cwd(),
|
||||
appName,
|
||||
{upgrade: true, force: true}
|
||||
);
|
||||
}
|
||||
|
||||
function runYeomanGenerators(generatorDir, appName, verbose) {
|
||||
if (!verbose) {
|
||||
// Yeoman output needs monkey-patching (no silent option)
|
||||
TerminalAdapter.prototype.log = () => {};
|
||||
TerminalAdapter.prototype.log.force = () => {};
|
||||
TerminalAdapter.prototype.log.create = () => {};
|
||||
}
|
||||
|
||||
const env = yeoman.createEnv();
|
||||
env.register(generatorDir, 'react:app');
|
||||
const generatorArgs = ['react:app', appName];
|
||||
return new Promise((resolve) => env.run(generatorArgs, {upgrade: true, force: true}, resolve));
|
||||
}
|
||||
|
||||
async function run(requiredVersion, cliArgs) {
|
||||
const context = {
|
||||
tmpDir: path.resolve(os.tmpdir(), 'react-native-git-upgrade'),
|
||||
generatorDir: path.resolve(process.cwd(), 'node_modules', 'react-native', 'local-cli', 'generator'),
|
||||
requiredVersion,
|
||||
cliArgs,
|
||||
};
|
||||
|
||||
try {
|
||||
log.info('Check for react-native-git-upgrade updates');
|
||||
const lastGitUpgradeVersion = await exec('npm view react-native-git-upgrade@latest version');
|
||||
const current = require('./package').version;
|
||||
const latest = semver.clean(lastGitUpgradeVersion);
|
||||
if (current !== latest) {
|
||||
log.warn(
|
||||
'A more recent version of "react-native-git-upgrade" has been found.\n' +
|
||||
`Current: ${current}\n` +
|
||||
`Latest: ${latest}\n` +
|
||||
'Please run "npm install -g react-native-git-upgrade"'
|
||||
);
|
||||
}
|
||||
|
||||
log.info('Read package.json files');
|
||||
const {rnPak, pak} = readPackageFiles();
|
||||
context.appName = pak.name;
|
||||
context.currentVersion = rnPak.version;
|
||||
context.declaredVersion = pak.dependencies['react-native'];
|
||||
context.declaredReactVersion = pak.dependencies.react;
|
||||
|
||||
const verbose = context.cliArgs.verbose;
|
||||
|
||||
log.info('Check declared version');
|
||||
checkDeclaredVersion(context.declaredVersion);
|
||||
|
||||
log.info('Check matching versions');
|
||||
checkMatchingVersions(context.currentVersion, context.declaredVersion);
|
||||
|
||||
log.info('Check React peer dependency');
|
||||
checkReactPeerDependency(context.currentVersion, context.declaredReactVersion);
|
||||
|
||||
log.info('Check Git installation');
|
||||
checkGitAvailable();
|
||||
|
||||
log.info('Get react-native version from NPM registry');
|
||||
const versionOutput = await exec('npm view react-native@' + (context.requiredVersion || 'latest') + ' version', verbose);
|
||||
context.newVersion = semver.clean(versionOutput);
|
||||
|
||||
log.info('Check new version');
|
||||
checkNewVersion(context.newVersion, context.requiredVersion);
|
||||
|
||||
log.info('Setup temporary working directory');
|
||||
await setupWorkingDir(context.tmpDir);
|
||||
|
||||
log.info('Configure Git environment');
|
||||
configureGitEnv(context.tmpDir);
|
||||
|
||||
log.info('Init Git repository');
|
||||
await exec('git init', verbose);
|
||||
|
||||
log.info('Add all files to commit');
|
||||
await exec('git add .', verbose);
|
||||
|
||||
log.info('Commit pristine sources');
|
||||
await exec('git commit -m "Project snapshot"', verbose);
|
||||
|
||||
log.info ('Create a tag before updating sources');
|
||||
await exec('git tag project-snapshot', verbose);
|
||||
context.sourcesUpdated = true;
|
||||
|
||||
log.info('Generate old version template');
|
||||
await generateTemplates(context.generatorDir, context.appName, verbose);
|
||||
|
||||
log.info('Add updated files to commit');
|
||||
await exec('git add .', verbose);
|
||||
|
||||
log.info('Commit old version template');
|
||||
await exec('git commit -m "Old version" --allow-empty', verbose);
|
||||
|
||||
log.info('Install the new version');
|
||||
await exec('npm install --save react-native@' + context.newVersion + ' --color=always', verbose);
|
||||
|
||||
log.info('Generate new version template');
|
||||
await generateTemplates(context.generatorDir, context.appName, verbose);
|
||||
|
||||
log.info('Add updated files to commit');
|
||||
await exec('git add .', verbose);
|
||||
|
||||
log.info('Commit new version template');
|
||||
await exec('git commit -m "New version" --allow-empty', verbose);
|
||||
|
||||
log.info('Generate the patch between the 2 versions');
|
||||
const diffOutput = await exec('git diff HEAD~1 HEAD', verbose);
|
||||
|
||||
log.info('Save the patch in temp directory');
|
||||
context.patchPath = path.resolve(context.tmpDir, `upgrade_${context.currentVersion}_${context.newVersion}.patch`);
|
||||
fs.writeFileSync(context.patchPath, diffOutput);
|
||||
|
||||
log.info('Reset the 2 temporary commits');
|
||||
await exec('git reset HEAD~2 --hard', verbose);
|
||||
|
||||
try {
|
||||
log.info('Apply the patch');
|
||||
await exec(`git apply --3way ${context.patchPath}`, true);
|
||||
} catch (err) {
|
||||
log.warn('The upgrade process succeeded but you may have conflicts to solve');
|
||||
} finally {
|
||||
log.info('Upgrade done');
|
||||
if (context.cliArgs.verbose) {
|
||||
log.info(`Temporary working directory: ${context.tmpDir}`);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
log.error('An error occurred during upgrade:');
|
||||
log.error(err.stack);
|
||||
if (context.sourcesUpdated) {
|
||||
log.error('Restore initial sources');
|
||||
await exec('git checkout project-snapshot', true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
run: run,
|
||||
};
|
|
@ -0,0 +1,45 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
var argv = require('minimist')(process.argv.slice(2));
|
||||
|
||||
var cli = require('./cli');
|
||||
|
||||
|
||||
if (argv._.length === 0 && (argv.h || argv.help)) {
|
||||
console.log([
|
||||
'',
|
||||
' Usage: react-native-git-upgrade [version] [options]',
|
||||
'',
|
||||
'',
|
||||
' Commands:',
|
||||
'',
|
||||
' [Version] upgrades React Native and app templates to the desired version',
|
||||
' (latest, if not specified)',
|
||||
'',
|
||||
' Options:',
|
||||
'',
|
||||
' -h, --help output usage information',
|
||||
' -v, --version output the version number',
|
||||
' --verbose output',
|
||||
'',
|
||||
].join('\n'));
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (argv._.length === 0 && (argv.v || argv.version)) {
|
||||
console.log(require('./package.json').version);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
|
||||
cli.run(argv._[0], argv)
|
||||
.catch(console.error);
|
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"name": "react-native-git-upgrade",
|
||||
"version": "0.1.0",
|
||||
"license": "BSD-3-Clause",
|
||||
"description": "The React Native upgrade tool",
|
||||
"main": "cli.js",
|
||||
"bin": {
|
||||
"react-native-git-upgrade": "index.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/facebook/react-native.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"babel-core": "^6.18.0",
|
||||
"babel-preset-es2015-node": "^6.1.1",
|
||||
"babel-preset-stage-3": "^6.17.0",
|
||||
"babel-register": "^6.18.0",
|
||||
"npmlog": "^4.0.0",
|
||||
"promise": "^7.1.1",
|
||||
"rimraf": "^2.5.4",
|
||||
"semver": "^5.0.3",
|
||||
"shelljs": "^0.7.5",
|
||||
"yeoman-environment": "1.5.3"
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue