Skip to content

Commit

Permalink
Fix typing of CLI arguments
Browse files Browse the repository at this point in the history
Summary:
Changelog: [Internal]

Enables Flow in `commands/dependencies.js` and removes Flow suppressions where we used to unsafely cast `yargs` option objects to `RunBuildOptions`.

Reviewed By: jacdebug

Differential Revision: D43774990

fbshipit-source-id: 88480bc33ecc96120d9a5240d727081be62245df
  • Loading branch information
motiz88 authored and facebook-github-bot committed Mar 14, 2023
1 parent 78ebd9b commit 5c5830b
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 33 deletions.
2 changes: 1 addition & 1 deletion packages/metro/src/Server.js
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ class Server {
+dev: boolean,
+entryFile: string,
+minify: boolean,
+platform: string,
+platform: ?string,
...
}): Promise<Array<string>> {
const {
Expand Down
8 changes: 2 additions & 6 deletions packages/metro/src/cli-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@

'use strict';

import type {YargArguments} from 'metro-config/src/configTypes.flow';

const fs = require('fs');

exports.watchFile = async function (
Expand All @@ -27,10 +25,8 @@ exports.watchFile = async function (
};

exports.makeAsyncCommand =
(
command: (argv: YargArguments) => Promise<void>,
): ((argv: YargArguments) => void) =>
(argv: YargArguments) => {
<T>(command: (argv: T) => Promise<void>): ((argv: T) => void) =>
(argv: T) => {
Promise.resolve(command(argv)).catch(error => {
console.error(error.stack);
process.exitCode = 1;
Expand Down
30 changes: 26 additions & 4 deletions packages/metro/src/commands/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
'use strict';

import type {RunBuildOptions} from '../index';
import type {YargArguments} from 'metro-config/src/configTypes.flow';
import typeof Yargs from 'yargs';
import type {ModuleObject} from 'yargs';

Expand All @@ -24,6 +23,22 @@ const {Terminal} = require('metro-core');
const term = new Terminal(process.stdout);
const updateReporter = new TerminalReporter(term);

type Args = $ReadOnly<{
config?: string,
dev?: boolean,
entry: string,
legacyBundler?: boolean,
maxWorkers?: number,
minify?: boolean,
out: string,
outputType?: string,
platform?: string,
projectRoots?: $ReadOnlyArray<string>,
resetCache?: boolean,
sourceMap?: boolean,
sourceMapUrl?: string,
}>;

module.exports = (): {
...ModuleObject,
handler: Function,
Expand Down Expand Up @@ -58,10 +73,17 @@ module.exports = (): {
yargs.option('reset-cache', {type: 'boolean'});
},

handler: makeAsyncCommand(async (argv: YargArguments) => {
handler: makeAsyncCommand(async (argv: Args) => {
const config = await loadConfig(argv);
// $FlowExpectedError YargArguments and RunBuildOptions are used interchangeable but their types are not yet compatible
const options = (argv: RunBuildOptions);
const options: RunBuildOptions = {
entry: argv.entry,
dev: argv.dev,
out: argv.out,
minify: argv.minify,
platform: argv.platform,
sourceMap: argv.sourceMap,
sourceMapUrl: argv.sourceMapUrl,
};

// Inline require() to avoid circular dependency with ../index
const MetroApi = require('../index');
Expand Down
32 changes: 22 additions & 10 deletions packages/metro/src/commands/dependencies.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,43 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
* @oncall react_native
*/

'use strict';

import type {ConfigT} from 'metro-config';
import typeof Yargs from 'yargs';
import type {ModuleObject} from 'yargs';

const {makeAsyncCommand} = require('../cli-utils');
const Server = require('../Server');
const denodeify = require('denodeify');
const fs = require('fs');
const {loadConfig} = require('metro-config');
const path = require('path');
const {promisify} = require('util');

async function dependencies(args: any, config: any) {
type Args = $ReadOnly<{
entryFile: string,
output?: string,
platform?: string,
transformer?: string,
maxWorkers?: number,
dev: boolean,
verbose: boolean,
}>;

async function dependencies(args: Args, config: ConfigT) {
const rootModuleAbsolutePath = args.entryFile;
if (!fs.existsSync(rootModuleAbsolutePath)) {
return Promise.reject(
new Error(`File ${rootModuleAbsolutePath} does not exist`),
);
}

// $FlowFixMe[cannot-write]
config.cacheStores = [];

const relativePath = path.relative(
Expand All @@ -43,10 +56,8 @@ async function dependencies(args: any, config: any) {
generateSourceMaps: !args.dev,
};

const writeToFile = args.output;
const outStream = writeToFile
? fs.createWriteStream(args.output)
: process.stdout;
const outStream =
args.output != null ? fs.createWriteStream(args.output) : process.stdout;

const server = new Server(config);
const deps = await server.getOrderedDependencyPaths(options);
Expand All @@ -64,12 +75,13 @@ async function dependencies(args: any, config: any) {
});

server.end();
return writeToFile
? denodeify(outStream.end).bind(outStream)()
return args.output != null
? // $FlowFixMe[method-unbinding]
promisify(outStream.end).bind(outStream)()
: Promise.resolve();
}

module.exports = (): ModuleObject => ({
module.exports = (): {...ModuleObject, handler: Function} => ({
command: 'get-dependencies',
desc: 'List dependencies',
builder: (yargs: Yargs) => {
Expand Down Expand Up @@ -109,7 +121,7 @@ module.exports = (): ModuleObject => ({
description: 'Enables logging',
});
},
handler: makeAsyncCommand(async (argv: any) => {
handler: makeAsyncCommand(async (argv: Args) => {
const config = await loadConfig(argv);
await dependencies(argv, config);
}),
Expand Down
32 changes: 26 additions & 6 deletions packages/metro/src/commands/serve.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,27 @@

'use strict';

import type {RunServerOptions} from '../index';
import type {YargArguments} from 'metro-config/src/configTypes.flow';
import typeof Yargs from 'yargs';
import type {ModuleObject} from 'yargs';

const {makeAsyncCommand, watchFile} = require('../cli-utils');
const {loadConfig, resolveConfig} = require('metro-config');
const {promisify} = require('util');

type Args = $ReadOnly<{
projectRoots?: $ReadOnlyArray<string>,
host: string,
port: number,
maxWorkers?: number,
secure?: boolean,
secureKey?: string,
secureCert?: string,
secureServerOptions?: string,
hmrEnabled?: boolean,
config?: string,
resetCache?: boolean,
}>;

module.exports = (): {
...ModuleObject,
handler: Function,
Expand Down Expand Up @@ -63,7 +75,7 @@ module.exports = (): {
);
},

handler: makeAsyncCommand(async (argv: YargArguments) => {
handler: makeAsyncCommand(async (argv: Args) => {
let server = null;
let restarting = false;

Expand All @@ -86,13 +98,21 @@ module.exports = (): {
// Inline require() to avoid circular dependency with ../index
const MetroApi = require('../index');

// $FlowExpectedError YargArguments and RunBuildOptions are used interchangeable but their types are not yet compatible
server = await MetroApi.runServer(config, (argv: RunServerOptions));
const {
config: _config,
hmrEnabled: _hmrEnabled,
maxWorkers: _maxWorkers,
port: _port,
projectRoots: _projectRoots,
resetCache: _resetCache,
...runServerOptions
} = argv;
server = await MetroApi.runServer(config, runServerOptions);

restarting = false;
}

const foundConfig = await resolveConfig(argv.config, argv.cwd);
const foundConfig = await resolveConfig(argv.config);

if (foundConfig) {
await watchFile(foundConfig.filepath, restart);
Expand Down
13 changes: 7 additions & 6 deletions packages/metro/src/index.flow.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export type RunMetroOptions = {
waitForBundler?: boolean,
};

export type RunServerOptions = {
export type RunServerOptions = $ReadOnly<{
hasReducedPerformance?: boolean,
host?: string,
onError?: (Error & {code?: string}) => void,
Expand All @@ -66,10 +66,10 @@ export type RunServerOptions = {
secureKey?: string, // deprecated
waitForBundler?: boolean,
watch?: boolean,
websocketEndpoints?: {
websocketEndpoints?: $ReadOnly<{
[path: string]: typeof ws.Server,
},
};
}>,
}>;

type BuildGraphOptions = {
entries: $ReadOnlyArray<string>,
Expand Down Expand Up @@ -291,7 +291,8 @@ exports.runServer = async (
onReady(httpServer);
}

Object.assign(websocketEndpoints, {
websocketEndpoints = {
...websocketEndpoints,
...(inspectorProxy
? {...inspectorProxy.createWebSocketListeners(httpServer)}
: {}),
Expand All @@ -302,7 +303,7 @@ exports.runServer = async (
config,
),
}),
});
};

httpServer.on('upgrade', (request, socket, head) => {
const {pathname} = parse(request.url);
Expand Down

0 comments on commit 5c5830b

Please sign in to comment.