Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion jest/setupUnitTests.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,20 @@
* @flow
*/

jest.mock('@react-native-community/cli-tools');
jest.mock('@react-native-community/cli-tools', () => {
return {
...jest.requireActual('@react-native-community/cli-tools'),
logger: {
success: jest.fn(),
info: jest.fn(),
warn: jest.fn(),
error: jest.fn(),
debug: jest.fn(),
log: jest.fn(),
setVerbose: jest.fn(),
isVerbose: jest.fn(),
},
};
});

jest.setTimeout(20000);
23 changes: 22 additions & 1 deletion packages/cli/src/commands/config/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,31 @@
* @flow
*/
import {type ConfigT} from 'types';

function isValidRNDependency(config) {
return (
Object.keys(config.platforms).filter(key => Boolean(config.platforms[key]))
.length !== 0 ||
Object.keys(config.hooks).length !== 0 ||
config.assets.length !== 0 ||
config.params.length !== 0
);
}

function filterConfig(config) {
const filtered = {...config};
Object.keys(filtered.dependencies).forEach(item => {
if (!isValidRNDependency(filtered.dependencies[item])) {
delete filtered.dependencies[item];
}
});
return filtered;
}

export default {
name: 'config',
description: 'Print CLI configuration',
func: async (argv: string[], ctx: ConfigT) => {
console.log(JSON.stringify(ctx, null, 2));
console.log(JSON.stringify(filterConfig(ctx), null, 2));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good idea to do it here - we still keep the lazy behaviour in other places

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, that was the intention. Should I leave a comment to make it obvious?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's fine like this :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feel free to approve it then? 🙂

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Be my guest

},
};
28 changes: 12 additions & 16 deletions packages/cli/src/commands/link/__tests__/link-test.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import {func as link} from '../link';
import loadConfig from '../../../tools/config';
import makeHook from '../makeHook';

jest.mock('chalk', () => ({grey: str => str, bold: str => str}));
jest.mock('../../../tools/config');
jest.mock('../../../tools/logger');
jest.mock('../makeHook', () => {
return jest.fn(() => {
return jest.fn(() => Promise.resolve());
});
});

const baseConfig = loadConfig();

Expand Down Expand Up @@ -54,9 +60,9 @@ describe('link', () => {
expect(spy).toHaveBeenCalled();
});

it('should register native module when android/ios projects are present', done => {
const prelink = jest.fn();
const postlink = jest.fn();
it('should register native module when android/ios projects are present', async () => {
const prelink = 'node prelink.js';
const postlink = 'node postlink.js';
const registerNativeModule = jest.fn();

const config = {
Expand Down Expand Up @@ -87,19 +93,9 @@ describe('link', () => {
},
};

link(['react-native-blur'], config, {}).then(() => {
expect(registerNativeModule.mock.calls).toHaveLength(2);

expect(prelink.mock.invocationCallOrder[0]).toBeLessThan(
registerNativeModule.mock.invocationCallOrder[0],
);

expect(postlink.mock.invocationCallOrder[0]).toBeGreaterThan(
registerNativeModule.mock.invocationCallOrder[0],
);

done();
});
await link(['react-native-blur'], config, {});
expect(registerNativeModule.mock.calls).toHaveLength(2);
expect(makeHook.mock.calls).toEqual([[prelink], [postlink]]);
});

it('should copy assets only from the specific dependency that we are linking', done => {
Expand Down
5 changes: 3 additions & 2 deletions packages/cli/src/commands/link/link.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import getPlatformName from './getPlatformName';
import linkDependency from './linkDependency';
import linkAssets from './linkAssets';
import linkAll from './linkAll';
import makeHook from './makeHook';

type FlagsType = {
platforms?: Array<string>,
Expand Down Expand Up @@ -68,11 +69,11 @@ async function link(

try {
if (dependency.hooks.prelink) {
await dependency.hooks.prelink();
await makeHook(dependency.hooks.prelink)();
}
await linkDependency(platforms, project, dependency);
if (dependency.hooks.postlink) {
await dependency.hooks.postlink();
await makeHook(dependency.hooks.postlink)();
}
await linkAssets(platforms, project, dependency.assets);
} catch (error) {
Expand Down
5 changes: 3 additions & 2 deletions packages/cli/src/commands/link/linkAll.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {CLIError, logger} from '@react-native-community/cli-tools';
import type {ConfigT} from 'types';
import linkAssets from './linkAssets';
import linkDependency from './linkDependency';
import makeHook from './makeHook';

const dedupeAssets = (assets: Array<string>): Array<string> =>
uniqBy(assets, asset => path.basename(asset));
Expand All @@ -35,11 +36,11 @@ async function linkAll(config: ConfigT, options: Options) {
const dependency = config.dependencies[key];
try {
if (dependency.hooks.prelink) {
await dependency.hooks.prelink();
await makeHook(dependency.hooks.prelink)();
}
await linkDependency(config.platforms, config.project, dependency);
if (dependency.hooks.postlink) {
await dependency.hooks.postlink();
await makeHook(dependency.hooks.postlink)();
}
} catch (error) {
throw new CLIError(
Expand Down
5 changes: 3 additions & 2 deletions packages/cli/src/commands/link/unlink.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {flatMap, values, difference} from 'lodash';
import {logger, CLIError} from '@react-native-community/cli-tools';
import type {ConfigT} from 'types';
import getPlatformName from './getPlatformName';
import makeHook from './makeHook';

const unlinkDependency = (
platforms,
Expand Down Expand Up @@ -91,7 +92,7 @@ async function unlink(args: Array<string>, ctx: ConfigT) {
const dependencies = values(otherDependencies);
try {
if (dependency.hooks.preulink) {
await dependency.hooks.preulink();
await makeHook(dependency.hooks.preulink)();
}
unlinkDependency(
ctx.platforms,
Expand All @@ -101,7 +102,7 @@ async function unlink(args: Array<string>, ctx: ConfigT) {
dependencies,
);
if (dependency.hooks.postunlink) {
await dependency.hooks.postunlink();
await makeHook(dependency.hooks.postunlink)();
}
} catch (error) {
throw new CLIError(
Expand Down
145 changes: 78 additions & 67 deletions packages/cli/src/tools/config/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,90 @@
* @flow
*/
import path from 'path';
import {mapValues} from 'lodash';
import chalk from 'chalk';

import {logger, inlineString} from '@react-native-community/cli-tools';
import * as ios from '@react-native-community/cli-platform-ios';
import * as android from '@react-native-community/cli-platform-android';
import findDependencies from './findDependencies';
import resolveReactNativePath from './resolveReactNativePath';
import findAssets from './findAssets';
import makeHook from './makeHook';
import {
readConfigFromDisk,
readDependencyConfigFromDisk,
} from './readConfigFromDisk';

import {type ConfigT} from 'types';

import assign from '../assign';
import merge from '../merge';
import resolveNodeModuleDir from './resolveNodeModuleDir';
/**
* Built-in platforms
*/
import * as ios from '@react-native-community/cli-platform-ios';
import * as android from '@react-native-community/cli-platform-android';
import {logger, inlineString} from '@react-native-community/cli-tools';

function getDependencyConfig(
root,
dependencyName,
finalConfig,
config,
userConfig,
isPlatform,
) {
return merge(
{
root,
name: dependencyName,
platforms: Object.keys(finalConfig.platforms).reduce(
(dependency, platform) => {
// Linking platforms is not supported
dependency[platform] = isPlatform
? null
: finalConfig.platforms[platform].dependencyConfig(
root,
config.dependency.platforms[platform] || {},
);
return dependency;
},
{},
),
assets: findAssets(root, config.dependency.assets),
hooks: config.dependency.hooks,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the only change in this moved block is this line – we pass the hooks string directly, without mapping to functions (which are not serializable, hence not displayed after JSON.stringify runs on config)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, right!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess an alternative take would be to provide a special toString implementation as a result of makeHook call to make it serializable?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's better to keep the whole config serializable anyway, less things to remember

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I was suggesting to make makeHook return a serializable function (toString returns a path).

They are going to be gone (most likely) in the future anyway, so not bothering to much with that one.

params: config.dependency.params,
},
userConfig.dependencies[dependencyName] || {},
);
}

/**
* Loads CLI configuration
*/
function loadConfig(projectRoot: string = process.cwd()): ConfigT {
const userConfig = readConfigFromDisk(projectRoot);

const initialConfig: ConfigT = {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this block was moved without modifications

root: projectRoot,
get reactNativePath() {
return userConfig.reactNativePath
? path.resolve(projectRoot, userConfig.reactNativePath)
: resolveReactNativePath(projectRoot);
},
dependencies: {},
commands: userConfig.commands,
get assets() {
return findAssets(projectRoot, userConfig.assets);
},
platforms: userConfig.platforms,
haste: {
providesModuleNodeModules: [],
platforms: Object.keys(userConfig.platforms),
},
get project() {
const project = {};
for (const platform in finalConfig.platforms) {
project[platform] = finalConfig.platforms[platform].projectConfig(
projectRoot,
userConfig.project[platform] || {},
);
}
return project;
},
};

const finalConfig = findDependencies(projectRoot).reduce(
(acc: ConfigT, dependencyName) => {
let root;
Expand All @@ -53,9 +107,8 @@ function loadConfig(projectRoot: string = process.cwd()): ConfigT {
}

/**
* This workaround is necessary for development only before
* first 0.60.0-rc.0 gets released and we can switch to it
* while testing.
* @todo: remove this code once `react-native` is published with
* `platforms` and `commands` inside `react-native.config.js`.
*/
if (dependencyName === 'react-native') {
if (Object.keys(config.platforms).length === 0) {
Expand All @@ -72,39 +125,24 @@ function loadConfig(projectRoot: string = process.cwd()): ConfigT {
* Legacy `rnpm` config required `haste` to be defined. With new config,
* we do it automatically.
*
* Remove this once `rnpm` config is deprecated.
* @todo: Remove this once `rnpm` config is deprecated and all major RN libs are converted.
*/
const haste = config.haste || {
providesModuleNodeModules: isPlatform ? [dependencyName] : [],
platforms: Object.keys(config.platforms),
};

return assign({}, acc, {
return (assign({}, acc, {
dependencies: assign({}, acc.dependencies, {
// $FlowExpectedError: Dynamic getters are not supported
get [dependencyName]() {
return merge(
{
root,
name: dependencyName,
platforms: Object.keys(finalConfig.platforms).reduce(
(dependency, platform) => {
// Linking platforms is not supported
dependency[platform] = isPlatform
? null
: finalConfig.platforms[platform].dependencyConfig(
root,
config.dependency.platforms[platform] || {},
);
return dependency;
},
{},
),
assets: findAssets(root, config.dependency.assets),
hooks: mapValues(config.dependency.hooks, makeHook),
params: config.dependency.params,
},
userConfig.dependencies[dependencyName] || {},
return getDependencyConfig(
root,
dependencyName,
finalConfig,
config,
userConfig,
isPlatform,
);
},
}),
Expand All @@ -120,36 +158,9 @@ function loadConfig(projectRoot: string = process.cwd()): ConfigT {
],
platforms: [...acc.haste.platforms, ...haste.platforms],
},
});
}): ConfigT);
},
({
root: projectRoot,
get reactNativePath() {
return userConfig.reactNativePath
? path.resolve(projectRoot, userConfig.reactNativePath)
: resolveReactNativePath(projectRoot);
},
dependencies: {},
commands: userConfig.commands,
get assets() {
return findAssets(projectRoot, userConfig.assets);
},
platforms: userConfig.platforms,
haste: {
providesModuleNodeModules: [],
platforms: Object.keys(userConfig.platforms),
},
get project() {
const project = {};
for (const platform in finalConfig.platforms) {
project[platform] = finalConfig.platforms[platform].projectConfig(
projectRoot,
userConfig.project[platform] || {},
);
}
return project;
},
}: ConfigT),
initialConfig,
);

return finalConfig;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const path = require('path');

const PODFILES_PATH = path.join(__dirname, '../__fixtures__/');
const LINE_AFTER_TARGET_IN_TEST_PODFILE = 4;
console.log(PODFILES_PATH);

describe('pods::findLineToAddPod', () => {
it('returns null if file is not Podfile', () => {
const podfile = readPodfile(path.join(PODFILES_PATH, 'Info.plist'));
Expand Down
Loading