Skip to content

Commit

Permalink
fix(CLI): Adds CLI config and link plugin (#1601)
Browse files Browse the repository at this point in the history
There is a pending change against the RN CLI to allow platform plugins to provide their own configuration and, optionally, plug into the `link` and `unlink` commands.

In terms of net new changes, the only files that need to be reviewed are:
- local-cli/link/index.js
- local-cli/platform.js
- package.json

All other files are copy/paste from React Native.
  • Loading branch information
rozele committed Feb 20, 2018
1 parent c0b1d8f commit a1a23c3
Show file tree
Hide file tree
Showing 24 changed files with 580 additions and 1 deletion.
21 changes: 21 additions & 0 deletions local-cli/core/windows/findDependencyProject.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* 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 findProjectWithFilePattern = require('./findProjectWithFilePattern');

/**
* Find a C# dependency project file
*
* @param {String} folder Name of the folder where to seek
* @return {String}
*/
module.exports = function findDependencyProject(folder) {
return findProjectWithFilePattern(folder, /class\s+\S+\s*:\s*IReactPackage/);
};
34 changes: 34 additions & 0 deletions local-cli/core/windows/findMainFile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/**
* 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 the main file for the C# project
*
* @param {String} folder Name of the folder where to seek
* @return {String}
*/
module.exports = function findMainFile(folder) {
let mainFilePath = glob.sync('MainReactNativeHost.cs', {
cwd: folder,
ignore: ['node_modules/**', '**/build/**', 'Examples/**', 'examples/**'],
});

if (mainFilePath.length === 0) {
mainFilePath = glob.sync('MainPage.cs', {
cwd: folder,
ignore: ['node_modules/**', '**/build/**', 'Examples/**', 'examples/**'],
});
}

return mainFilePath && mainFilePath.length > 0 ? path.join(folder, mainFilePath[0]) : null;
};
30 changes: 30 additions & 0 deletions local-cli/core/windows/findNamespace.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* 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;
};
30 changes: 30 additions & 0 deletions local-cli/core/windows/findPackageClassName.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* 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;
};
21 changes: 21 additions & 0 deletions local-cli/core/windows/findProject.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* 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 findProjectWithFilePattern = require('./findProjectWithFilePattern');

/**
* Find a C# dependency project file
*
* @param {String} folder Name of the folder where to seek
* @return {String}
*/
module.exports = function findDependencyProject(folder) {
return findProjectWithFilePattern(folder, /class\s+\S+\s*:\s*(ReactNativeHost|ReactPage)/);
};
22 changes: 22 additions & 0 deletions local-cli/core/windows/findProjectGUID.js
Original file line number Diff line number Diff line change
@@ -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';

const fs = require('fs');

/**
* Gets GUID of dependency project.
*
* @param {String} folder Path to dependency project .csproj
*/
module.exports = function findProjectGuid(path) {
const file = fs.readFileSync(path, 'utf8');
const result = file.match(/<ProjectGuid>\{(.*)\}<\/ProjectGuid>/);
return result ? result[1] : null;
};
22 changes: 22 additions & 0 deletions local-cli/core/windows/findProjectName.js
Original file line number Diff line number Diff line change
@@ -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';

const fs = require('fs');

/**
* Gets name of dependency project.
*
* @param {String} folder Path to dependency project .csproj
*/
module.exports = function findProjectGuid(path) {
const file = fs.readFileSync(path, 'utf8');
const result = file.match(/<AssemblyName>(.*)<\/AssemblyName>/);
return result ? result[1] : null;
};
47 changes: 47 additions & 0 deletions local-cli/core/windows/findProjectWithFilePattern.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* 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');

/**
* Find an C# project file
*
* @param {String} folder Name of the folder where to seek
* @return {String}
*/
module.exports = function findProjectWithFilePattern(folder, pattern) {
const csprojPaths = glob.sync(path.join('**', '*.csproj'), {
cwd: folder,
ignore: ['node_modules/**', '**/build/**', 'Examples/**', 'examples/**', '**/bin/**', '**/obj/**' ],
});

// Search all folders with *.csproj files for one that exports an `IReactPackage`
for (var csprojPath of csprojPaths) {
const csprojFullPath = path.join(folder, csprojPath);
const csprojDir = path.dirname(csprojFullPath);
const files = glob.sync(path.join('**', '*.cs'), {
cwd: csprojDir,
ignore: ['node_modules/**', '**/build/**', 'Examples/**', 'examples/**', '**/bin/**', '**/obj/**' ],
});

const packages = files
.map(filePath => fs.readFileSync(path.join(csprojDir, filePath), 'utf8'))
.map(file => file.match(pattern))
.filter(match => match);

if (packages.length) {
return csprojFullPath;
}
}

return null;
};
60 changes: 60 additions & 0 deletions local-cli/core/windows/findWindowsSolution.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/**
* 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];
};
100 changes: 100 additions & 0 deletions local-cli/core/windows/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/**
* 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 findDependencyProject = require('./findDependencyProject');
const findProjectName = require('./findProjectName');
const findProjectGUID = require('./findProjectGUID');
const findPackageClassName = require('./findPackageClassName');
const findMainFile = require('./findMainFile');
const path = require('path');

const relativeProjectPath = (fullProjPath) => {
const windowsPath = fullProjPath
.substring(fullProjPath.lastIndexOf("node_modules") - 1, fullProjPath.length)
.replace(/\//g, '\\');

return path.join('..', windowsPath);
};

/**
* 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);
const projectPath = userConfig.projectPath || findProject(folder);

if (!csSolution || !projectPath) {
return null;
}

// expects solutions to be named the same as project folders
const solutionPath = path.join(folder, csSolution);
const sourceDir = userConfig.sourceDir || path.dirname(projectPath);
const mainFilePath = findMainFile(sourceDir);

return {
sourceDir,
solutionPath,
projectPath,
mainFilePath,
folder,
userConfig,
};
};

/**
* Same as projectConfigWindows except it returns
* different config that applies to packages only
*/
exports.dependencyConfig = function dependencyConfigWindows(folder, userConfig) {

const projectPath = userConfig.projectPath || findDependencyProject(folder);

if (!projectPath) {
return null;
}

const sourceDir = userConfig.sourceDir || path.dirname(projectPath);
const packageClassName = findPackageClassName(sourceDir);
const namespace = userConfig.namespace || findNamespace(sourceDir);

/**
* 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 = findProjectGUID(projectPath);
const projectName = findProjectName(projectPath);
const relativeProjPath = relativeProjectPath(projectPath);

return {
sourceDir,
packageUsingPath,
packageInstance,
projectName,
projectPath,
folder,
projectGUID,
relativeProjPath,
};
};
Loading

0 comments on commit a1a23c3

Please sign in to comment.