Enable platforms to configure CLI commands
Summary: This change adds hooks via the `package.json` for a platform plugin to specify hooks for generating platform configurations. This change also adds hooks to allow platform plugins to participate in `link` and `unlink` commands. The goal is to move platform-specific code for platform plugins into their own repositories / node_modules. <!-- Thank you for sending the PR! We appreciate you spending the time to work on these changes. Help us understand your motivation by explaining why you decided to make this change. You can learn more about contributing to React Native here: http://facebook.github.io/react-native/docs/contributing.html Happy contributing! --> We need to be able to configure the CLI commands for plugin platforms (e.g., react-native-windows) in their own repositories. (Write your test plan here. If you changed any code, please provide us with clear instructions on how you verified your changes work. Bonus points for screenshots and videos!) - All jest tests, including new tests, pass. - `link` and `unlink` commands are successful on iOS and Android. (If this PR adds or changes functionality, please take some time to update the docs at https://github.com/facebook/react-native-website, and link to your PR here.) https://github.com/Microsoft/react-native-windows/pull/1601 <!-- Help reviewers and the release process by writing your own release notes **INTERNAL and MINOR tagged notes will not be included in the next version's final release notes.** CATEGORY [----------] TYPE [ CLI ] [-------------] LOCATION [ DOCS ] [ BREAKING ] [-------------] [ GENERAL ] [ BUGFIX ] [-{Component}-] [ INTERNAL ] [ ENHANCEMENT ] [ {File} ] [ IOS ] [ FEATURE ] [ {Directory} ] |-----------| [ ANDROID ] [ MINOR ] [ {Framework} ] - | {Message} | [----------] [-------------] [-------------] |-----------| [CATEGORY] [TYPE] [LOCATION] - MESSAGE EXAMPLES: [IOS] [BREAKING] [FlatList] - Change a thing that breaks other things [ANDROID] [BUGFIX] [TextInput] - Did a thing to TextInput [CLI] [FEATURE] [local-cli/info/info.js] - CLI easier to do things with [DOCS] [BUGFIX] [GettingStarted.md] - Accidentally a thing/word [GENERAL] [ENHANCEMENT] [Yoga] - Added new yoga thing/position [INTERNAL] [FEATURE] [./scripts] - Added thing to script that nobody will see --> [CLI][FEATURE][local-cli/core/index.js] - Allow platform plugins to contribute to the RNConfig. [CLI][FEATURE][local-cli/link/link.js] - Allow platform plugins to participate in the `link` command. [CLI][FEATURE][local-cli/link/unlink.js] - Allow platform plugins to participate in the `unlink` command. Closes https://github.com/facebook/react-native/pull/17745 Differential Revision: D6883558 Pulled By: hramos fbshipit-source-id: ea32fe21cedd4cc02c5c0d48229f2cdb2ac8142b
This commit is contained in:
parent
2c63f49269
commit
9775308458
|
@ -27,18 +27,27 @@ describe('findPlugins', () => {
|
||||||
jest.mock(pjsonPath, () => ({
|
jest.mock(pjsonPath, () => ({
|
||||||
dependencies: {'rnpm-plugin-test': '*'},
|
dependencies: {'rnpm-plugin-test': '*'},
|
||||||
}));
|
}));
|
||||||
expect(findPlugins([ROOT])).toHaveLength(1);
|
|
||||||
expect(findPlugins([ROOT])[0]).toBe('rnpm-plugin-test');
|
expect(findPlugins([ROOT])).toHaveProperty('commands');
|
||||||
|
expect(findPlugins([ROOT])).toHaveProperty('platforms');
|
||||||
|
expect(findPlugins([ROOT]).commands).toHaveLength(1);
|
||||||
|
expect(findPlugins([ROOT]).commands[0]).toBe('rnpm-plugin-test');
|
||||||
|
expect(findPlugins([ROOT]).platforms).toHaveLength(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns an empty array if there are no plugins in this folder', () => {
|
it('returns an empty array if there are no plugins in this folder', () => {
|
||||||
jest.mock(pjsonPath, () => ({}));
|
jest.mock(pjsonPath, () => ({}));
|
||||||
expect(findPlugins([ROOT])).toHaveLength(0);
|
expect(findPlugins([ROOT])).toHaveProperty('commands');
|
||||||
|
expect(findPlugins([ROOT])).toHaveProperty('platforms');
|
||||||
|
expect(findPlugins([ROOT]).commands).toHaveLength(0);
|
||||||
|
expect(findPlugins([ROOT]).platforms).toHaveLength(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns an empty array if there is no package.json in the supplied folder', () => {
|
it('returns an object with empty arrays if there is no package.json in the supplied folder', () => {
|
||||||
expect(Array.isArray(findPlugins(['fake-path']))).toBeTruthy();
|
expect(findPlugins(['fake-path'])).toHaveProperty('commands');
|
||||||
expect(findPlugins(['fake-path'])).toHaveLength(0);
|
expect(findPlugins(['fake-path'])).toHaveProperty('platforms');
|
||||||
|
expect(findPlugins(['fake-path']).commands).toHaveLength(0);
|
||||||
|
expect(findPlugins(['fake-path']).platforms).toHaveLength(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns plugins from both dependencies and dev dependencies', () => {
|
it('returns plugins from both dependencies and dev dependencies', () => {
|
||||||
|
@ -46,7 +55,10 @@ describe('findPlugins', () => {
|
||||||
dependencies: {'rnpm-plugin-test': '*'},
|
dependencies: {'rnpm-plugin-test': '*'},
|
||||||
devDependencies: {'rnpm-plugin-test-2': '*'},
|
devDependencies: {'rnpm-plugin-test-2': '*'},
|
||||||
}));
|
}));
|
||||||
expect(findPlugins([ROOT])).toHaveLength(2);
|
expect(findPlugins([ROOT])).toHaveProperty('commands');
|
||||||
|
expect(findPlugins([ROOT])).toHaveProperty('platforms');
|
||||||
|
expect(findPlugins([ROOT]).commands).toHaveLength(2);
|
||||||
|
expect(findPlugins([ROOT]).platforms).toHaveLength(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns unique list of plugins', () => {
|
it('returns unique list of plugins', () => {
|
||||||
|
@ -54,6 +66,6 @@ describe('findPlugins', () => {
|
||||||
dependencies: {'rnpm-plugin-test': '*'},
|
dependencies: {'rnpm-plugin-test': '*'},
|
||||||
devDependencies: {'rnpm-plugin-test': '*'},
|
devDependencies: {'rnpm-plugin-test': '*'},
|
||||||
}));
|
}));
|
||||||
expect(findPlugins([ROOT])).toHaveLength(1);
|
expect(findPlugins([ROOT]).commands).toHaveLength(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -37,11 +37,19 @@ const findPluginsInReactNativePackage = (pjson) => {
|
||||||
return path.join(pjson.name, pjson.rnpm.plugin);
|
return path.join(pjson.name, pjson.rnpm.plugin);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const findPlatformsInPackage = (pjson) => {
|
||||||
|
if (!pjson.rnpm || !pjson.rnpm.platform) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return path.join(pjson.name, pjson.rnpm.platform);
|
||||||
|
};
|
||||||
|
|
||||||
const findPluginInFolder = (folder) => {
|
const findPluginInFolder = (folder) => {
|
||||||
const pjson = readPackage(folder);
|
const pjson = readPackage(folder);
|
||||||
|
|
||||||
if (!pjson) {
|
if (!pjson) {
|
||||||
return [];
|
return {commands: [], platforms: []};
|
||||||
}
|
}
|
||||||
|
|
||||||
const deps = union(
|
const deps = union(
|
||||||
|
@ -51,27 +59,33 @@ const findPluginInFolder = (folder) => {
|
||||||
|
|
||||||
return deps.reduce(
|
return deps.reduce(
|
||||||
(acc, pkg) => {
|
(acc, pkg) => {
|
||||||
|
let commands = acc.commands;
|
||||||
|
let platforms = acc.platforms;
|
||||||
if (isRNPMPlugin(pkg)) {
|
if (isRNPMPlugin(pkg)) {
|
||||||
return acc.concat(pkg);
|
commands = commands.concat(pkg);
|
||||||
}
|
}
|
||||||
if (isReactNativePlugin(pkg)) {
|
if (isReactNativePlugin(pkg)) {
|
||||||
const pkgJson = readPackage(path.join(folder, 'node_modules', pkg));
|
const pkgJson = readPackage(path.join(folder, 'node_modules', pkg));
|
||||||
if (!pkgJson) {
|
if (pkgJson) {
|
||||||
return acc;
|
commands = commands.concat(findPluginsInReactNativePackage(pkgJson));
|
||||||
|
platforms = platforms.concat(findPlatformsInPackage(pkgJson));
|
||||||
}
|
}
|
||||||
return acc.concat(findPluginsInReactNativePackage(pkgJson));
|
|
||||||
}
|
}
|
||||||
return acc;
|
return {commands: commands, platforms: platforms};
|
||||||
},
|
},
|
||||||
[]
|
{commands: [], platforms: []}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find plugins in package.json of the given folder
|
* Find plugins in package.json of the given folder
|
||||||
* @param {String} folder Path to the folder to get the package.json from
|
* @param {String} folder Path to the folder to get the package.json from
|
||||||
* @type {Array} Array of plugins or an empty array if no package.json found
|
* @type {Object} Object of commands and platform plugins
|
||||||
*/
|
*/
|
||||||
module.exports = function findPlugins(folders) {
|
module.exports = function findPlugins(folders) {
|
||||||
return uniq(flatten(folders.map(findPluginInFolder)));
|
const plugins = folders.map(findPluginInFolder);
|
||||||
|
return {
|
||||||
|
commands: uniq(flatten(plugins.map(p => p.commands))),
|
||||||
|
platforms: uniq(flatten(plugins.map(p => p.platforms)))
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -15,7 +15,6 @@ const Config = require('../util/Config');
|
||||||
const findPlugins = require('./findPlugins');
|
const findPlugins = require('./findPlugins');
|
||||||
const findAssets = require('./findAssets');
|
const findAssets = require('./findAssets');
|
||||||
const ios = require('./ios');
|
const ios = require('./ios');
|
||||||
const windows = require('./windows');
|
|
||||||
const wrapCommands = require('./wrapCommands');
|
const wrapCommands = require('./wrapCommands');
|
||||||
|
|
||||||
/* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error
|
/* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error
|
||||||
|
@ -33,6 +32,10 @@ import type {ConfigT} from 'metro';
|
||||||
|
|
||||||
export type RNConfig = {
|
export type RNConfig = {
|
||||||
...ConfigT,
|
...ConfigT,
|
||||||
|
/**
|
||||||
|
* Returns an object with all platform configurations.
|
||||||
|
*/
|
||||||
|
getPlatformConfig(): Object,
|
||||||
/**
|
/**
|
||||||
* Returns an array of project commands used by the CLI to load
|
* Returns an array of project commands used by the CLI to load
|
||||||
*/
|
*/
|
||||||
|
@ -55,10 +58,21 @@ const attachPackage = (command, pkg) => Array.isArray(command)
|
||||||
? command.map(cmd => attachPackage(cmd, pkg))
|
? command.map(cmd => attachPackage(cmd, pkg))
|
||||||
: { ...command, pkg };
|
: { ...command, pkg };
|
||||||
|
|
||||||
|
const appRoot = process.cwd();
|
||||||
|
const plugins = findPlugins([appRoot]);
|
||||||
|
const pluginPlatforms = plugins
|
||||||
|
.platforms
|
||||||
|
.reduce((acc, pathToPlatforms) => {
|
||||||
|
// $FlowFixMe non-literal require
|
||||||
|
return Object.assign(acc, require(path.join(appRoot, 'node_modules', pathToPlatforms)));
|
||||||
|
},
|
||||||
|
{});
|
||||||
|
|
||||||
const defaultRNConfig = {
|
const defaultRNConfig = {
|
||||||
|
|
||||||
getProjectCommands(): Array<CommandT> {
|
getProjectCommands(): Array<CommandT> {
|
||||||
const appRoot = process.cwd();
|
const commands = plugins
|
||||||
const plugins = findPlugins([appRoot])
|
.commands
|
||||||
.map(pathToCommands => {
|
.map(pathToCommands => {
|
||||||
const name = pathToCommands.split(path.sep)[0];
|
const name = pathToCommands.split(path.sep)[0];
|
||||||
|
|
||||||
|
@ -70,35 +84,51 @@ const defaultRNConfig = {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
return flatten(plugins);
|
return flatten(commands);
|
||||||
|
},
|
||||||
|
|
||||||
|
getPlatformConfig(): Object {
|
||||||
|
return {
|
||||||
|
ios,
|
||||||
|
android,
|
||||||
|
...pluginPlatforms
|
||||||
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
getProjectConfig(): Object {
|
getProjectConfig(): Object {
|
||||||
|
const platforms = this.getPlatformConfig();
|
||||||
const folder = process.cwd();
|
const folder = process.cwd();
|
||||||
const rnpm = getRNPMConfig(folder);
|
const rnpm = getRNPMConfig(folder);
|
||||||
|
|
||||||
return Object.assign({}, rnpm, {
|
let config = Object.assign({}, rnpm, {
|
||||||
ios: ios.projectConfig(folder, rnpm.ios || {}),
|
|
||||||
android: android.projectConfig(folder, rnpm.android || {}),
|
|
||||||
windows: windows.projectConfig(folder, rnpm.windows || {}),
|
|
||||||
assets: findAssets(folder, rnpm.assets),
|
assets: findAssets(folder, rnpm.assets),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Object.keys(platforms).forEach(key => {
|
||||||
|
config[key] = platforms[key].projectConfig(folder, rnpm[key] || {});
|
||||||
|
});
|
||||||
|
|
||||||
|
return config;
|
||||||
},
|
},
|
||||||
|
|
||||||
getDependencyConfig(packageName: string) {
|
getDependencyConfig(packageName: string) {
|
||||||
|
const platforms = this.getPlatformConfig();
|
||||||
const folder = path.join(process.cwd(), 'node_modules', packageName);
|
const folder = path.join(process.cwd(), 'node_modules', packageName);
|
||||||
const rnpm = getRNPMConfig(
|
const rnpm = getRNPMConfig(
|
||||||
path.join(process.cwd(), 'node_modules', packageName)
|
path.join(process.cwd(), 'node_modules', packageName)
|
||||||
);
|
);
|
||||||
|
|
||||||
return Object.assign({}, rnpm, {
|
let config = Object.assign({}, rnpm, {
|
||||||
ios: ios.dependencyConfig(folder, rnpm.ios || {}),
|
|
||||||
android: android.dependencyConfig(folder, rnpm.android || {}),
|
|
||||||
windows: windows.dependencyConfig(folder, rnpm.windows || {}),
|
|
||||||
assets: findAssets(folder, rnpm.assets),
|
assets: findAssets(folder, rnpm.assets),
|
||||||
commands: wrapCommands(rnpm.commands),
|
commands: wrapCommands(rnpm.commands),
|
||||||
params: rnpm.params || [],
|
params: rnpm.params || [],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Object.keys(platforms).forEach(key => {
|
||||||
|
config[key] = platforms[key].dependencyConfig(folder, rnpm[key] || {});
|
||||||
|
});
|
||||||
|
|
||||||
|
return config;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
/**
|
|
||||||
* 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 glob = require('glob');
|
|
||||||
const path = require('path');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets package's namespace
|
|
||||||
* by searching for its declaration in all C# files present in the folder
|
|
||||||
*
|
|
||||||
* @param {String} folder Folder to find C# files
|
|
||||||
*/
|
|
||||||
module.exports = function getNamespace(folder) {
|
|
||||||
const files = glob.sync('**/*.cs', { cwd: folder });
|
|
||||||
|
|
||||||
const packages = files
|
|
||||||
.map(filePath => fs.readFileSync(path.join(folder, filePath), 'utf8'))
|
|
||||||
.map(file => file.match(/namespace (.*)[\s\S]+IReactPackage/))
|
|
||||||
.filter(match => match);
|
|
||||||
|
|
||||||
return packages.length ? packages[0][1] : null;
|
|
||||||
};
|
|
|
@ -1,30 +0,0 @@
|
||||||
/**
|
|
||||||
* 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 glob = require('glob');
|
|
||||||
const path = require('path');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets package's class name (class that implements IReactPackage)
|
|
||||||
* by searching for its declaration in all C# files present in the folder
|
|
||||||
*
|
|
||||||
* @param {String} folder Folder to find C# files
|
|
||||||
*/
|
|
||||||
module.exports = function getPackageClassName(folder) {
|
|
||||||
const files = glob.sync('**/*.cs', { cwd: folder });
|
|
||||||
|
|
||||||
const packages = files
|
|
||||||
.map(filePath => fs.readFileSync(path.join(folder, filePath), 'utf8'))
|
|
||||||
.map(file => file.match(/class (.*) : IReactPackage/))
|
|
||||||
.filter(match => match);
|
|
||||||
|
|
||||||
return packages.length ? packages[0][1] : null;
|
|
||||||
};
|
|
|
@ -1,27 +0,0 @@
|
||||||
/**
|
|
||||||
* 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 glob = require('glob');
|
|
||||||
const path = require('path');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find an C# project file
|
|
||||||
*
|
|
||||||
* @param {String} folder Name of the folder where to seek
|
|
||||||
* @return {String}
|
|
||||||
*/
|
|
||||||
module.exports = function findManifest(folder) {
|
|
||||||
const csprojPath = glob.sync(path.join('**', '*.csproj'), {
|
|
||||||
cwd: folder,
|
|
||||||
ignore: ['node_modules/**', '**/build/**', 'Examples/**', 'examples/**'],
|
|
||||||
})[0];
|
|
||||||
|
|
||||||
return csprojPath ? path.join(folder, csprojPath) : null;
|
|
||||||
};
|
|
|
@ -1,60 +0,0 @@
|
||||||
/**
|
|
||||||
* 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 glob = require('glob');
|
|
||||||
const path = require('path');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Glob pattern to look for solution file
|
|
||||||
*/
|
|
||||||
const GLOB_PATTERN = '**/*.sln';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Regexp matching all test projects
|
|
||||||
*/
|
|
||||||
const TEST_PROJECTS = /test|example|sample/i;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base windows folder
|
|
||||||
*/
|
|
||||||
const WINDOWS_BASE = 'windows';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* These folders will be excluded from search to speed it up
|
|
||||||
*/
|
|
||||||
const GLOB_EXCLUDE_PATTERN = ['**/@(node_modules)/**'];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Finds windows project by looking for all .sln files
|
|
||||||
* in given folder.
|
|
||||||
*
|
|
||||||
* Returns first match if files are found or null
|
|
||||||
*
|
|
||||||
* Note: `./windows/*.sln` are returned regardless of the name
|
|
||||||
*/
|
|
||||||
module.exports = function findSolution(folder) {
|
|
||||||
const projects = glob
|
|
||||||
.sync(GLOB_PATTERN, {
|
|
||||||
cwd: folder,
|
|
||||||
ignore: GLOB_EXCLUDE_PATTERN,
|
|
||||||
})
|
|
||||||
.filter(project => {
|
|
||||||
return path.dirname(project) === WINDOWS_BASE || !TEST_PROJECTS.test(project);
|
|
||||||
})
|
|
||||||
.sort((projectA, projectB) => {
|
|
||||||
return path.dirname(projectA) === WINDOWS_BASE ? -1 : 1;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (projects.length === 0) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return projects[0];
|
|
||||||
};
|
|
|
@ -1,10 +0,0 @@
|
||||||
const s4 = () => {
|
|
||||||
return Math.floor((1 + Math.random()) * 0x10000)
|
|
||||||
.toString(16)
|
|
||||||
.substring(1);
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = function generateGUID() {
|
|
||||||
return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
|
|
||||||
s4() + '-' + s4() + s4() + s4();
|
|
||||||
};
|
|
|
@ -1,114 +0,0 @@
|
||||||
/**
|
|
||||||
* 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 findWindowsSolution = require('./findWindowsSolution');
|
|
||||||
const findNamespace = require('./findNamespace');
|
|
||||||
const findProject = require('./findProject');
|
|
||||||
const findPackageClassName = require('./findPackageClassName');
|
|
||||||
const path = require('path');
|
|
||||||
const generateGUID = require('./generateGUID');
|
|
||||||
|
|
||||||
const relativeProjectPath = (fullProjPath) => {
|
|
||||||
const windowsPath = fullProjPath
|
|
||||||
.substring(fullProjPath.lastIndexOf('node_modules') - 1, fullProjPath.length)
|
|
||||||
.replace(/\//g, '\\');
|
|
||||||
|
|
||||||
return '..' + windowsPath;
|
|
||||||
};
|
|
||||||
|
|
||||||
const getProjectName = (fullProjPath) => {
|
|
||||||
return fullProjPath.split('/').slice(-1)[0].replace(/\.csproj/i, '');
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets windows project config by analyzing given folder and taking some
|
|
||||||
* defaults specified by user into consideration
|
|
||||||
*/
|
|
||||||
exports.projectConfig = function projectConfigWindows(folder, userConfig) {
|
|
||||||
|
|
||||||
const csSolution = userConfig.csSolution || findWindowsSolution(folder);
|
|
||||||
|
|
||||||
if (!csSolution) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// expects solutions to be named the same as project folders
|
|
||||||
const solutionPath = path.join(folder, csSolution);
|
|
||||||
const windowsAppFolder = csSolution.substring(0, csSolution.lastIndexOf('.sln'));
|
|
||||||
const src = userConfig.sourceDir || windowsAppFolder;
|
|
||||||
const sourceDir = path.join(folder, src);
|
|
||||||
const mainPage = path.join(sourceDir, 'MainPage.cs');
|
|
||||||
const projectPath = userConfig.projectPath || findProject(folder);
|
|
||||||
|
|
||||||
return {
|
|
||||||
sourceDir,
|
|
||||||
solutionPath,
|
|
||||||
projectPath,
|
|
||||||
mainPage,
|
|
||||||
folder,
|
|
||||||
userConfig,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Same as projectConfigWindows except it returns
|
|
||||||
* different config that applies to packages only
|
|
||||||
*/
|
|
||||||
exports.dependencyConfig = function dependencyConfigWindows(folder, userConfig) {
|
|
||||||
|
|
||||||
const csSolution = userConfig.csSolution || findWindowsSolution(folder);
|
|
||||||
|
|
||||||
if (!csSolution) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// expects solutions to be named the same as project folders
|
|
||||||
const windowsAppFolder = csSolution.substring(0, csSolution.lastIndexOf('.sln'));
|
|
||||||
const src = userConfig.sourceDir || windowsAppFolder;
|
|
||||||
|
|
||||||
if (!src) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const sourceDir = path.join(folder, src);
|
|
||||||
const packageClassName = findPackageClassName(sourceDir);
|
|
||||||
const namespace = userConfig.namespace || findNamespace(sourceDir);
|
|
||||||
const csProj = userConfig.csProj || findProject(folder);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This module has no package to export or no namespace
|
|
||||||
*/
|
|
||||||
if (!packageClassName || !namespace) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const packageUsingPath = userConfig.packageUsingPath ||
|
|
||||||
`using ${namespace};`;
|
|
||||||
|
|
||||||
const packageInstance = userConfig.packageInstance ||
|
|
||||||
`new ${packageClassName}()`;
|
|
||||||
|
|
||||||
const projectGUID = generateGUID();
|
|
||||||
const pathGUID = generateGUID();
|
|
||||||
const projectName = getProjectName(csProj);
|
|
||||||
const relativeProjPath = relativeProjectPath(csProj);
|
|
||||||
|
|
||||||
return {
|
|
||||||
sourceDir,
|
|
||||||
packageUsingPath,
|
|
||||||
packageInstance,
|
|
||||||
projectName,
|
|
||||||
csProj,
|
|
||||||
folder,
|
|
||||||
projectGUID,
|
|
||||||
pathGUID,
|
|
||||||
relativeProjPath,
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -39,6 +39,7 @@ describe('link', () => {
|
||||||
|
|
||||||
it('should accept a name of a dependency to link', (done) => {
|
it('should accept a name of a dependency to link', (done) => {
|
||||||
const config = {
|
const config = {
|
||||||
|
getPlatformConfig: () => ({ios: {}, android: {}}),
|
||||||
getProjectConfig: () => ({ assets: [] }),
|
getProjectConfig: () => ({ assets: [] }),
|
||||||
getDependencyConfig: sinon.stub().returns({ assets: [], commands: {} }),
|
getDependencyConfig: sinon.stub().returns({ assets: [], commands: {} }),
|
||||||
};
|
};
|
||||||
|
@ -54,6 +55,7 @@ describe('link', () => {
|
||||||
|
|
||||||
it('should read dependencies from package.json when name not provided', (done) => {
|
it('should read dependencies from package.json when name not provided', (done) => {
|
||||||
const config = {
|
const config = {
|
||||||
|
getPlatformConfig: () => ({ios: {}, android: {}}),
|
||||||
getProjectConfig: () => ({ assets: [] }),
|
getProjectConfig: () => ({ assets: [] }),
|
||||||
getDependencyConfig: sinon.stub().returns({ assets: [], commands: {} }),
|
getDependencyConfig: sinon.stub().returns({ assets: [], commands: {} }),
|
||||||
};
|
};
|
||||||
|
@ -80,6 +82,7 @@ describe('link', () => {
|
||||||
const registerNativeModule = sinon.stub();
|
const registerNativeModule = sinon.stub();
|
||||||
const dependencyConfig = {android: {}, ios: {}, assets: [], commands: {}};
|
const dependencyConfig = {android: {}, ios: {}, assets: [], commands: {}};
|
||||||
const config = {
|
const config = {
|
||||||
|
getPlatformConfig: () => ({ios: {}, android: {}}),
|
||||||
getProjectConfig: () => ({android: {}, ios: {}, assets: []}),
|
getProjectConfig: () => ({android: {}, ios: {}, assets: []}),
|
||||||
getDependencyConfig: sinon.stub().returns(dependencyConfig),
|
getDependencyConfig: sinon.stub().returns(dependencyConfig),
|
||||||
};
|
};
|
||||||
|
@ -116,6 +119,7 @@ describe('link', () => {
|
||||||
const registerNativeModule = sinon.stub();
|
const registerNativeModule = sinon.stub();
|
||||||
const dependencyConfig = {ios: {}, android: {}, assets: [], commands: {}};
|
const dependencyConfig = {ios: {}, android: {}, assets: [], commands: {}};
|
||||||
const config = {
|
const config = {
|
||||||
|
getPlatformConfig: () => ({ios: {}, android: {}}),
|
||||||
getProjectConfig: () => ({ ios: {}, android: {}, assets: [] }),
|
getProjectConfig: () => ({ ios: {}, android: {}, assets: [] }),
|
||||||
getDependencyConfig: sinon.stub().returns(dependencyConfig),
|
getDependencyConfig: sinon.stub().returns(dependencyConfig),
|
||||||
};
|
};
|
||||||
|
@ -148,6 +152,62 @@ describe('link', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should register native modules for plugins', (done) => {
|
||||||
|
const registerNativeModule = sinon.stub();
|
||||||
|
const dependencyConfig = {ios: {}, android: {}, test: {}, assets: [], commands: {}};
|
||||||
|
const linkPluginConfig = { isInstalled: () => false, register: registerNativeModule };
|
||||||
|
const config = {
|
||||||
|
getPlatformConfig: () => ({ ios: {}, android: {}, test: { linkConfig: () => linkPluginConfig }}),
|
||||||
|
getProjectConfig: () => ({ ios: {}, android: {}, test: {}, assets: [] }),
|
||||||
|
getDependencyConfig: sinon.stub().returns(dependencyConfig),
|
||||||
|
};
|
||||||
|
|
||||||
|
jest.setMock(
|
||||||
|
'../ios/isInstalled.js',
|
||||||
|
sinon.stub().returns(true)
|
||||||
|
);
|
||||||
|
|
||||||
|
jest.setMock(
|
||||||
|
'../android/isInstalled.js',
|
||||||
|
sinon.stub().returns(true)
|
||||||
|
);
|
||||||
|
|
||||||
|
const link = require('../link').func;
|
||||||
|
|
||||||
|
link(['react-native-blur'], config).then(() => {
|
||||||
|
expect(registerNativeModule.calledOnce).toBeTruthy();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not register native modules for plugins when already installed', (done) => {
|
||||||
|
const registerNativeModule = sinon.stub();
|
||||||
|
const dependencyConfig = {ios: {}, android: {}, test: {}, assets: [], commands: {}};
|
||||||
|
const linkPluginConfig = { isInstalled: () => true, register: registerNativeModule};
|
||||||
|
const config = {
|
||||||
|
getPlatformConfig: () => ({ ios: {}, android: {}, test: { linkConfig: () => linkPluginConfig }}),
|
||||||
|
getProjectConfig: () => ({ ios: {}, android: {}, test: {}, assets: [] }),
|
||||||
|
getDependencyConfig: sinon.stub().returns(dependencyConfig),
|
||||||
|
};
|
||||||
|
|
||||||
|
jest.setMock(
|
||||||
|
'../ios/isInstalled.js',
|
||||||
|
sinon.stub().returns(true)
|
||||||
|
);
|
||||||
|
|
||||||
|
jest.setMock(
|
||||||
|
'../android/isInstalled.js',
|
||||||
|
sinon.stub().returns(true)
|
||||||
|
);
|
||||||
|
|
||||||
|
const link = require('../link').func;
|
||||||
|
|
||||||
|
link(['react-native-blur'], config).then(() => {
|
||||||
|
expect(registerNativeModule.callCount).toEqual(0);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should run prelink and postlink commands at the appropriate times', (done) => {
|
it('should run prelink and postlink commands at the appropriate times', (done) => {
|
||||||
const registerNativeModule = sinon.stub();
|
const registerNativeModule = sinon.stub();
|
||||||
const prelink = sinon.stub().yieldsAsync();
|
const prelink = sinon.stub().yieldsAsync();
|
||||||
|
@ -164,6 +224,7 @@ describe('link', () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
|
getPlatformConfig: () => ({ ios: {}}),
|
||||||
getProjectConfig: () => ({ ios: {}, assets: [] }),
|
getProjectConfig: () => ({ ios: {}, assets: [] }),
|
||||||
getDependencyConfig: sinon.stub().returns({
|
getDependencyConfig: sinon.stub().returns({
|
||||||
ios: {}, assets: [], commands: { prelink, postlink },
|
ios: {}, assets: [], commands: { prelink, postlink },
|
||||||
|
@ -181,7 +242,7 @@ describe('link', () => {
|
||||||
|
|
||||||
it('should copy assets from both project and dependencies projects', (done) => {
|
it('should copy assets from both project and dependencies projects', (done) => {
|
||||||
const dependencyAssets = ['Fonts/Font.ttf'];
|
const dependencyAssets = ['Fonts/Font.ttf'];
|
||||||
const dependencyConfig = {assets: dependencyAssets, commands: {}};
|
const dependencyConfig = {assets: dependencyAssets, ios: {}, commands: {}};
|
||||||
const projectAssets = ['Fonts/FontC.ttf'];
|
const projectAssets = ['Fonts/FontC.ttf'];
|
||||||
const copyAssets = sinon.stub();
|
const copyAssets = sinon.stub();
|
||||||
|
|
||||||
|
@ -191,6 +252,7 @@ describe('link', () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
|
getPlatformConfig: () => ({ ios: {} }),
|
||||||
getProjectConfig: () => ({ ios: {}, assets: projectAssets }),
|
getProjectConfig: () => ({ ios: {}, assets: projectAssets }),
|
||||||
getDependencyConfig: sinon.stub().returns(dependencyConfig),
|
getDependencyConfig: sinon.stub().returns(dependencyConfig),
|
||||||
};
|
};
|
||||||
|
|
|
@ -27,11 +27,9 @@ const chalk = require('chalk');
|
||||||
const isEmpty = require('lodash').isEmpty;
|
const isEmpty = require('lodash').isEmpty;
|
||||||
const promiseWaterfall = require('./promiseWaterfall');
|
const promiseWaterfall = require('./promiseWaterfall');
|
||||||
const registerDependencyAndroid = require('./android/registerNativeModule');
|
const registerDependencyAndroid = require('./android/registerNativeModule');
|
||||||
const registerDependencyWindows = require('./windows/registerNativeModule');
|
|
||||||
const registerDependencyIOS = require('./ios/registerNativeModule');
|
const registerDependencyIOS = require('./ios/registerNativeModule');
|
||||||
const registerDependencyPods = require('./pods/registerNativeModule');
|
const registerDependencyPods = require('./pods/registerNativeModule');
|
||||||
const isInstalledAndroid = require('./android/isInstalled');
|
const isInstalledAndroid = require('./android/isInstalled');
|
||||||
const isInstalledWindows = require('./windows/isInstalled');
|
|
||||||
const isInstalledIOS = require('./ios/isInstalled');
|
const isInstalledIOS = require('./ios/isInstalled');
|
||||||
const isInstalledPods = require('./pods/isInstalled');
|
const isInstalledPods = require('./pods/isInstalled');
|
||||||
const copyAssetsAndroid = require('./android/copyAssets');
|
const copyAssetsAndroid = require('./android/copyAssets');
|
||||||
|
@ -76,31 +74,40 @@ const linkDependencyAndroid = (androidProject, dependency) => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const linkDependencyWindows = (windowsProject, dependency) => {
|
const linkDependencyPlatforms = (platforms, project, dependency) => {
|
||||||
|
const ignorePlatforms = ['android', 'ios'];
|
||||||
|
Object.keys(platforms || {})
|
||||||
|
.filter(platform => ignorePlatforms.indexOf(platform) < 0)
|
||||||
|
.forEach(platform => {
|
||||||
|
if (!project[platform] || !dependency.config[platform]) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if (!windowsProject || !dependency.config.windows) {
|
const linkConfig = platforms[platform] && platforms[platform].linkConfig && platforms[platform].linkConfig();
|
||||||
return null;
|
if (!linkConfig || !linkConfig.isInstalled || !linkConfig.register) {
|
||||||
}
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
const isInstalled = isInstalledWindows(windowsProject, dependency.config.windows);
|
const isInstalled = linkConfig.isInstalled(project[platform], dependency.config[platform]);
|
||||||
|
|
||||||
if (isInstalled) {
|
if (isInstalled) {
|
||||||
log.info(chalk.grey(`Windows module ${dependency.name} is already linked`));
|
log.info(chalk.grey(`Platform '${platform}' module ${dependency.name} is already linked`));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return pollParams(dependency.config.params).then(params => {
|
return pollParams(dependency.config.params).then(params => {
|
||||||
log.info(`Linking ${dependency.name} windows dependency`);
|
log.info(`Linking ${dependency.name} ${platform} dependency`);
|
||||||
|
|
||||||
registerDependencyWindows(
|
linkConfig.register(
|
||||||
dependency.name,
|
dependency.name,
|
||||||
dependency.config.windows,
|
dependency.config[platform],
|
||||||
params,
|
params,
|
||||||
windowsProject
|
project[platform]
|
||||||
);
|
);
|
||||||
|
|
||||||
log.info(`Windows module ${dependency.name} has been successfully linked`);
|
log.info(`Platform '${platform}' module ${dependency.name} has been successfully linked`);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const linkDependencyIOS = (iOSProject, dependency) => {
|
const linkDependencyIOS = (iOSProject, dependency) => {
|
||||||
|
@ -124,7 +131,7 @@ const linkDependencyIOS = (iOSProject, dependency) => {
|
||||||
log.info(`iOS module ${dependency.name} has been successfully linked`);
|
log.info(`iOS module ${dependency.name} has been successfully linked`);
|
||||||
};
|
};
|
||||||
|
|
||||||
const linkAssets = (project, assets) => {
|
const linkAssets = (platforms, project, assets) => {
|
||||||
if (isEmpty(assets)) {
|
if (isEmpty(assets)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -139,6 +146,19 @@ const linkAssets = (project, assets) => {
|
||||||
copyAssetsAndroid(assets, project.android.assetsPath);
|
copyAssetsAndroid(assets, project.android.assetsPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ignorePlatforms = ['android', 'ios'];
|
||||||
|
Object.keys(platforms || {})
|
||||||
|
.filter(platform => ignorePlatforms.indexOf(platform) < 0)
|
||||||
|
.forEach(platform => {
|
||||||
|
const linkConfig = platforms[platform] && platforms[platform].linkConfig && platforms[platform].linkConfig();
|
||||||
|
if (!linkConfig || !linkConfig.copyAssets) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info(`Linking assets to ${platform} project`);
|
||||||
|
linkConfig.copyAssets(assets, project[platform]);
|
||||||
|
});
|
||||||
|
|
||||||
log.info('Assets have been successfully linked to your project');
|
log.info('Assets have been successfully linked to your project');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -150,9 +170,11 @@ const linkAssets = (project, assets) => {
|
||||||
* @param config CLI config, see local-cli/core/index.js
|
* @param config CLI config, see local-cli/core/index.js
|
||||||
*/
|
*/
|
||||||
function link(args: Array<string>, config: RNConfig) {
|
function link(args: Array<string>, config: RNConfig) {
|
||||||
var project;
|
let project;
|
||||||
|
let platforms;
|
||||||
try {
|
try {
|
||||||
project = config.getProjectConfig();
|
project = config.getProjectConfig();
|
||||||
|
platforms = config.getPlatformConfig();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
log.error(
|
log.error(
|
||||||
'ERRPACKAGEJSON',
|
'ERRPACKAGEJSON',
|
||||||
|
@ -161,7 +183,8 @@ function link(args: Array<string>, config: RNConfig) {
|
||||||
return Promise.reject(err);
|
return Promise.reject(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!project.android && !project.ios && !project.windows && findReactNativeScripts()) {
|
const hasProjectConfig = Object.keys(platforms).reduce((acc, key) => acc || key in project, false);
|
||||||
|
if (!hasProjectConfig && findReactNativeScripts()) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'`react-native link` can not be used in Create React Native App projects. ' +
|
'`react-native link` can not be used in Create React Native App projects. ' +
|
||||||
'If you need to include a library that relies on custom native code, ' +
|
'If you need to include a library that relies on custom native code, ' +
|
||||||
|
@ -183,7 +206,7 @@ function link(args: Array<string>, config: RNConfig) {
|
||||||
);
|
);
|
||||||
|
|
||||||
const assets = dedupeAssets(dependencies.reduce(
|
const assets = dedupeAssets(dependencies.reduce(
|
||||||
(assets, dependency) => assets.concat(dependency.config.assets),
|
(acc, dependency) => acc.concat(dependency.config.assets),
|
||||||
project.assets
|
project.assets
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@ -191,11 +214,11 @@ function link(args: Array<string>, config: RNConfig) {
|
||||||
() => promisify(dependency.config.commands.prelink || commandStub),
|
() => promisify(dependency.config.commands.prelink || commandStub),
|
||||||
() => linkDependencyAndroid(project.android, dependency),
|
() => linkDependencyAndroid(project.android, dependency),
|
||||||
() => linkDependencyIOS(project.ios, dependency),
|
() => linkDependencyIOS(project.ios, dependency),
|
||||||
() => linkDependencyWindows(project.windows, dependency),
|
() => linkDependencyPlatforms(platforms, project, dependency),
|
||||||
() => promisify(dependency.config.commands.postlink || commandStub),
|
() => promisify(dependency.config.commands.postlink || commandStub),
|
||||||
]));
|
]));
|
||||||
|
|
||||||
tasks.push(() => linkAssets(project, assets));
|
tasks.push(() => linkAssets(platforms, project, assets));
|
||||||
|
|
||||||
return promiseWaterfall(tasks).catch(err => {
|
return promiseWaterfall(tasks).catch(err => {
|
||||||
log.error(
|
log.error(
|
||||||
|
|
|
@ -2,11 +2,9 @@ const log = require('npmlog');
|
||||||
|
|
||||||
const getProjectDependencies = require('./getProjectDependencies');
|
const getProjectDependencies = require('./getProjectDependencies');
|
||||||
const unregisterDependencyAndroid = require('./android/unregisterNativeModule');
|
const unregisterDependencyAndroid = require('./android/unregisterNativeModule');
|
||||||
const unregisterDependencyWindows = require('./windows/unregisterNativeModule');
|
|
||||||
const unregisterDependencyIOS = require('./ios/unregisterNativeModule');
|
const unregisterDependencyIOS = require('./ios/unregisterNativeModule');
|
||||||
const unregisterDependencyPods = require('./pods/unregisterNativeModule');
|
const unregisterDependencyPods = require('./pods/unregisterNativeModule');
|
||||||
const isInstalledAndroid = require('./android/isInstalled');
|
const isInstalledAndroid = require('./android/isInstalled');
|
||||||
const isInstalledWindows = require('./windows/isInstalled');
|
|
||||||
const isInstalledIOS = require('./ios/isInstalled');
|
const isInstalledIOS = require('./ios/isInstalled');
|
||||||
const isInstalledPods = require('./pods/isInstalled');
|
const isInstalledPods = require('./pods/isInstalled');
|
||||||
const unlinkAssetsAndroid = require('./android/unlinkAssets');
|
const unlinkAssetsAndroid = require('./android/unlinkAssets');
|
||||||
|
@ -42,23 +40,38 @@ const unlinkDependencyAndroid = (androidProject, dependency, packageName) => {
|
||||||
log.info(`Android module ${packageName} has been successfully unlinked`);
|
log.info(`Android module ${packageName} has been successfully unlinked`);
|
||||||
};
|
};
|
||||||
|
|
||||||
const unlinkDependencyWindows = (windowsProject, dependency, packageName) => {
|
const unlinkDependencyPlatforms = (platforms, project, dependency, packageName) => {
|
||||||
if (!windowsProject || !dependency.windows) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const isInstalled = isInstalledWindows(windowsProject, dependency.windows);
|
const ignorePlatforms = ['android', 'ios'];
|
||||||
|
Object.keys(platforms || {})
|
||||||
|
.filter(platform => ignorePlatforms.indexOf(platform) < 0)
|
||||||
|
.forEach(platform => {
|
||||||
|
if (!project[platform] || !dependency[platform]) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if (!isInstalled) {
|
const linkConfig = platforms[platform] && platforms[platform].linkConfig && platforms[platform].linkConfig();
|
||||||
log.info(`Windows module ${packageName} is not installed`);
|
if (!linkConfig || !linkConfig.isInstalled || !linkConfig.unregister) {
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info(`Unlinking ${packageName} windows dependency`);
|
const isInstalled = linkConfig.isInstalled(project[platform], dependency[platform]);
|
||||||
|
|
||||||
unregisterDependencyWindows(packageName, dependency.windows, windowsProject);
|
if (!isInstalled) {
|
||||||
|
log.info(`Platform '${platform}' module ${packageName} is not installed`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
log.info(`Windows module ${packageName} has been successfully unlinked`);
|
log.info(`Unlinking ${packageName} ${platform} dependency`);
|
||||||
|
|
||||||
|
linkConfig.unregister(
|
||||||
|
packageName,
|
||||||
|
dependency[platform],
|
||||||
|
project[platform]
|
||||||
|
);
|
||||||
|
|
||||||
|
log.info(`Platform '${platform}' module ${dependency.name} has been successfully unlinked`);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const unlinkDependencyIOS = (iOSProject, dependency, packageName, iOSDependencies) => {
|
const unlinkDependencyIOS = (iOSProject, dependency, packageName, iOSDependencies) => {
|
||||||
|
@ -94,10 +107,12 @@ const unlinkDependencyIOS = (iOSProject, dependency, packageName, iOSDependencie
|
||||||
function unlink(args, config) {
|
function unlink(args, config) {
|
||||||
const packageName = args[0];
|
const packageName = args[0];
|
||||||
|
|
||||||
var project;
|
let platforms;
|
||||||
var dependency;
|
let project;
|
||||||
|
let dependency;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
platforms = config.getPlatformConfig();
|
||||||
project = config.getProjectConfig();
|
project = config.getProjectConfig();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
log.error(
|
log.error(
|
||||||
|
@ -125,7 +140,7 @@ function unlink(args, config) {
|
||||||
() => promisify(dependency.commands.preunlink || commandStub),
|
() => promisify(dependency.commands.preunlink || commandStub),
|
||||||
() => unlinkDependencyAndroid(project.android, dependency, packageName),
|
() => unlinkDependencyAndroid(project.android, dependency, packageName),
|
||||||
() => unlinkDependencyIOS(project.ios, dependency, packageName, iOSDependencies),
|
() => unlinkDependencyIOS(project.ios, dependency, packageName, iOSDependencies),
|
||||||
() => unlinkDependencyWindows(project.windows, dependency, packageName),
|
() => unlinkDependencyPlatforms(platforms, project, dependency, packageName),
|
||||||
() => promisify(dependency.commands.postunlink || commandStub)
|
() => promisify(dependency.commands.postunlink || commandStub)
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
const fs = require('fs');
|
|
||||||
const makeUsingPatch = require('./patches/makeUsingPatch');
|
|
||||||
|
|
||||||
module.exports = function isInstalled(config, dependencyConfig) {
|
|
||||||
return fs
|
|
||||||
.readFileSync(config.mainPage)
|
|
||||||
.indexOf(makeUsingPatch(dependencyConfig.packageUsingPath).patch) > -1;
|
|
||||||
};
|
|
|
@ -1,23 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) 2013-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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const toCamelCase = require('lodash').camelCase;
|
|
||||||
|
|
||||||
module.exports = function applyParams(str, params, prefix) {
|
|
||||||
return str.replace(
|
|
||||||
/\$\{(\w+)\}/g,
|
|
||||||
(pattern, param) => {
|
|
||||||
const name = toCamelCase(prefix) + '_' + param;
|
|
||||||
|
|
||||||
return params[param]
|
|
||||||
? `getResources().getString(R.string.${name})`
|
|
||||||
: null;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
|
@ -1,11 +0,0 @@
|
||||||
const fs = require('fs');
|
|
||||||
|
|
||||||
module.exports = function applyPatch(file, patch, flip = false) {
|
|
||||||
|
|
||||||
fs.writeFileSync(file, fs
|
|
||||||
.readFileSync(file, 'utf8')
|
|
||||||
.replace(patch.pattern, match => {
|
|
||||||
return flip ? `${patch.patch}${match}` : `${match}${patch.patch}`;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
};
|
|
|
@ -1,10 +0,0 @@
|
||||||
const applyParams = require('./applyParams');
|
|
||||||
|
|
||||||
module.exports = function makePackagePatch(packageInstance, params, prefix) {
|
|
||||||
const processedInstance = applyParams(packageInstance, params, prefix);
|
|
||||||
|
|
||||||
return {
|
|
||||||
pattern: 'new MainReactPackage()',
|
|
||||||
patch: ',\n ' + processedInstance,
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -1,14 +0,0 @@
|
||||||
module.exports = function makeProjectPatch(windowsConfig) {
|
|
||||||
|
|
||||||
const projectInsert = `<ProjectReference Include="..\\${windowsConfig.relativeProjPath}">
|
|
||||||
<Project>{${windowsConfig.pathGUID}}</Project>
|
|
||||||
<Name>${windowsConfig.projectName}</Name>
|
|
||||||
</ProjectReference>
|
|
||||||
`;
|
|
||||||
|
|
||||||
return {
|
|
||||||
pattern: '<ProjectReference Include="..\\..\\node_modules\\react-native-windows\\ReactWindows\\ReactNative\\ReactNative.csproj">',
|
|
||||||
patch: projectInsert,
|
|
||||||
unpatch: new RegExp(`<ProjectReference.+\\s+.+\\s+.+${windowsConfig.projectName}.+\\s+.+\\s`),
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -1,12 +0,0 @@
|
||||||
module.exports = function makeSolutionPatch(windowsConfig) {
|
|
||||||
|
|
||||||
const solutionInsert = `Project("{${windowsConfig.projectGUID.toUpperCase()}}") = "${windowsConfig.projectName}", "${windowsConfig.relativeProjPath}", "{${windowsConfig.pathGUID.toUpperCase()}}"
|
|
||||||
EndProject
|
|
||||||
`;
|
|
||||||
|
|
||||||
return {
|
|
||||||
pattern: 'Global',
|
|
||||||
patch: solutionInsert,
|
|
||||||
unpatch: new RegExp(`Project.+${windowsConfig.projectName}.+\\s+EndProject\\s+`),
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -1,6 +0,0 @@
|
||||||
module.exports = function makeUsingPatch(packageImportPath) {
|
|
||||||
return {
|
|
||||||
pattern: 'using ReactNative.Modules.Core;',
|
|
||||||
patch: '\n' + packageImportPath,
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -1,9 +0,0 @@
|
||||||
const fs = require('fs');
|
|
||||||
|
|
||||||
module.exports = function revokePatch(file, patch) {
|
|
||||||
const unpatch = patch.unpatch || patch.patch;
|
|
||||||
fs.writeFileSync(file, fs
|
|
||||||
.readFileSync(file, 'utf8')
|
|
||||||
.replace(unpatch, '')
|
|
||||||
);
|
|
||||||
};
|
|
|
@ -1,26 +0,0 @@
|
||||||
const applyPatch = require('./patches/applyPatch');
|
|
||||||
|
|
||||||
const makeProjectPatch = require('./patches/makeProjectPatch');
|
|
||||||
const makeSolutionPatch = require('./patches/makeSolutionPatch');
|
|
||||||
const makeUsingPatch = require('./patches/makeUsingPatch');
|
|
||||||
const makePackagePatch = require('./patches/makePackagePatch');
|
|
||||||
|
|
||||||
module.exports = function registerNativeWindowsModule(
|
|
||||||
name,
|
|
||||||
windowsConfig,
|
|
||||||
params,
|
|
||||||
projectConfig
|
|
||||||
) {
|
|
||||||
applyPatch(projectConfig.projectPath, makeProjectPatch(windowsConfig), true);
|
|
||||||
applyPatch(projectConfig.solutionPath, makeSolutionPatch(windowsConfig), true);
|
|
||||||
|
|
||||||
applyPatch(
|
|
||||||
projectConfig.mainPage,
|
|
||||||
makePackagePatch(windowsConfig.packageInstance, params, name)
|
|
||||||
);
|
|
||||||
|
|
||||||
applyPatch(
|
|
||||||
projectConfig.mainPage,
|
|
||||||
makeUsingPatch(windowsConfig.packageUsingPath)
|
|
||||||
);
|
|
||||||
};
|
|
|
@ -1,27 +0,0 @@
|
||||||
const fs = require('fs');
|
|
||||||
const toCamelCase = require('lodash').camelCase;
|
|
||||||
|
|
||||||
const revokePatch = require('./patches/revokePatch');
|
|
||||||
const makeProjectPatch = require('./patches/makeProjectPatch');
|
|
||||||
const makeSolutionPatch = require('./patches/makeSolutionPatch');
|
|
||||||
const makeUsingPatch = require('./patches/makeUsingPatch');
|
|
||||||
const makePackagePatch = require('./patches/makePackagePatch');
|
|
||||||
|
|
||||||
module.exports = function unregisterNativeWindowsModule(
|
|
||||||
name,
|
|
||||||
windowsConfig,
|
|
||||||
projectConfig
|
|
||||||
) {
|
|
||||||
revokePatch(projectConfig.projectPath, makeProjectPatch(windowsConfig));
|
|
||||||
revokePatch(projectConfig.solutionPath, makeSolutionPatch(windowsConfig));
|
|
||||||
|
|
||||||
revokePatch(
|
|
||||||
projectConfig.mainPage,
|
|
||||||
makePackagePatch(windowsConfig.packageInstance, {}, name)
|
|
||||||
);
|
|
||||||
|
|
||||||
revokePatch(
|
|
||||||
projectConfig.mainPage,
|
|
||||||
makeUsingPatch(windowsConfig.packageUsingPath)
|
|
||||||
);
|
|
||||||
};
|
|
Loading…
Reference in New Issue