Skip to content

Commit dc619c9

Browse files
committed
fix(CLI): Adds CLI config and link plugin
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.
1 parent 080b99a commit dc619c9

24 files changed

+583
-1
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/**
2+
* Copyright (c) 2015-present, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*/
9+
'use strict';
10+
11+
const findProjectWithFilePattern = require('./findProjectWithFilePattern');
12+
13+
/**
14+
* Find a C# dependency project file
15+
*
16+
* @param {String} folder Name of the folder where to seek
17+
* @return {String}
18+
*/
19+
module.exports = function findDependencyProject(folder) {
20+
return findProjectWithFilePattern(folder, /class\s+\S+\s*:\s*IReactPackage/);
21+
};
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/**
2+
* Copyright (c) 2015-present, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*/
9+
'use strict';
10+
11+
const glob = require('glob');
12+
const path = require('path');
13+
14+
/**
15+
* Find the main file for the C# project
16+
*
17+
* @param {String} folder Name of the folder where to seek
18+
* @return {String}
19+
*/
20+
module.exports = function findMainFile(folder) {
21+
let mainFilePath = glob.sync('MainReactNativeHost.cs', {
22+
cwd: folder,
23+
ignore: ['node_modules/**', '**/build/**', 'Examples/**', 'examples/**'],
24+
});
25+
26+
if (mainFilePath.length === 0) {
27+
mainFilePath = glob.sync('MainPage.cs', {
28+
cwd: folder,
29+
ignore: ['node_modules/**', '**/build/**', 'Examples/**', 'examples/**'],
30+
});
31+
}
32+
33+
return mainFilePath && mainFilePath.length > 0 ? path.join(folder, mainFilePath[0]) : null;
34+
};
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/**
2+
* Copyright (c) 2015-present, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*/
9+
'use strict';
10+
11+
const fs = require('fs');
12+
const glob = require('glob');
13+
const path = require('path');
14+
15+
/**
16+
* Gets package's namespace
17+
* by searching for its declaration in all C# files present in the folder
18+
*
19+
* @param {String} folder Folder to find C# files
20+
*/
21+
module.exports = function getNamespace(folder) {
22+
const files = glob.sync('**/*.cs', { cwd: folder });
23+
24+
const packages = files
25+
.map(filePath => fs.readFileSync(path.join(folder, filePath), 'utf8'))
26+
.map(file => file.match(/namespace (.*)[\s\S]+IReactPackage/))
27+
.filter(match => match);
28+
29+
return packages.length ? packages[0][1] : null;
30+
};
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/**
2+
* Copyright (c) 2015-present, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*/
9+
'use strict';
10+
11+
const fs = require('fs');
12+
const glob = require('glob');
13+
const path = require('path');
14+
15+
/**
16+
* Gets package's class name (class that implements IReactPackage)
17+
* by searching for its declaration in all C# files present in the folder
18+
*
19+
* @param {String} folder Folder to find C# files
20+
*/
21+
module.exports = function getPackageClassName(folder) {
22+
const files = glob.sync('**/*.cs', { cwd: folder });
23+
24+
const packages = files
25+
.map(filePath => fs.readFileSync(path.join(folder, filePath), 'utf8'))
26+
.map(file => file.match(/class (.*) : IReactPackage/))
27+
.filter(match => match);
28+
29+
return packages.length ? packages[0][1] : null;
30+
};
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/**
2+
* Copyright (c) 2015-present, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*/
9+
'use strict';
10+
11+
const findProjectWithFilePattern = require('./findProjectWithFilePattern');
12+
13+
/**
14+
* Find a C# dependency project file
15+
*
16+
* @param {String} folder Name of the folder where to seek
17+
* @return {String}
18+
*/
19+
module.exports = function findDependencyProject(folder) {
20+
return findProjectWithFilePattern(folder, /class\s+\S+\s*:\s*(ReactNativeHost|ReactPage)/);
21+
};
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/**
2+
* Copyright (c) 2015-present, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*/
9+
'use strict';
10+
11+
const fs = require('fs');
12+
13+
/**
14+
* Gets GUID of dependency project.
15+
*
16+
* @param {String} folder Path to dependency project .csproj
17+
*/
18+
module.exports = function findProjectGuid(path) {
19+
const file = fs.readFileSync(path, 'utf8');
20+
const result = file.match(/<ProjectGuid>\{(.*)\}<\/ProjectGuid>/);
21+
return result ? result[1] : null;
22+
};
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/**
2+
* Copyright (c) 2015-present, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*/
9+
'use strict';
10+
11+
const fs = require('fs');
12+
13+
/**
14+
* Gets name of dependency project.
15+
*
16+
* @param {String} folder Path to dependency project .csproj
17+
*/
18+
module.exports = function findProjectGuid(path) {
19+
const file = fs.readFileSync(path, 'utf8');
20+
const result = file.match(/<AssemblyName>(.*)<\/AssemblyName>/);
21+
return result ? result[1] : null;
22+
};
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/**
2+
* Copyright (c) 2015-present, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*/
9+
'use strict';
10+
11+
const fs = require('fs');
12+
const glob = require('glob');
13+
const path = require('path');
14+
15+
/**
16+
* Find an C# project file
17+
*
18+
* @param {String} folder Name of the folder where to seek
19+
* @return {String}
20+
*/
21+
module.exports = function findProjectWithFilePattern(folder, pattern) {
22+
const csprojPaths = glob.sync(path.join('**', '*.csproj'), {
23+
cwd: folder,
24+
ignore: ['node_modules/**', '**/build/**', 'Examples/**', 'examples/**', '**/bin/**', '**/obj/**' ],
25+
});
26+
27+
// Search all folders with *.csproj files for one that exports an `IReactPackage`
28+
for (var csprojPath of csprojPaths) {
29+
const csprojFullPath = path.join(folder, csprojPath);
30+
const csprojDir = path.dirname(csprojFullPath);
31+
const files = glob.sync(path.join('**', '*.cs'), {
32+
cwd: csprojDir,
33+
ignore: ['node_modules/**', '**/build/**', 'Examples/**', 'examples/**', '**/bin/**', '**/obj/**' ],
34+
});
35+
36+
const packages = files
37+
.map(filePath => fs.readFileSync(path.join(csprojDir, filePath), 'utf8'))
38+
.map(file => file.match(pattern))
39+
.filter(match => match);
40+
41+
if (packages.length) {
42+
return csprojFullPath;
43+
}
44+
}
45+
46+
return null;
47+
};
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/**
2+
* Copyright (c) 2015-present, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*/
9+
'use strict';
10+
11+
const glob = require('glob');
12+
const path = require('path');
13+
14+
/**
15+
* Glob pattern to look for solution file
16+
*/
17+
const GLOB_PATTERN = '**/*.sln';
18+
19+
/**
20+
* Regexp matching all test projects
21+
*/
22+
const TEST_PROJECTS = /test|example|sample/i;
23+
24+
/**
25+
* Base windows folder
26+
*/
27+
const WINDOWS_BASE = 'windows';
28+
29+
/**
30+
* These folders will be excluded from search to speed it up
31+
*/
32+
const GLOB_EXCLUDE_PATTERN = ['**/@(node_modules)/**'];
33+
34+
/**
35+
* Finds windows project by looking for all .sln files
36+
* in given folder.
37+
*
38+
* Returns first match if files are found or null
39+
*
40+
* Note: `./windows/*.sln` are returned regardless of the name
41+
*/
42+
module.exports = function findSolution(folder) {
43+
const projects = glob
44+
.sync(GLOB_PATTERN, {
45+
cwd: folder,
46+
ignore: GLOB_EXCLUDE_PATTERN,
47+
})
48+
.filter(project => {
49+
return path.dirname(project) === WINDOWS_BASE || !TEST_PROJECTS.test(project);
50+
})
51+
.sort((projectA, projectB) => {
52+
return path.dirname(projectA) === WINDOWS_BASE ? -1 : 1;
53+
});
54+
55+
if (projects.length === 0) {
56+
return null;
57+
}
58+
59+
return projects[0];
60+
};

local-cli/core/windows/index.js

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/**
2+
* Copyright (c) 2015-present, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*/
9+
'use strict';
10+
11+
const findWindowsSolution = require('./findWindowsSolution');
12+
const findNamespace = require('./findNamespace');
13+
const findProject = require('./findProject');
14+
const findDependencyProject = require('./findDependencyProject');
15+
const findProjectName = require('./findProjectName');
16+
const findProjectGUID = require('./findProjectGUID');
17+
const findPackageClassName = require('./findPackageClassName');
18+
const findMainFile = require('./findMainFile');
19+
const path = require('path');
20+
21+
const relativeProjectPath = (fullProjPath) => {
22+
const windowsPath = fullProjPath
23+
.substring(fullProjPath.lastIndexOf("node_modules") - 1, fullProjPath.length)
24+
.replace(/\//g, '\\');
25+
26+
return path.join('..', windowsPath);
27+
};
28+
29+
/**
30+
* Gets windows project config by analyzing given folder and taking some
31+
* defaults specified by user into consideration
32+
*/
33+
exports.projectConfig = function projectConfigWindows(folder, userConfig) {
34+
35+
const csSolution = userConfig.csSolution || findWindowsSolution(folder);
36+
const projectPath = userConfig.projectPath || findProject(folder);
37+
38+
if (!csSolution || !projectPath) {
39+
return null;
40+
}
41+
42+
// expects solutions to be named the same as project folders
43+
const solutionPath = path.join(folder, csSolution);
44+
const sourceDir = userConfig.sourceDir || path.dirname(projectPath);
45+
const mainFilePath = findMainFile(sourceDir);
46+
47+
return {
48+
sourceDir,
49+
solutionPath,
50+
projectPath,
51+
mainFilePath,
52+
folder,
53+
userConfig,
54+
};
55+
};
56+
57+
/**
58+
* Same as projectConfigWindows except it returns
59+
* different config that applies to packages only
60+
*/
61+
exports.dependencyConfig = function dependencyConfigWindows(folder, userConfig) {
62+
63+
const projectPath = userConfig.projectPath || findDependencyProject(folder);
64+
65+
if (!projectPath) {
66+
return null;
67+
}
68+
69+
const sourceDir = userConfig.sourceDir || path.dirname(projectPath);
70+
const packageClassName = findPackageClassName(sourceDir);
71+
const namespace = userConfig.namespace || findNamespace(sourceDir);
72+
73+
/**
74+
* This module has no package to export or no namespace
75+
*/
76+
if (!packageClassName || !namespace) {
77+
return null;
78+
}
79+
80+
const packageUsingPath = userConfig.packageUsingPath ||
81+
`using ${namespace};`;
82+
83+
const packageInstance = userConfig.packageInstance ||
84+
`new ${packageClassName}()`;
85+
86+
const projectGUID = findProjectGUID(projectPath);
87+
const projectName = findProjectName(projectPath);
88+
const relativeProjPath = relativeProjectPath(projectPath);
89+
90+
return {
91+
sourceDir,
92+
packageUsingPath,
93+
packageInstance,
94+
projectName,
95+
projectPath,
96+
folder,
97+
projectGUID,
98+
relativeProjPath,
99+
};
100+
};
101+

0 commit comments

Comments
 (0)