1 | const chalk = require('chalk');
|
2 | const decamel = require('decamelize');
|
3 | const loadUtils = require('loader-utils');
|
4 | const meant = require('meant');
|
5 | const merge = require('merge-options');
|
6 | const resolve = require('enhanced-resolve');
|
7 | const strip = require('strip-ansi');
|
8 | const table = require('text-table');
|
9 | const weblog = require('webpack-log');
|
10 |
|
11 | module.exports = {
|
12 | bind(value, enforce, options) {
|
13 | if (!value) {
|
14 | return options;
|
15 | }
|
16 |
|
17 | let [extension, loader] = value.split('=');
|
18 |
|
19 |
|
20 |
|
21 | if (extension && !loader) {
|
22 | loader = `${extension}-loader`;
|
23 | }
|
24 |
|
25 |
|
26 | extension = extension.replace(
|
27 |
|
28 | /[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,
|
29 | '\\$&'
|
30 | );
|
31 |
|
32 | const test = new RegExp(`\\.${extension}$`);
|
33 | const rule = { enforce, loader, test };
|
34 |
|
35 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
140 | if (!options.stdout) {
|
141 | throw new Error(out);
|
142 | } else {
|
143 | log.error(out);
|
144 | }
|
145 | }
|
146 |
|
147 | if (unknown.length) {
|
148 |
|
149 | if (errors.length && options.stdout) {
|
150 | console.log('');
|
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 |
|
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 | };
|