-
Notifications
You must be signed in to change notification settings - Fork 2.7k
/
run.js
105 lines (96 loc) · 3.23 KB
/
run.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
/**
* Copyright (c) 2016-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.
*
* @flow
*/
import type {Reporter} from '../../reporters/index.js';
import type Config from '../../config.js';
import {execCommand} from '../../util/execute-lifecycle-script.js';
import {MessageError} from '../../errors.js';
import {registries} from '../../resolvers/index.js';
import * as fs from '../../util/fs.js';
import map from '../../util/map.js';
const leven = require('leven');
const path = require('path');
const _ = require('lodash');
export async function run(
config: Config,
reporter: Reporter,
flags: Object,
args: Array<string>,
): Promise<void> {
// build up a list of possible scripts
const pkg = await config.readManifest(config.cwd);
const scripts = map();
const binCommands = [];
let binFolders = [];
let pkgCommands = [];
for (const registry of Object.keys(registries)) {
binFolders.push(path.join(config.cwd, config.registries[registry].folder, '.bin'));
}
binFolders = _.uniq(binFolders);
for (const binFolder of binFolders) {
if (await fs.exists(binFolder)) {
for (const name of await fs.readdir(binFolder)) {
binCommands.push(name);
scripts[name] = `"${path.join(binFolder, name)}"`;
}
}
}
if (pkg.scripts) {
// inherit `scripts` from manifest
pkgCommands = Object.keys(pkg.scripts);
Object.assign(scripts, pkg.scripts);
}
async function runCommand(args): Promise<void> {
const action = args.shift();
const actions = [`pre${action}`, action, `post${action}`];
// build up list of commands
const cmds = [];
for (const action of actions) {
const cmd = scripts[action];
if (cmd) {
cmds.push([action, cmd]);
}
}
if (cmds.length) {
for (const [stage, cmd] of cmds) {
// only tack on trailing arguments for default script, ignore for pre and post - #1595
const cmdWithArgs = stage === action ? `${cmd} ${args.join(' ')}` : cmd;
await execCommand(stage, config, cmdWithArgs, config.cwd);
}
} else {
let suggestion;
for (const commandName in scripts) {
const steps = leven(commandName, action);
if (steps < 2) {
suggestion = commandName;
}
}
let msg = `Command ${JSON.stringify(action)} not found.`;
if (suggestion) {
msg += ` Did you mean ${JSON.stringify(suggestion)}?`;
}
throw new MessageError(msg);
}
}
// list possible scripts if none specified
if (args.length === 0) {
reporter.error(reporter.lang('commandNotSpecified'));
reporter.info(`${reporter.lang('binCommands') + binCommands.join(', ')}`);
reporter.info(`${reporter.lang('possibleCommands')}`);
reporter.list('possibleCommands', pkgCommands.sort());
await reporter.question(reporter.lang('commandQuestion')).then(
(answer) => runCommand(answer.split(' ')),
() => reporter.error(reporter.lang('commandNotSpecified')),
);
return Promise.resolve();
} else {
return await runCommand(args);
}
}