Skip to content

Commit 00d83c3

Browse files
test: update snapshots
1 parent 8c4e2cd commit 00d83c3

File tree

3 files changed

+558
-144
lines changed

3 files changed

+558
-144
lines changed

bin/process-arguments.js

Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
'use strict';
2+
3+
const path = require('path');
4+
5+
// Based on https://github.com/webpack/webpack/blob/master/lib/cli.js
6+
// Please do not modify it
7+
8+
const cliAddedItems = new WeakMap();
9+
10+
const getObjectAndProperty = (config, schemaPath, index = 0) => {
11+
if (!schemaPath) return { value: config };
12+
const parts = schemaPath.split('.');
13+
const property = parts.pop();
14+
let current = config;
15+
let i = 0;
16+
for (const part of parts) {
17+
const isArray = part.endsWith('[]');
18+
const name = isArray ? part.slice(0, -2) : part;
19+
let value = current[name];
20+
if (isArray) {
21+
// eslint-disable-next-line no-undefined
22+
if (value === undefined) {
23+
value = {};
24+
current[name] = [...Array.from({ length: index }), value];
25+
cliAddedItems.set(current[name], index + 1);
26+
} else if (!Array.isArray(value)) {
27+
return {
28+
problem: {
29+
type: 'unexpected-non-array-in-path',
30+
path: parts.slice(0, i).join('.'),
31+
},
32+
};
33+
} else {
34+
let addedItems = cliAddedItems.get(value) || 0;
35+
while (addedItems <= index) {
36+
// eslint-disable-next-line no-undefined
37+
value.push(undefined);
38+
// eslint-disable-next-line no-plusplus
39+
addedItems++;
40+
}
41+
cliAddedItems.set(value, addedItems);
42+
const x = value.length - addedItems + index;
43+
// eslint-disable-next-line no-undefined
44+
if (value[x] === undefined) {
45+
value[x] = {};
46+
} else if (value[x] === null || typeof value[x] !== 'object') {
47+
return {
48+
problem: {
49+
type: 'unexpected-non-object-in-path',
50+
path: parts.slice(0, i).join('.'),
51+
},
52+
};
53+
}
54+
value = value[x];
55+
}
56+
// eslint-disable-next-line no-undefined
57+
} else if (value === undefined) {
58+
// eslint-disable-next-line no-multi-assign
59+
value = current[name] = {};
60+
} else if (value === null || typeof value !== 'object') {
61+
return {
62+
problem: {
63+
type: 'unexpected-non-object-in-path',
64+
path: parts.slice(0, i).join('.'),
65+
},
66+
};
67+
}
68+
current = value;
69+
// eslint-disable-next-line no-plusplus
70+
i++;
71+
}
72+
const value = current[property];
73+
if (property.endsWith('[]')) {
74+
const name = property.slice(0, -2);
75+
const value = current[name];
76+
// eslint-disable-next-line no-undefined
77+
if (value === undefined) {
78+
// eslint-disable-next-line no-undefined
79+
current[name] = [...Array.from({ length: index }), undefined];
80+
cliAddedItems.set(current[name], index + 1);
81+
// eslint-disable-next-line no-undefined
82+
return { object: current[name], property: index, value: undefined };
83+
} else if (!Array.isArray(value)) {
84+
// eslint-disable-next-line no-undefined
85+
current[name] = [value, ...Array.from({ length: index }), undefined];
86+
cliAddedItems.set(current[name], index + 1);
87+
// eslint-disable-next-line no-undefined
88+
return { object: current[name], property: index + 1, value: undefined };
89+
}
90+
let addedItems = cliAddedItems.get(value) || 0;
91+
while (addedItems <= index) {
92+
// eslint-disable-next-line no-undefined
93+
value.push(undefined);
94+
// eslint-disable-next-line no-plusplus
95+
addedItems++;
96+
}
97+
cliAddedItems.set(value, addedItems);
98+
const x = value.length - addedItems + index;
99+
// eslint-disable-next-line no-undefined
100+
if (value[x] === undefined) {
101+
value[x] = {};
102+
} else if (value[x] === null || typeof value[x] !== 'object') {
103+
return {
104+
problem: {
105+
type: 'unexpected-non-object-in-path',
106+
path: schemaPath,
107+
},
108+
};
109+
}
110+
return {
111+
object: value,
112+
property: x,
113+
value: value[x],
114+
};
115+
}
116+
return { object: current, property, value };
117+
};
118+
119+
const parseValueForArgumentConfig = (argConfig, value) => {
120+
// eslint-disable-next-line default-case
121+
switch (argConfig.type) {
122+
case 'string':
123+
if (typeof value === 'string') {
124+
return value;
125+
}
126+
break;
127+
case 'path':
128+
if (typeof value === 'string') {
129+
return path.resolve(value);
130+
}
131+
break;
132+
case 'number':
133+
if (typeof value === 'number') return value;
134+
if (typeof value === 'string' && /^[+-]?\d*(\.\d*)[eE]\d+$/) {
135+
const n = +value;
136+
if (!isNaN(n)) return n;
137+
}
138+
break;
139+
case 'boolean':
140+
if (typeof value === 'boolean') return value;
141+
if (value === 'true') return true;
142+
if (value === 'false') return false;
143+
break;
144+
case 'RegExp':
145+
if (value instanceof RegExp) return value;
146+
if (typeof value === 'string') {
147+
// cspell:word yugi
148+
const match = /^\/(.*)\/([yugi]*)$/.exec(value);
149+
if (match && !/[^\\]\//.test(match[1])) {
150+
return new RegExp(match[1], match[2]);
151+
}
152+
}
153+
break;
154+
case 'enum':
155+
if (argConfig.values.includes(value)) return value;
156+
for (const item of argConfig.values) {
157+
if (`${item}` === value) return item;
158+
}
159+
break;
160+
case 'reset':
161+
if (value === true) return [];
162+
break;
163+
}
164+
};
165+
166+
const getExpectedValue = (argConfig) => {
167+
switch (argConfig.type) {
168+
default:
169+
return argConfig.type;
170+
case 'boolean':
171+
return 'true | false';
172+
case 'RegExp':
173+
return 'regular expression (example: /ab?c*/)';
174+
case 'enum':
175+
return argConfig.values.map((v) => `${v}`).join(' | ');
176+
case 'reset':
177+
return 'true (will reset the previous value to an empty array)';
178+
}
179+
};
180+
181+
const setValue = (config, schemaPath, value, index) => {
182+
const { problem, object, property } = getObjectAndProperty(
183+
config,
184+
schemaPath,
185+
index
186+
);
187+
if (problem) return problem;
188+
object[property] = value;
189+
return null;
190+
};
191+
192+
const processArgumentConfig = (argConfig, config, value, index) => {
193+
// eslint-disable-next-line no-undefined
194+
if (index !== undefined && !argConfig.multiple) {
195+
return {
196+
type: 'multiple-values-unexpected',
197+
path: argConfig.path,
198+
};
199+
}
200+
const parsed = parseValueForArgumentConfig(argConfig, value);
201+
// eslint-disable-next-line no-undefined
202+
if (parsed === undefined) {
203+
return {
204+
type: 'invalid-value',
205+
path: argConfig.path,
206+
expected: getExpectedValue(argConfig),
207+
};
208+
}
209+
const problem = setValue(config, argConfig.path, parsed, index);
210+
if (problem) return problem;
211+
return null;
212+
};
213+
214+
const processArguments = (args, config, values) => {
215+
const problems = [];
216+
for (const key of Object.keys(values)) {
217+
const arg = args[key];
218+
if (!arg) {
219+
problems.push({
220+
type: 'unknown-argument',
221+
path: '',
222+
argument: key,
223+
});
224+
// eslint-disable-next-line no-continue
225+
continue;
226+
}
227+
const processValue = (value, i) => {
228+
const currentProblems = [];
229+
for (const argConfig of arg.configs) {
230+
const problem = processArgumentConfig(argConfig, config, value, i);
231+
if (!problem) {
232+
return;
233+
}
234+
currentProblems.push({
235+
...problem,
236+
argument: key,
237+
value,
238+
index: i,
239+
});
240+
}
241+
problems.push(...currentProblems);
242+
};
243+
const value = values[key];
244+
if (Array.isArray(value)) {
245+
for (let i = 0; i < value.length; i++) {
246+
processValue(value[i], i);
247+
}
248+
} else {
249+
// eslint-disable-next-line no-undefined
250+
processValue(value, undefined);
251+
}
252+
}
253+
if (problems.length === 0) return null;
254+
return problems;
255+
};
256+
257+
module.exports = processArguments;

lib/Server.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,12 +75,20 @@ class Server {
7575
}
7676

7777
static getArguments(webpack, ...args) {
78-
// TODO polyfill for webpack v4
78+
// TODO remove after drop webpack v4
79+
if (!webpack.cli) {
80+
return require('../bin/cli-flags');
81+
}
82+
7983
return webpack.cli.getArguments(schema, ...args);
8084
}
8185

8286
static processArguments(webpack, ...args) {
83-
// TODO polyfill for webpack v4
87+
// TODO remove after drop webpack v4
88+
if (!webpack.cli) {
89+
return require('../bin/process-arguments')(...args);
90+
}
91+
8492
return webpack.cli.processArguments(...args);
8593
}
8694

0 commit comments

Comments
 (0)