Skip to content
Closed
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
6 changes: 5 additions & 1 deletion packages/metro-config/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,13 @@
"license": "MIT",
"dependencies": {
"cosmiconfig": "^5.0.5",
"jest-validate": "^24.5.0",
"metro": "0.53.1",
"metro-cache": "0.53.1",
"metro-core": "0.53.1",
"pretty-format": "24.0.0-alpha.6"
"pretty-format": "^24.5.0"
},
"devDependencies": {
"strip-ansi": "^4.0.0"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ Object {
"cacheStores": Array [],
"cacheVersion": "1.0",
"maxWorkers": 2,
"metro": true,
"projectRoot": "/",
"reporter": null,
"resetCache": false,
Expand Down Expand Up @@ -138,7 +137,6 @@ Object {
"cacheStores": Array [],
"cacheVersion": "1.0",
"maxWorkers": 2,
"metro": true,
"projectRoot": "/",
"reporter": null,
"resetCache": false,
Expand Down Expand Up @@ -265,3 +263,119 @@ Object {
],
}
`;

exports[`loadConfig validates config for projectRoot 1`] = `
"● Validation Error:

Option \\"projectRoot\\" must be of type:
string
but instead received:
array

Example:
{
\\"projectRoot\\": \\"/path/to/project\\"
}
"
`;

exports[`loadConfig validates config for resolver 1`] = `
"● Validation Error:

Option \\"resolver\\" must be of type:
object
but instead received:
string

Example:
{
\\"resolver\\": {
\\"allowPnp\\": true,
\\"assetExts\\": [
\\"bmp\\",
\\"gif\\",
\\"jpg\\",
\\"jpeg\\",
\\"png\\",
\\"psd\\",
\\"svg\\",
\\"webp\\",
\\"m4v\\",
\\"mov\\",
\\"mp4\\",
\\"mpeg\\",
\\"mpg\\",
\\"webm\\",
\\"aac\\",
\\"aiff\\",
\\"caf\\",
\\"m4a\\",
\\"mp3\\",
\\"wav\\",
\\"html\\",
\\"json\\",
\\"pdf\\",
\\"yaml\\",
\\"yml\\",
\\"otf\\",
\\"ttf\\",
\\"zip\\"
],
\\"platforms\\": [
\\"ios\\",
\\"android\\",
\\"windows\\",
\\"web\\"
],
\\"sourceExts\\": [
\\"js\\",
\\"json\\",
\\"ts\\",
\\"tsx\\"
],
\\"providesModuleNodeModules\\": [
\\"react-native\\",
\\"react-native-windows\\"
],
\\"resolverMainFields\\": [
\\"browser\\",
\\"main\\"
],
\\"extraNodeModules\\": {},
\\"hasteImplModulePath\\": \\"./path\\",
\\"blacklistRE\\": {},
\\"useWatchman\\": true
}
}
"
`;

exports[`loadConfig validates config for server 1`] = `
"● Validation Error:

Option \\"server.useGlobalHotkey\\" must be of type:
boolean
but instead received:
string

Example:
{
\\"useGlobalHotkey\\": true
}
"
`;

exports[`loadConfig validates config for transformer 1`] = `
"● Validation Error:

Option \\"transformer.enableBabelRuntime\\" must be of type:
boolean
but instead received:
number

Example:
{
\\"enableBabelRuntime\\": true
}
"
`;
72 changes: 70 additions & 2 deletions packages/metro-config/src/__tests__/loadConfig-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const {loadConfig} = require('../loadConfig');
const getDefaultConfig = require('../defaults');
const cosmiconfig = require('cosmiconfig');
const prettyFormat = require('pretty-format');
const stripAnsi = require('strip-ansi');

describe('loadConfig', () => {
beforeEach(() => {
Expand All @@ -25,7 +26,6 @@ describe('loadConfig', () => {

it('can load config objects', async () => {
const config = {
metro: true,
reporter: null,
maxWorkers: 2,
cacheStores: [],
Expand Down Expand Up @@ -63,7 +63,6 @@ describe('loadConfig', () => {
it('can load the config with a path', async () => {
const config = defaultConfig => ({
...defaultConfig,
metro: true,
reporter: null,
maxWorkers: 2,
cacheStores: [],
Expand Down Expand Up @@ -91,4 +90,73 @@ describe('loadConfig', () => {

expect(prettyFormat(result)).toEqual(prettyFormat(defaultConfig));
});

it('validates config for resolver', async () => {
expect.assertions(1);
const config = defaultConfig => ({
...defaultConfig,
resolver: 'test',
});

cosmiconfig.setResolvedConfig(config);

try {
await loadConfig({});
} catch (error) {
expect(stripAnsi(error.message)).toMatchSnapshot();
}
});

it('validates config for server', async () => {
expect.assertions(1);
const config = defaultConfig => ({
...defaultConfig,
server: {
useGlobalHotkey: 'test',
},
});

cosmiconfig.setResolvedConfig(config);

try {
await loadConfig({});
} catch (error) {
expect(stripAnsi(error.message)).toMatchSnapshot();
}
});

it('validates config for projectRoot', async () => {
expect.assertions(1);
const config = defaultConfig => ({
...defaultConfig,
projectRoot: ['test'],
});

cosmiconfig.setResolvedConfig(config);

try {
await loadConfig({});
} catch (error) {
expect(stripAnsi(error.message)).toMatchSnapshot();
}
});

it('validates config for transformer', async () => {
expect.assertions(1);
const config = defaultConfig => ({
...defaultConfig,
transformer: {
...defaultConfig.transformer,
enableBabelRuntime: 1,
},
});

cosmiconfig.setResolvedConfig(config);

try {
await loadConfig({});
} catch (error) {
expect(stripAnsi(error.message)).toMatchSnapshot();
}
});
});
28 changes: 28 additions & 0 deletions packages/metro-config/src/defaults/validConfig.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
'use strict';

module.exports = async () => {
const defaultConfig = await require('./index')('/path/to/project');
const validConfig = {
...defaultConfig,
resolver: {
...defaultConfig.resolver,
resolveRequest: function CustomResolver() {},
hasteImplModulePath: './path',
},
transformer: {
...defaultConfig.transformer,
getTransformOptions: function getTransformOptions() {},
},
};

return validConfig;
};
11 changes: 9 additions & 2 deletions packages/metro-config/src/loadConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
'use strict';

const cosmiconfig = require('cosmiconfig');
const {validate} = require('jest-validate');
const getDefaultConfig = require('./defaults');
const validConfig = require('./defaults/validConfig');

const {dirname, resolve, join} = require('path');

Expand Down Expand Up @@ -231,8 +233,8 @@ function overrideConfigWithArguments(
* @return {object} Configuration returned
*/
async function loadConfig(
argv: YargArguments = {},
defaultConfigOverrides: InputConfigT = {},
argv?: YargArguments = {},
defaultConfigOverrides?: InputConfigT = {},
): Promise<ConfigT> {
argv.config = overrideArgument(argv.config);

Expand All @@ -242,6 +244,11 @@ async function loadConfig(
defaultConfigOverrides,
);

validate(configuration, {
exampleConfig: await validConfig(),
recursiveBlacklist: ['reporter'],
});

// Override the configuration with cli parameters
const configWithArgs = overrideConfigWithArguments(configuration, argv);

Expand Down
40 changes: 0 additions & 40 deletions packages/metro-core/src/__mocks__/chalk.js

This file was deleted.

Loading