UNPKG

4.63 kBJavaScriptView Raw
1const chalk = require('chalk');
2const decamel = require('decamelize');
3const loadUtils = require('loader-utils');
4const meant = require('meant');
5const merge = require('merge-options');
6const resolve = require('enhanced-resolve');
7const strip = require('strip-ansi');
8const table = require('text-table');
9const weblog = require('webpack-log');
10
11module.exports = {
12 bind(value, enforce, options) {
13 if (!value) {
14 return options;
15 }
16
17 let [extension, loader] = value.split('=');
18
19 // this is logic copied from webpack-cli/convert-arg. not entirely sure why
20 // this is done, perhaps for something like `--module-bind js`?
21 if (extension && !loader) {
22 loader = `${extension}-loader`;
23 }
24
25 // eslint-disable-next-line no-useless-escape
26 extension = extension.replace(
27 // eslint-disable-next-line no-useless-escape
28 /[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,
29 '\\$&'
30 );
31
32 const test = new RegExp(`\\.${extension}$`);
33 const rule = { enforce, loader, test };
34
35 // eslint-disable-next-line no-param-reassign
36 const result = merge({ module: { rules: [] } }, options);
37 result.module.rules.push(rule);
38
39 return result;
40 },
41
42 loadPlugin(name) {
43 const log = weblog({ name: 'webpack', id: 'webpack-command' });
44 const queryPos = name && name.indexOf('?');
45 let args;
46 let pluginPath;
47
48 try {
49 if (queryPos > -1) {
50 args = loadUtils.parseQuery(name.substring(queryPos));
51 // eslint-disable-next-line no-param-reassign
52 name = name.substring(0, queryPos);
53 }
54 } catch (e) {
55 log.error(`Invalid plugin arguments ${name} (${e}).`);
56 throw e;
57 }
58
59 try {
60 pluginPath = resolve.sync(process.cwd(), name);
61 // eslint-disable-next-line global-require, import/no-dynamic-require
62 const PluginClass = require(pluginPath);
63 return new PluginClass(args);
64 } catch (e) {
65 log.error(chalk`Cannot load plugin ${name} {dim from ${pluginPath}}`);
66 throw e;
67 }
68 },
69
70 // eslint-disable-next-line consistent-return
71 validate(flag, value) {
72 const { type: types } = flag;
73 let result = false;
74
75 if (!value || !types) {
76 return true;
77 }
78
79 for (const type of [].concat(types)) {
80 if (result !== true) {
81 if (type === 'array') {
82 result = Array.isArray(value);
83 } else {
84 // eslint-disable-next-line valid-typeof
85 result = typeof value === type;
86 }
87 }
88 }
89
90 return result;
91 },
92
93 validateFlags(flags, argv, options = { stdout: true }) {
94 const errors = [];
95 const log = weblog({ name: 'webpack', id: 'webpack-command' });
96 const names = Object.keys(flags);
97 const tableOptions = {
98 align: ['', 'l', 'l'],
99 stringLength(str) {
100 return strip(str).length;
101 },
102 };
103 const uniqueArgs = new Set(Object.keys(argv).map((n) => decamel(n, '-')));
104 const unknown = [];
105 const { validate } = module.exports;
106
107 for (const unique of uniqueArgs) {
108 if (!names.includes(unique)) {
109 const [suggestion] = meant(unique, names);
110 let help = 'Not sure what you mean there';
111
112 if (suggestion) {
113 help = chalk`Did you mean {bold --${suggestion}}?`;
114 }
115
116 unknown.push(['', chalk.blue(`--${unique}`), help]);
117 }
118 }
119
120 for (const name of names) {
121 const flag = flags[name];
122 const value = argv[name];
123
124 // eslint-disable-next-line valid-typeof
125 if (!validate(flag, value)) {
126 errors.push([
127 '',
128 chalk.blue(`--${name}`),
129 chalk`must be set to a {bold ${flag.type}}`,
130 ]);
131 }
132 }
133
134 if (errors.length) {
135 const pre = 'Flags were specified with invalid values:';
136 const post = 'Please check the command executed.';
137 const out = `${pre}\n\n${table(errors, tableOptions)}\n\n${post}`;
138
139 /* istanbul ignore else */
140 if (!options.stdout) {
141 throw new Error(out);
142 } else {
143 log.error(out);
144 }
145 }
146
147 if (unknown.length) {
148 /* istanbul ignore if */
149 if (errors.length && options.stdout) {
150 console.log(''); // eslint-disable-line no-console
151 }
152
153 const pre = `Flags were specified that were not recognized:`;
154 const post = 'Please check the command executed.';
155 const out = `${pre}\n\n${table(unknown, tableOptions)}\n\n${post}`;
156
157 /* istanbul ignore if */
158 if (options.stdout) {
159 log.error(out);
160 } else {
161 throw new Error(out);
162 }
163 }
164
165 if (errors.length || unknown.length) {
166 return false;
167 }
168
169 return true;
170 },
171};