| 
									
										
										
										
											2020-03-09 21:18:34 +08:00
										 |  |  | /* | 
					
						
							|  |  |  | 	MIT License http://www.opensource.org/licenses/mit-license.php
 | 
					
						
							|  |  |  | 	Author Tobias Koppers @sokra | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | "use strict"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  | const path = require("path"); | 
					
						
							| 
									
										
										
										
											2025-07-17 21:16:32 +08:00
										 |  |  | const tty = require("tty"); | 
					
						
							| 
									
										
										
										
											2020-03-26 23:45:49 +08:00
										 |  |  | const webpackSchema = require("../schemas/WebpackOptions.json"); | 
					
						
							| 
									
										
										
										
											2020-03-09 21:18:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-23 07:34:59 +08:00
										 |  |  | /** @typedef {import("json-schema").JSONSchema4} JSONSchema4 */ | 
					
						
							|  |  |  | /** @typedef {import("json-schema").JSONSchema6} JSONSchema6 */ | 
					
						
							|  |  |  | /** @typedef {import("json-schema").JSONSchema7} JSONSchema7 */ | 
					
						
							|  |  |  | /** @typedef {JSONSchema4 | JSONSchema6 | JSONSchema7} JSONSchema */ | 
					
						
							|  |  |  | /** @typedef {JSONSchema & { absolutePath: boolean, instanceof: string, cli: { helper?: boolean, exclude?: boolean, description?: string, negatedDescription?: string, resetDescription?: string } }} Schema */ | 
					
						
							| 
									
										
										
										
											2024-08-09 23:42:37 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  | // TODO add originPath to PathItem for better errors
 | 
					
						
							|  |  |  | /** | 
					
						
							| 
									
										
										
										
											2024-06-11 21:09:50 +08:00
										 |  |  |  * @typedef {object} PathItem | 
					
						
							| 
									
										
										
										
											2025-04-04 21:38:51 +08:00
										 |  |  |  * @property {Schema} schema the part of the schema | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  |  * @property {string} path the path in the config | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-21 21:01:38 +08:00
										 |  |  | /** @typedef {"unknown-argument" | "unexpected-non-array-in-path" | "unexpected-non-object-in-path" | "multiple-values-unexpected" | "invalid-value"} ProblemType */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-04 21:38:51 +08:00
										 |  |  | /** @typedef {string | number | boolean | RegExp} Value */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2024-06-11 21:09:50 +08:00
										 |  |  |  * @typedef {object} Problem | 
					
						
							| 
									
										
										
										
											2020-03-21 21:01:38 +08:00
										 |  |  |  * @property {ProblemType} type | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  |  * @property {string} path | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  |  * @property {string} argument | 
					
						
							| 
									
										
										
										
											2025-04-04 21:38:51 +08:00
										 |  |  |  * @property {Value=} value | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  |  * @property {number=} index | 
					
						
							| 
									
										
										
										
											2020-03-26 23:41:50 +08:00
										 |  |  |  * @property {string=} expected | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							| 
									
										
										
										
											2024-06-11 21:09:50 +08:00
										 |  |  |  * @typedef {object} LocalProblem | 
					
						
							| 
									
										
										
										
											2020-03-21 21:01:38 +08:00
										 |  |  |  * @property {ProblemType} type | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  |  * @property {string} path | 
					
						
							| 
									
										
										
										
											2020-03-26 23:41:50 +08:00
										 |  |  |  * @property {string=} expected | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-04 21:38:51 +08:00
										 |  |  | /** @typedef {{ [key: string]: EnumValue }} EnumValueObject */ | 
					
						
							|  |  |  | /** @typedef {EnumValue[]} EnumValueArray */ | 
					
						
							|  |  |  | /** @typedef {string | number | boolean | EnumValueObject | EnumValueArray | null} EnumValue */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2024-06-11 21:09:50 +08:00
										 |  |  |  * @typedef {object} ArgumentConfig | 
					
						
							| 
									
										
										
										
											2025-04-16 22:04:11 +08:00
										 |  |  |  * @property {string=} description | 
					
						
							|  |  |  |  * @property {string=} negatedDescription | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  |  * @property {string} path | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  |  * @property {boolean} multiple | 
					
						
							| 
									
										
										
										
											2025-04-16 22:04:11 +08:00
										 |  |  |  * @property {"enum" | "string" | "path" | "number" | "boolean" | "RegExp" | "reset"} type | 
					
						
							| 
									
										
										
										
											2025-04-04 21:38:51 +08:00
										 |  |  |  * @property {EnumValue[]=} values | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-09 23:42:37 +08:00
										 |  |  | /** @typedef {"string" | "number" | "boolean"} SimpleType */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2024-06-11 21:09:50 +08:00
										 |  |  |  * @typedef {object} Argument | 
					
						
							| 
									
										
										
										
											2024-08-09 23:42:37 +08:00
										 |  |  |  * @property {string | undefined} description | 
					
						
							|  |  |  |  * @property {SimpleType} simpleType | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  |  * @property {boolean} multiple | 
					
						
							|  |  |  |  * @property {ArgumentConfig[]} configs | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-09 23:42:37 +08:00
										 |  |  | /** @typedef {Record<string, Argument>} Flags */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-09 18:59:21 +08:00
										 |  |  | /** @typedef {Record<string, EXPECTED_ANY>} ObjectConfiguration */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2024-08-09 23:42:37 +08:00
										 |  |  |  * @param {Schema=} schema a json schema to create arguments for (by default webpack schema is used) | 
					
						
							|  |  |  |  * @returns {Flags} object of arguments | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2020-03-26 23:45:49 +08:00
										 |  |  | const getArguments = (schema = webpackSchema) => { | 
					
						
							| 
									
										
										
										
											2024-08-09 23:42:37 +08:00
										 |  |  | 	/** @type {Flags} */ | 
					
						
							| 
									
										
										
										
											2020-03-09 21:18:34 +08:00
										 |  |  | 	const flags = {}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-06 11:08:48 +08:00
										 |  |  | 	/** | 
					
						
							|  |  |  | 	 * @param {string} input input | 
					
						
							|  |  |  | 	 * @returns {string} result | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2025-07-17 00:13:14 +08:00
										 |  |  | 	const pathToArgumentName = (input) => | 
					
						
							| 
									
										
										
										
											2024-07-31 11:31:11 +08:00
										 |  |  | 		input | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  | 			.replace(/\./g, "-") | 
					
						
							| 
									
										
										
										
											2020-03-25 18:36:33 +08:00
										 |  |  | 			.replace(/\[\]/g, "") | 
					
						
							| 
									
										
										
										
											2020-03-09 21:18:34 +08:00
										 |  |  | 			.replace( | 
					
						
							| 
									
										
										
										
											2020-08-16 18:29:28 +08:00
										 |  |  | 				/(\p{Uppercase_Letter}+|\p{Lowercase_Letter}|\d)(\p{Uppercase_Letter}+)/gu, | 
					
						
							| 
									
										
										
										
											2020-03-09 21:18:34 +08:00
										 |  |  | 				"$1-$2" | 
					
						
							|  |  |  | 			) | 
					
						
							| 
									
										
										
										
											2020-03-09 23:24:04 +08:00
										 |  |  | 			.replace(/-?[^\p{Uppercase_Letter}\p{Lowercase_Letter}\d]+/gu, "-") | 
					
						
							| 
									
										
										
										
											2020-03-09 21:18:34 +08:00
										 |  |  | 			.toLowerCase(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-06 11:08:48 +08:00
										 |  |  | 	/** | 
					
						
							|  |  |  | 	 * @param {string} path path | 
					
						
							| 
									
										
										
										
											2024-08-09 23:42:37 +08:00
										 |  |  | 	 * @returns {Schema} schema part | 
					
						
							| 
									
										
										
										
											2024-08-06 11:08:48 +08:00
										 |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2025-07-17 00:13:14 +08:00
										 |  |  | 	const getSchemaPart = (path) => { | 
					
						
							| 
									
										
										
										
											2020-03-09 21:18:34 +08:00
										 |  |  | 		const newPath = path.split("/"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		let schemaPart = schema; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for (let i = 1; i < newPath.length; i++) { | 
					
						
							| 
									
										
										
										
											2025-04-04 21:38:51 +08:00
										 |  |  | 			const inner = schemaPart[/** @type {keyof Schema} */ (newPath[i])]; | 
					
						
							| 
									
										
										
										
											2020-03-09 21:18:34 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			if (!inner) { | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			schemaPart = inner; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return schemaPart; | 
					
						
							| 
									
										
										
										
											2020-03-09 23:24:04 +08:00
										 |  |  | 	}; | 
					
						
							| 
									
										
										
										
											2020-03-09 21:18:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  | 	/** | 
					
						
							|  |  |  | 	 * @param {PathItem[]} path path in the schema | 
					
						
							|  |  |  | 	 * @returns {string | undefined} description | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2025-07-17 00:13:14 +08:00
										 |  |  | 	const getDescription = (path) => { | 
					
						
							| 
									
										
										
										
											2020-03-09 23:46:31 +08:00
										 |  |  | 		for (const { schema } of path) { | 
					
						
							| 
									
										
										
										
											2022-01-14 20:19:48 +08:00
										 |  |  | 			if (schema.cli) { | 
					
						
							|  |  |  | 				if (schema.cli.helper) continue; | 
					
						
							|  |  |  | 				if (schema.cli.description) return schema.cli.description; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2020-03-09 23:46:31 +08:00
										 |  |  | 			if (schema.description) return schema.description; | 
					
						
							| 
									
										
										
										
											2020-03-09 23:24:04 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-03-09 21:18:34 +08:00
										 |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-12 17:21:18 +08:00
										 |  |  | 	/** | 
					
						
							|  |  |  | 	 * @param {PathItem[]} path path in the schema | 
					
						
							|  |  |  | 	 * @returns {string | undefined} negative description | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2025-07-17 00:13:14 +08:00
										 |  |  | 	const getNegatedDescription = (path) => { | 
					
						
							| 
									
										
										
										
											2021-12-12 17:21:18 +08:00
										 |  |  | 		for (const { schema } of path) { | 
					
						
							| 
									
										
										
										
											2022-01-14 20:19:48 +08:00
										 |  |  | 			if (schema.cli) { | 
					
						
							|  |  |  | 				if (schema.cli.helper) continue; | 
					
						
							|  |  |  | 				if (schema.cli.negatedDescription) return schema.cli.negatedDescription; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * @param {PathItem[]} path path in the schema | 
					
						
							|  |  |  | 	 * @returns {string | undefined} reset description | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2025-07-17 00:13:14 +08:00
										 |  |  | 	const getResetDescription = (path) => { | 
					
						
							| 
									
										
										
										
											2022-01-14 20:19:48 +08:00
										 |  |  | 		for (const { schema } of path) { | 
					
						
							|  |  |  | 			if (schema.cli) { | 
					
						
							|  |  |  | 				if (schema.cli.helper) continue; | 
					
						
							|  |  |  | 				if (schema.cli.resetDescription) return schema.cli.resetDescription; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2021-12-12 17:21:18 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  | 	/** | 
					
						
							| 
									
										
										
										
											2024-08-09 23:42:37 +08:00
										 |  |  | 	 * @param {Schema} schemaPart schema | 
					
						
							| 
									
										
										
										
											2025-04-04 21:38:51 +08:00
										 |  |  | 	 * @returns {Pick<ArgumentConfig, "type" | "values"> | undefined} partial argument config | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2025-07-17 00:13:14 +08:00
										 |  |  | 	const schemaToArgumentConfig = (schemaPart) => { | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  | 		if (schemaPart.enum) { | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  | 			return { | 
					
						
							|  |  |  | 				type: "enum", | 
					
						
							|  |  |  | 				values: schemaPart.enum | 
					
						
							|  |  |  | 			}; | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		switch (schemaPart.type) { | 
					
						
							|  |  |  | 			case "number": | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  | 				return { | 
					
						
							|  |  |  | 					type: "number" | 
					
						
							|  |  |  | 				}; | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  | 			case "string": | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  | 				return { | 
					
						
							| 
									
										
										
										
											2020-03-26 06:27:55 +08:00
										 |  |  | 					type: schemaPart.absolutePath ? "path" : "string" | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  | 				}; | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  | 			case "boolean": | 
					
						
							| 
									
										
										
										
											2020-03-25 18:36:33 +08:00
										 |  |  | 				return { | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  | 					type: "boolean" | 
					
						
							| 
									
										
										
										
											2020-03-25 18:36:33 +08:00
										 |  |  | 				}; | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  | 		if (schemaPart.instanceof === "RegExp") { | 
					
						
							|  |  |  | 			return { | 
					
						
							|  |  |  | 				type: "RegExp" | 
					
						
							|  |  |  | 			}; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return undefined; | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * @param {PathItem[]} path path in the schema | 
					
						
							|  |  |  | 	 * @returns {void} | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2025-07-17 00:13:14 +08:00
										 |  |  | 	const addResetFlag = (path) => { | 
					
						
							| 
									
										
										
										
											2020-03-26 18:37:42 +08:00
										 |  |  | 		const schemaPath = path[0].path; | 
					
						
							|  |  |  | 		const name = pathToArgumentName(`${schemaPath}.reset`); | 
					
						
							| 
									
										
										
										
											2022-01-14 20:19:48 +08:00
										 |  |  | 		const description = | 
					
						
							|  |  |  | 			getResetDescription(path) || | 
					
						
							|  |  |  | 			`Clear all items provided in '${schemaPath}' configuration. ${getDescription( | 
					
						
							|  |  |  | 				path | 
					
						
							|  |  |  | 			)}`;
 | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  | 		flags[name] = { | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  | 			configs: [ | 
					
						
							|  |  |  | 				{ | 
					
						
							| 
									
										
										
										
											2020-03-26 18:37:42 +08:00
										 |  |  | 					type: "reset", | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  | 					multiple: false, | 
					
						
							| 
									
										
										
										
											2022-01-14 20:19:48 +08:00
										 |  |  | 					description, | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  | 					path: schemaPath | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  | 			], | 
					
						
							|  |  |  | 			description: undefined, | 
					
						
							| 
									
										
										
										
											2024-08-09 23:42:37 +08:00
										 |  |  | 			simpleType: | 
					
						
							|  |  |  | 				/** @type {SimpleType} */ | 
					
						
							|  |  |  | 				(/** @type {unknown} */ (undefined)), | 
					
						
							|  |  |  | 			multiple: /** @type {boolean} */ (/** @type {unknown} */ (undefined)) | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  | 		}; | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * @param {PathItem[]} path full path in schema | 
					
						
							|  |  |  | 	 * @param {boolean} multiple inside of an array | 
					
						
							|  |  |  | 	 * @returns {number} number of arguments added | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2020-03-09 23:46:31 +08:00
										 |  |  | 	const addFlag = (path, multiple) => { | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  | 		const argConfigBase = schemaToArgumentConfig(path[0].schema); | 
					
						
							|  |  |  | 		if (!argConfigBase) return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-12 17:21:18 +08:00
										 |  |  | 		const negatedDescription = getNegatedDescription(path); | 
					
						
							| 
									
										
										
										
											2020-03-09 23:46:31 +08:00
										 |  |  | 		const name = pathToArgumentName(path[0].path); | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  | 		/** @type {ArgumentConfig} */ | 
					
						
							|  |  |  | 		const argConfig = { | 
					
						
							|  |  |  | 			...argConfigBase, | 
					
						
							|  |  |  | 			multiple, | 
					
						
							|  |  |  | 			description: getDescription(path), | 
					
						
							|  |  |  | 			path: path[0].path | 
					
						
							|  |  |  | 		}; | 
					
						
							| 
									
										
										
										
											2020-03-09 21:18:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-12 17:21:18 +08:00
										 |  |  | 		if (negatedDescription) { | 
					
						
							|  |  |  | 			argConfig.negatedDescription = negatedDescription; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-09 21:18:34 +08:00
										 |  |  | 		if (!flags[name]) { | 
					
						
							|  |  |  | 			flags[name] = { | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  | 				configs: [], | 
					
						
							|  |  |  | 				description: undefined, | 
					
						
							| 
									
										
										
										
											2024-08-09 23:42:37 +08:00
										 |  |  | 				simpleType: | 
					
						
							|  |  |  | 					/** @type {SimpleType} */ | 
					
						
							|  |  |  | 					(/** @type {unknown} */ (undefined)), | 
					
						
							|  |  |  | 				multiple: /** @type {boolean} */ (/** @type {unknown} */ (undefined)) | 
					
						
							| 
									
										
										
										
											2020-03-09 21:18:34 +08:00
										 |  |  | 			}; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  | 		if ( | 
					
						
							|  |  |  | 			flags[name].configs.some( | 
					
						
							| 
									
										
										
										
											2025-07-17 00:13:14 +08:00
										 |  |  | 				(item) => JSON.stringify(item) === JSON.stringify(argConfig) | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  | 			) | 
					
						
							|  |  |  | 		) { | 
					
						
							|  |  |  | 			return 0; | 
					
						
							| 
									
										
										
										
											2020-03-09 21:18:34 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-26 16:48:21 +08:00
										 |  |  | 		if ( | 
					
						
							|  |  |  | 			flags[name].configs.some( | 
					
						
							| 
									
										
										
										
											2025-07-17 00:13:14 +08:00
										 |  |  | 				(item) => item.type === argConfig.type && item.multiple !== multiple | 
					
						
							| 
									
										
										
										
											2020-03-26 16:48:21 +08:00
										 |  |  | 			) | 
					
						
							|  |  |  | 		) { | 
					
						
							|  |  |  | 			if (multiple) { | 
					
						
							|  |  |  | 				throw new Error( | 
					
						
							|  |  |  | 					`Conflicting schema for ${path[0].path} with ${argConfig.type} type (array type must be before single item type)` | 
					
						
							|  |  |  | 				); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return 0; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  | 		flags[name].configs.push(argConfig); | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		return 1; | 
					
						
							| 
									
										
										
										
											2020-03-09 23:24:04 +08:00
										 |  |  | 	}; | 
					
						
							| 
									
										
										
										
											2020-03-09 21:18:34 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// TODO support `not` and `if/then/else`
 | 
					
						
							|  |  |  | 	// TODO support `const`, but we don't use it on our schema
 | 
					
						
							| 
									
										
										
										
											2020-03-09 23:24:04 +08:00
										 |  |  | 	/** | 
					
						
							| 
									
										
										
										
											2024-08-09 23:42:37 +08:00
										 |  |  | 	 * @param {Schema} schemaPart the current schema | 
					
						
							| 
									
										
										
										
											2020-03-09 23:24:04 +08:00
										 |  |  | 	 * @param {string} schemaPath the current path in the schema | 
					
						
							| 
									
										
										
										
											2025-04-04 21:38:51 +08:00
										 |  |  | 	 * @param {PathItem[]} path all previous visited schemaParts | 
					
						
							| 
									
										
										
										
											2020-03-09 23:24:04 +08:00
										 |  |  | 	 * @param {string | null} inArray if inside of an array, the path to the array | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  | 	 * @returns {number} added arguments | 
					
						
							| 
									
										
										
										
											2020-03-09 23:24:04 +08:00
										 |  |  | 	 */ | 
					
						
							|  |  |  | 	const traverse = (schemaPart, schemaPath = "", path = [], inArray = null) => { | 
					
						
							| 
									
										
										
										
											2020-03-09 21:18:34 +08:00
										 |  |  | 		while (schemaPart.$ref) { | 
					
						
							|  |  |  | 			schemaPart = getSchemaPart(schemaPart.$ref); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-26 06:27:55 +08:00
										 |  |  | 		const repetitions = path.filter(({ schema }) => schema === schemaPart); | 
					
						
							| 
									
										
										
										
											2020-03-09 23:46:31 +08:00
										 |  |  | 		if ( | 
					
						
							| 
									
										
										
										
											2020-03-26 06:27:55 +08:00
										 |  |  | 			repetitions.length >= 2 || | 
					
						
							|  |  |  | 			repetitions.some(({ path }) => path === schemaPath) | 
					
						
							| 
									
										
										
										
											2020-03-09 23:46:31 +08:00
										 |  |  | 		) { | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  | 			return 0; | 
					
						
							| 
									
										
										
										
											2020-03-09 23:46:31 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  | 		if (schemaPart.cli && schemaPart.cli.exclude) return 0; | 
					
						
							| 
									
										
										
										
											2020-03-09 21:18:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-04 21:38:51 +08:00
										 |  |  | 		/** @type {PathItem[]} */ | 
					
						
							| 
									
										
										
										
											2020-03-09 23:46:31 +08:00
										 |  |  | 		const fullPath = [{ schema: schemaPart, path: schemaPath }, ...path]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  | 		let addedArguments = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-31 11:11:11 +08:00
										 |  |  | 		addedArguments += addFlag(fullPath, Boolean(inArray)); | 
					
						
							| 
									
										
										
										
											2020-03-09 21:18:34 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (schemaPart.type === "object") { | 
					
						
							|  |  |  | 			if (schemaPart.properties) { | 
					
						
							| 
									
										
										
										
											2020-03-09 23:24:04 +08:00
										 |  |  | 				for (const property of Object.keys(schemaPart.properties)) { | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  | 					addedArguments += traverse( | 
					
						
							| 
									
										
										
										
											2024-08-09 23:42:37 +08:00
										 |  |  | 						/** @type {Schema} */ | 
					
						
							|  |  |  | 						(schemaPart.properties[property]), | 
					
						
							| 
									
										
										
										
											2020-03-09 21:18:34 +08:00
										 |  |  | 						schemaPath ? `${schemaPath}.${property}` : property, | 
					
						
							| 
									
										
										
										
											2020-03-09 23:46:31 +08:00
										 |  |  | 						fullPath, | 
					
						
							| 
									
										
										
										
											2020-03-09 23:24:04 +08:00
										 |  |  | 						inArray | 
					
						
							|  |  |  | 					); | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2020-03-09 21:18:34 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  | 			return addedArguments; | 
					
						
							| 
									
										
										
										
											2020-03-09 21:18:34 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (schemaPart.type === "array") { | 
					
						
							| 
									
										
										
										
											2020-03-09 23:24:04 +08:00
										 |  |  | 			if (inArray) { | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  | 				return 0; | 
					
						
							| 
									
										
										
										
											2020-03-09 23:24:04 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2020-03-09 21:18:34 +08:00
										 |  |  | 			if (Array.isArray(schemaPart.items)) { | 
					
						
							| 
									
										
										
										
											2024-07-31 04:09:42 +08:00
										 |  |  | 				const i = 0; | 
					
						
							| 
									
										
										
										
											2020-03-09 23:24:04 +08:00
										 |  |  | 				for (const item of schemaPart.items) { | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  | 					addedArguments += traverse( | 
					
						
							| 
									
										
										
										
											2024-08-09 23:42:37 +08:00
										 |  |  | 						/** @type {Schema} */ | 
					
						
							|  |  |  | 						(item), | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  | 						`${schemaPath}.${i}`, | 
					
						
							|  |  |  | 						fullPath, | 
					
						
							|  |  |  | 						schemaPath | 
					
						
							|  |  |  | 					); | 
					
						
							| 
									
										
										
										
											2020-03-09 23:24:04 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2020-03-09 21:18:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  | 				return addedArguments; | 
					
						
							| 
									
										
										
										
											2020-03-09 21:18:34 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  | 			addedArguments += traverse( | 
					
						
							| 
									
										
										
										
											2024-08-09 23:42:37 +08:00
										 |  |  | 				/** @type {Schema} */ | 
					
						
							|  |  |  | 				(schemaPart.items), | 
					
						
							| 
									
										
										
										
											2020-03-25 18:36:33 +08:00
										 |  |  | 				`${schemaPath}[]`, | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  | 				fullPath, | 
					
						
							|  |  |  | 				schemaPath | 
					
						
							|  |  |  | 			); | 
					
						
							| 
									
										
										
										
											2020-03-09 21:18:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-26 06:48:51 +08:00
										 |  |  | 			if (addedArguments > 0) { | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  | 				addResetFlag(fullPath); | 
					
						
							|  |  |  | 				addedArguments++; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			return addedArguments; | 
					
						
							| 
									
										
										
										
											2020-03-09 21:18:34 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		const maybeOf = schemaPart.oneOf || schemaPart.anyOf || schemaPart.allOf; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (maybeOf) { | 
					
						
							|  |  |  | 			const items = maybeOf; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-09 23:24:04 +08:00
										 |  |  | 			for (let i = 0; i < items.length; i++) { | 
					
						
							| 
									
										
										
										
											2024-08-09 23:42:37 +08:00
										 |  |  | 				addedArguments += traverse( | 
					
						
							|  |  |  | 					/** @type {Schema} */ | 
					
						
							|  |  |  | 					(items[i]), | 
					
						
							|  |  |  | 					schemaPath, | 
					
						
							|  |  |  | 					fullPath, | 
					
						
							|  |  |  | 					inArray | 
					
						
							|  |  |  | 				); | 
					
						
							| 
									
										
										
										
											2020-03-09 23:24:04 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2020-03-09 21:18:34 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  | 			return addedArguments; | 
					
						
							| 
									
										
										
										
											2020-03-09 21:18:34 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		return addedArguments; | 
					
						
							| 
									
										
										
										
											2020-03-09 23:24:04 +08:00
										 |  |  | 	}; | 
					
						
							| 
									
										
										
										
											2020-03-09 21:18:34 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	traverse(schema); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  | 	// Summarize flags
 | 
					
						
							|  |  |  | 	for (const name of Object.keys(flags)) { | 
					
						
							| 
									
										
										
										
											2024-08-09 23:42:37 +08:00
										 |  |  | 		/** @type {Argument} */ | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  | 		const argument = flags[name]; | 
					
						
							| 
									
										
										
										
											2024-08-09 23:42:37 +08:00
										 |  |  | 		argument.description = argument.configs.reduce((desc, { description }) => { | 
					
						
							|  |  |  | 			if (!desc) return description; | 
					
						
							|  |  |  | 			if (!description) return desc; | 
					
						
							|  |  |  | 			if (desc.includes(description)) return desc; | 
					
						
							|  |  |  | 			return `${desc} ${description}`; | 
					
						
							|  |  |  | 		}, /** @type {string | undefined} */ (undefined)); | 
					
						
							| 
									
										
										
										
											2024-08-06 11:08:48 +08:00
										 |  |  | 		argument.simpleType = | 
					
						
							| 
									
										
										
										
											2024-08-09 23:42:37 +08:00
										 |  |  | 			/** @type {SimpleType} */ | 
					
						
							| 
									
										
										
										
											2024-08-06 11:08:48 +08:00
										 |  |  | 			( | 
					
						
							|  |  |  | 				argument.configs.reduce((t, argConfig) => { | 
					
						
							| 
									
										
										
										
											2024-08-09 23:42:37 +08:00
										 |  |  | 					/** @type {SimpleType} */ | 
					
						
							| 
									
										
										
										
											2024-08-06 11:08:48 +08:00
										 |  |  | 					let type = "string"; | 
					
						
							|  |  |  | 					switch (argConfig.type) { | 
					
						
							|  |  |  | 						case "number": | 
					
						
							|  |  |  | 							type = "number"; | 
					
						
							|  |  |  | 							break; | 
					
						
							|  |  |  | 						case "reset": | 
					
						
							|  |  |  | 						case "boolean": | 
					
						
							|  |  |  | 							type = "boolean"; | 
					
						
							|  |  |  | 							break; | 
					
						
							|  |  |  | 						case "enum": { | 
					
						
							|  |  |  | 							const values = | 
					
						
							|  |  |  | 								/** @type {NonNullable<ArgumentConfig["values"]>} */ | 
					
						
							|  |  |  | 								(argConfig.values); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-17 00:13:14 +08:00
										 |  |  | 							if (values.every((v) => typeof v === "boolean")) type = "boolean"; | 
					
						
							|  |  |  | 							if (values.every((v) => typeof v === "number")) type = "number"; | 
					
						
							| 
									
										
										
										
											2024-08-06 11:08:48 +08:00
										 |  |  | 							break; | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					if (t === undefined) return type; | 
					
						
							|  |  |  | 					return t === type ? t : "string"; | 
					
						
							| 
									
										
										
										
											2024-08-09 23:42:37 +08:00
										 |  |  | 				}, /** @type {SimpleType | undefined} */ (undefined)) | 
					
						
							| 
									
										
										
										
											2024-08-06 11:08:48 +08:00
										 |  |  | 			); | 
					
						
							| 
									
										
										
										
											2025-07-17 00:13:14 +08:00
										 |  |  | 		argument.multiple = argument.configs.some((c) => c.multiple); | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-09 21:18:34 +08:00
										 |  |  | 	return flags; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  | const cliAddedItems = new WeakMap(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-06 11:08:48 +08:00
										 |  |  | /** @typedef {string | number} Property */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2025-07-09 18:59:21 +08:00
										 |  |  |  * @param {ObjectConfiguration} config configuration | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  |  * @param {string} schemaPath path in the config | 
					
						
							|  |  |  |  * @param {number | undefined} index index of value when multiple values are provided, otherwise undefined | 
					
						
							| 
									
										
										
										
											2025-07-09 18:59:21 +08:00
										 |  |  |  * @returns {{ problem?: LocalProblem, object?: ObjectConfiguration, property?: Property, value?: EXPECTED_OBJECT | EXPECTED_ANY[] }} problem or object with property and value | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  |  */ | 
					
						
							|  |  |  | const getObjectAndProperty = (config, schemaPath, index = 0) => { | 
					
						
							|  |  |  | 	if (!schemaPath) return { value: config }; | 
					
						
							|  |  |  | 	const parts = schemaPath.split("."); | 
					
						
							| 
									
										
										
										
											2024-08-06 11:08:48 +08:00
										 |  |  | 	const property = /** @type {string} */ (parts.pop()); | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  | 	let current = config; | 
					
						
							|  |  |  | 	let i = 0; | 
					
						
							|  |  |  | 	for (const part of parts) { | 
					
						
							|  |  |  | 		const isArray = part.endsWith("[]"); | 
					
						
							|  |  |  | 		const name = isArray ? part.slice(0, -2) : part; | 
					
						
							|  |  |  | 		let value = current[name]; | 
					
						
							|  |  |  | 		if (isArray) { | 
					
						
							|  |  |  | 			if (value === undefined) { | 
					
						
							|  |  |  | 				value = {}; | 
					
						
							|  |  |  | 				current[name] = [...Array.from({ length: index }), value]; | 
					
						
							|  |  |  | 				cliAddedItems.set(current[name], index + 1); | 
					
						
							|  |  |  | 			} else if (!Array.isArray(value)) { | 
					
						
							|  |  |  | 				return { | 
					
						
							|  |  |  | 					problem: { | 
					
						
							|  |  |  | 						type: "unexpected-non-array-in-path", | 
					
						
							|  |  |  | 						path: parts.slice(0, i).join(".") | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				}; | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				let addedItems = cliAddedItems.get(value) || 0; | 
					
						
							|  |  |  | 				while (addedItems <= index) { | 
					
						
							|  |  |  | 					value.push(undefined); | 
					
						
							|  |  |  | 					addedItems++; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				cliAddedItems.set(value, addedItems); | 
					
						
							|  |  |  | 				const x = value.length - addedItems + index; | 
					
						
							|  |  |  | 				if (value[x] === undefined) { | 
					
						
							|  |  |  | 					value[x] = {}; | 
					
						
							|  |  |  | 				} else if (value[x] === null || typeof value[x] !== "object") { | 
					
						
							|  |  |  | 					return { | 
					
						
							|  |  |  | 						problem: { | 
					
						
							|  |  |  | 							type: "unexpected-non-object-in-path", | 
					
						
							|  |  |  | 							path: parts.slice(0, i).join(".") | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					}; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				value = value[x]; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2024-07-31 04:54:55 +08:00
										 |  |  | 		} else if (value === undefined) { | 
					
						
							|  |  |  | 			value = current[name] = {}; | 
					
						
							|  |  |  | 		} else if (value === null || typeof value !== "object") { | 
					
						
							|  |  |  | 			return { | 
					
						
							|  |  |  | 				problem: { | 
					
						
							|  |  |  | 					type: "unexpected-non-object-in-path", | 
					
						
							|  |  |  | 					path: parts.slice(0, i).join(".") | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}; | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		current = value; | 
					
						
							|  |  |  | 		i++; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-07-31 04:09:42 +08:00
										 |  |  | 	const value = current[property]; | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  | 	if (property.endsWith("[]")) { | 
					
						
							|  |  |  | 		const name = property.slice(0, -2); | 
					
						
							|  |  |  | 		const value = current[name]; | 
					
						
							|  |  |  | 		if (value === undefined) { | 
					
						
							|  |  |  | 			current[name] = [...Array.from({ length: index }), undefined]; | 
					
						
							|  |  |  | 			cliAddedItems.set(current[name], index + 1); | 
					
						
							|  |  |  | 			return { object: current[name], property: index, value: undefined }; | 
					
						
							|  |  |  | 		} else if (!Array.isArray(value)) { | 
					
						
							|  |  |  | 			current[name] = [value, ...Array.from({ length: index }), undefined]; | 
					
						
							|  |  |  | 			cliAddedItems.set(current[name], index + 1); | 
					
						
							|  |  |  | 			return { object: current[name], property: index + 1, value: undefined }; | 
					
						
							| 
									
										
										
										
											2024-07-31 04:21:27 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		let addedItems = cliAddedItems.get(value) || 0; | 
					
						
							|  |  |  | 		while (addedItems <= index) { | 
					
						
							|  |  |  | 			value.push(undefined); | 
					
						
							|  |  |  | 			addedItems++; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		cliAddedItems.set(value, addedItems); | 
					
						
							|  |  |  | 		const x = value.length - addedItems + index; | 
					
						
							|  |  |  | 		if (value[x] === undefined) { | 
					
						
							|  |  |  | 			value[x] = {}; | 
					
						
							|  |  |  | 		} else if (value[x] === null || typeof value[x] !== "object") { | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  | 			return { | 
					
						
							| 
									
										
										
										
											2024-07-31 04:21:27 +08:00
										 |  |  | 				problem: { | 
					
						
							|  |  |  | 					type: "unexpected-non-object-in-path", | 
					
						
							|  |  |  | 					path: schemaPath | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  | 			}; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-07-31 04:21:27 +08:00
										 |  |  | 		return { | 
					
						
							|  |  |  | 			object: value, | 
					
						
							|  |  |  | 			property: x, | 
					
						
							|  |  |  | 			value: value[x] | 
					
						
							|  |  |  | 		}; | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return { object: current, property, value }; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							| 
									
										
										
										
											2025-07-09 18:59:21 +08:00
										 |  |  |  * @param {ObjectConfiguration} config configuration | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  |  * @param {string} schemaPath path in the config | 
					
						
							| 
									
										
										
										
											2025-04-04 21:38:51 +08:00
										 |  |  |  * @param {ParsedValue} value parsed value | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  |  * @param {number | undefined} index index of value when multiple values are provided, otherwise undefined | 
					
						
							|  |  |  |  * @returns {LocalProblem | null} problem or null for success | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | const setValue = (config, schemaPath, value, index) => { | 
					
						
							|  |  |  | 	const { problem, object, property } = getObjectAndProperty( | 
					
						
							|  |  |  | 		config, | 
					
						
							|  |  |  | 		schemaPath, | 
					
						
							|  |  |  | 		index | 
					
						
							|  |  |  | 	); | 
					
						
							|  |  |  | 	if (problem) return problem; | 
					
						
							| 
									
										
										
										
											2025-07-09 18:59:21 +08:00
										 |  |  | 	/** @type {ObjectConfiguration} */ | 
					
						
							|  |  |  | 	(object)[/** @type {Property} */ (property)] = value; | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  | 	return null; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @param {ArgumentConfig} argConfig processing instructions | 
					
						
							| 
									
										
										
										
											2025-07-09 18:59:21 +08:00
										 |  |  |  * @param {ObjectConfiguration} config configuration | 
					
						
							| 
									
										
										
										
											2024-08-09 23:42:37 +08:00
										 |  |  |  * @param {Value} value the value | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  |  * @param {number | undefined} index the index if multiple values provided | 
					
						
							|  |  |  |  * @returns {LocalProblem | null} a problem if any | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | const processArgumentConfig = (argConfig, config, value, index) => { | 
					
						
							|  |  |  | 	if (index !== undefined && !argConfig.multiple) { | 
					
						
							|  |  |  | 		return { | 
					
						
							|  |  |  | 			type: "multiple-values-unexpected", | 
					
						
							|  |  |  | 			path: argConfig.path | 
					
						
							|  |  |  | 		}; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	const parsed = parseValueForArgumentConfig(argConfig, value); | 
					
						
							|  |  |  | 	if (parsed === undefined) { | 
					
						
							|  |  |  | 		return { | 
					
						
							|  |  |  | 			type: "invalid-value", | 
					
						
							| 
									
										
										
										
											2020-03-26 23:41:50 +08:00
										 |  |  | 			path: argConfig.path, | 
					
						
							|  |  |  | 			expected: getExpectedValue(argConfig) | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  | 		}; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	const problem = setValue(config, argConfig.path, parsed, index); | 
					
						
							|  |  |  | 	if (problem) return problem; | 
					
						
							|  |  |  | 	return null; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-26 23:41:50 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @param {ArgumentConfig} argConfig processing instructions | 
					
						
							|  |  |  |  * @returns {string | undefined} expected message | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2025-07-17 00:13:14 +08:00
										 |  |  | const getExpectedValue = (argConfig) => { | 
					
						
							| 
									
										
										
										
											2020-03-26 23:41:50 +08:00
										 |  |  | 	switch (argConfig.type) { | 
					
						
							|  |  |  | 		case "boolean": | 
					
						
							|  |  |  | 			return "true | false"; | 
					
						
							|  |  |  | 		case "RegExp": | 
					
						
							|  |  |  | 			return "regular expression (example: /ab?c*/)"; | 
					
						
							|  |  |  | 		case "enum": | 
					
						
							| 
									
										
										
										
											2024-08-06 11:08:48 +08:00
										 |  |  | 			return /** @type {NonNullable<ArgumentConfig["values"]>} */ ( | 
					
						
							|  |  |  | 				argConfig.values | 
					
						
							|  |  |  | 			) | 
					
						
							| 
									
										
										
										
											2025-07-17 00:13:14 +08:00
										 |  |  | 				.map((v) => `${v}`) | 
					
						
							| 
									
										
										
										
											2024-08-06 11:08:48 +08:00
										 |  |  | 				.join(" | "); | 
					
						
							| 
									
										
										
										
											2020-03-26 23:41:50 +08:00
										 |  |  | 		case "reset": | 
					
						
							|  |  |  | 			return "true (will reset the previous value to an empty array)"; | 
					
						
							| 
									
										
										
										
											2024-07-31 09:37:24 +08:00
										 |  |  | 		default: | 
					
						
							|  |  |  | 			return argConfig.type; | 
					
						
							| 
									
										
										
										
											2020-03-26 23:41:50 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-04 21:38:51 +08:00
										 |  |  | /** @typedef {null | string | number | boolean | RegExp | EnumValue | []} ParsedValue */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @param {ArgumentConfig} argConfig processing instructions | 
					
						
							| 
									
										
										
										
											2024-08-09 23:42:37 +08:00
										 |  |  |  * @param {Value} value the value | 
					
						
							| 
									
										
										
										
											2025-04-04 21:38:51 +08:00
										 |  |  |  * @returns {ParsedValue | undefined} parsed value | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  |  */ | 
					
						
							|  |  |  | const parseValueForArgumentConfig = (argConfig, value) => { | 
					
						
							|  |  |  | 	switch (argConfig.type) { | 
					
						
							|  |  |  | 		case "string": | 
					
						
							|  |  |  | 			if (typeof value === "string") { | 
					
						
							|  |  |  | 				return value; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case "path": | 
					
						
							|  |  |  | 			if (typeof value === "string") { | 
					
						
							|  |  |  | 				return path.resolve(value); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case "number": | 
					
						
							|  |  |  | 			if (typeof value === "number") return value; | 
					
						
							|  |  |  | 			if (typeof value === "string" && /^[+-]?\d*(\.\d*)[eE]\d+$/) { | 
					
						
							| 
									
										
										
										
											2024-07-31 11:11:11 +08:00
										 |  |  | 				const n = Number(value); | 
					
						
							| 
									
										
										
										
											2024-08-02 02:36:27 +08:00
										 |  |  | 				if (!Number.isNaN(n)) return n; | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case "boolean": | 
					
						
							|  |  |  | 			if (typeof value === "boolean") return value; | 
					
						
							|  |  |  | 			if (value === "true") return true; | 
					
						
							|  |  |  | 			if (value === "false") return false; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case "RegExp": | 
					
						
							|  |  |  | 			if (value instanceof RegExp) return value; | 
					
						
							|  |  |  | 			if (typeof value === "string") { | 
					
						
							|  |  |  | 				// cspell:word yugi
 | 
					
						
							|  |  |  | 				const match = /^\/(.*)\/([yugi]*)$/.exec(value); | 
					
						
							| 
									
										
										
										
											2025-07-02 20:10:54 +08:00
										 |  |  | 				if (match && !/[^\\]\//.test(match[1])) { | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  | 					return new RegExp(match[1], match[2]); | 
					
						
							| 
									
										
										
										
											2025-07-02 20:10:54 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2024-08-06 11:08:48 +08:00
										 |  |  | 		case "enum": { | 
					
						
							|  |  |  | 			const values = | 
					
						
							| 
									
										
										
										
											2025-04-04 21:38:51 +08:00
										 |  |  | 				/** @type {EnumValue[]} */ | 
					
						
							| 
									
										
										
										
											2024-08-06 11:08:48 +08:00
										 |  |  | 				(argConfig.values); | 
					
						
							| 
									
										
										
										
											2025-07-02 20:10:54 +08:00
										 |  |  | 			if (values.includes(/** @type {Exclude<Value, RegExp>} */ (value))) { | 
					
						
							| 
									
										
										
										
											2025-04-04 21:38:51 +08:00
										 |  |  | 				return value; | 
					
						
							| 
									
										
										
										
											2025-07-02 20:10:54 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2024-08-06 11:08:48 +08:00
										 |  |  | 			for (const item of values) { | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  | 				if (`${item}` === value) return item; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2020-03-26 18:37:42 +08:00
										 |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2024-08-06 11:08:48 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-03-26 18:37:42 +08:00
										 |  |  | 		case "reset": | 
					
						
							|  |  |  | 			if (value === true) return []; | 
					
						
							|  |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-09 18:59:21 +08:00
										 |  |  | /** @typedef {Record<string, Value[]>} Values */ | 
					
						
							| 
									
										
										
										
											2024-08-09 23:42:37 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2024-08-09 23:42:37 +08:00
										 |  |  |  * @param {Flags} args object of arguments | 
					
						
							| 
									
										
										
										
											2025-07-09 18:59:21 +08:00
										 |  |  |  * @param {ObjectConfiguration} config configuration | 
					
						
							|  |  |  |  * @param {Values} values object with values | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  |  * @returns {Problem[] | null} problems or null for success | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | const processArguments = (args, config, values) => { | 
					
						
							|  |  |  | 	/** @type {Problem[]} */ | 
					
						
							|  |  |  | 	const problems = []; | 
					
						
							|  |  |  | 	for (const key of Object.keys(values)) { | 
					
						
							|  |  |  | 		const arg = args[key]; | 
					
						
							|  |  |  | 		if (!arg) { | 
					
						
							|  |  |  | 			problems.push({ | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  | 				type: "unknown-argument", | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  | 				path: "", | 
					
						
							|  |  |  | 				argument: key | 
					
						
							|  |  |  | 			}); | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-08-06 11:08:48 +08:00
										 |  |  | 		/** | 
					
						
							|  |  |  | 		 * @param {Value} value value | 
					
						
							| 
									
										
										
										
											2024-08-09 23:42:37 +08:00
										 |  |  | 		 * @param {number | undefined} i index | 
					
						
							| 
									
										
										
										
											2024-08-06 11:08:48 +08:00
										 |  |  | 		 */ | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  | 		const processValue = (value, i) => { | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  | 			const currentProblems = []; | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  | 			for (const argConfig of arg.configs) { | 
					
						
							|  |  |  | 				const problem = processArgumentConfig(argConfig, config, value, i); | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  | 				if (!problem) { | 
					
						
							|  |  |  | 					return; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  | 				currentProblems.push({ | 
					
						
							|  |  |  | 					...problem, | 
					
						
							|  |  |  | 					argument: key, | 
					
						
							| 
									
										
										
										
											2024-07-31 04:09:42 +08:00
										 |  |  | 					value, | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  | 					index: i | 
					
						
							|  |  |  | 				}); | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			problems.push(...currentProblems); | 
					
						
							|  |  |  | 		}; | 
					
						
							| 
									
										
										
										
											2024-07-31 04:09:42 +08:00
										 |  |  | 		const value = values[key]; | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  | 		if (Array.isArray(value)) { | 
					
						
							|  |  |  | 			for (let i = 0; i < value.length; i++) { | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  | 				processValue(value[i], i); | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2020-03-26 04:11:46 +08:00
										 |  |  | 			processValue(value, undefined); | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-03-25 18:36:33 +08:00
										 |  |  | 	if (problems.length === 0) return null; | 
					
						
							|  |  |  | 	return problems; | 
					
						
							| 
									
										
										
										
											2020-03-10 20:30:18 +08:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-07-17 21:16:32 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @returns {boolean} true when colors supported, otherwise false | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | const isColorSupported = () => { | 
					
						
							|  |  |  | 	const { env = {}, argv = [], platform = "" } = process; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	const isDisabled = "NO_COLOR" in env || argv.includes("--no-color"); | 
					
						
							|  |  |  | 	const isForced = "FORCE_COLOR" in env || argv.includes("--color"); | 
					
						
							|  |  |  | 	const isWindows = platform === "win32"; | 
					
						
							|  |  |  | 	const isDumbTerminal = env.TERM === "dumb"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	const isCompatibleTerminal = tty.isatty(1) && env.TERM && !isDumbTerminal; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	const isCI = | 
					
						
							|  |  |  | 		"CI" in env && | 
					
						
							|  |  |  | 		("GITHUB_ACTIONS" in env || "GITLAB_CI" in env || "CIRCLECI" in env); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ( | 
					
						
							|  |  |  | 		!isDisabled && | 
					
						
							|  |  |  | 		(isForced || (isWindows && !isDumbTerminal) || isCompatibleTerminal || isCI) | 
					
						
							|  |  |  | 	); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @param {number} index index | 
					
						
							|  |  |  |  * @param {string} string string | 
					
						
							|  |  |  |  * @param {string} close close | 
					
						
							|  |  |  |  * @param {string=} replace replace | 
					
						
							|  |  |  |  * @param {string=} head head | 
					
						
							|  |  |  |  * @param {string=} tail tail | 
					
						
							|  |  |  |  * @param {number=} next next | 
					
						
							|  |  |  |  * @returns {string} result | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | const replaceClose = ( | 
					
						
							|  |  |  | 	index, | 
					
						
							|  |  |  | 	string, | 
					
						
							|  |  |  | 	close, | 
					
						
							|  |  |  | 	replace, | 
					
						
							|  |  |  | 	head = string.slice(0, Math.max(0, index)) + replace, | 
					
						
							|  |  |  | 	tail = string.slice(Math.max(0, index + close.length)), | 
					
						
							|  |  |  | 	next = tail.indexOf(close) | 
					
						
							|  |  |  | ) => head + (next < 0 ? tail : replaceClose(next, tail, close, replace)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @param {number} index index to replace | 
					
						
							|  |  |  |  * @param {string} string string | 
					
						
							|  |  |  |  * @param {string} open open string | 
					
						
							|  |  |  |  * @param {string} close close string | 
					
						
							|  |  |  |  * @param {string=} replace extra replace | 
					
						
							|  |  |  |  * @returns {string} result | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | const clearBleed = (index, string, open, close, replace) => | 
					
						
							|  |  |  | 	index < 0 | 
					
						
							|  |  |  | 		? open + string + close | 
					
						
							|  |  |  | 		: open + replaceClose(index, string, close, replace) + close; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** @typedef {(value: EXPECTED_ANY) => string} PrintFunction */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @param {string} open open string | 
					
						
							|  |  |  |  * @param {string} close close string | 
					
						
							|  |  |  |  * @param {string=} replace extra replace | 
					
						
							|  |  |  |  * @param {number=} at at | 
					
						
							|  |  |  |  * @returns {PrintFunction} function to create color | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | const filterEmpty = | 
					
						
							|  |  |  | 	(open, close, replace = open, at = open.length + 1) => | 
					
						
							|  |  |  | 	(string) => | 
					
						
							|  |  |  | 		string || !(string === "" || string === undefined) | 
					
						
							|  |  |  | 			? clearBleed(`${string}`.indexOf(close, at), string, open, close, replace) | 
					
						
							|  |  |  | 			: ""; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @param {number} open open code | 
					
						
							|  |  |  |  * @param {number} close close code | 
					
						
							|  |  |  |  * @param {string=} replace extra replace | 
					
						
							|  |  |  |  * @returns {PrintFunction} result | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | const init = (open, close, replace) => | 
					
						
							|  |  |  | 	filterEmpty(`\u001B[${open}m`, `\u001B[${close}m`, replace); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @typedef {{ | 
					
						
							|  |  |  |  * reset: PrintFunction | 
					
						
							|  |  |  |  * bold: PrintFunction | 
					
						
							|  |  |  |  * dim: PrintFunction | 
					
						
							|  |  |  |  * italic: PrintFunction | 
					
						
							|  |  |  |  * underline: PrintFunction | 
					
						
							|  |  |  |  * inverse: PrintFunction | 
					
						
							|  |  |  |  * hidden: PrintFunction | 
					
						
							|  |  |  |  * strikethrough: PrintFunction | 
					
						
							|  |  |  |  * black: PrintFunction | 
					
						
							|  |  |  |  * red: PrintFunction | 
					
						
							|  |  |  |  * green: PrintFunction | 
					
						
							|  |  |  |  * yellow: PrintFunction | 
					
						
							|  |  |  |  * blue: PrintFunction | 
					
						
							|  |  |  |  * magenta: PrintFunction | 
					
						
							|  |  |  |  * cyan: PrintFunction | 
					
						
							|  |  |  |  * white: PrintFunction | 
					
						
							|  |  |  |  * gray: PrintFunction | 
					
						
							|  |  |  |  * bgBlack: PrintFunction | 
					
						
							|  |  |  |  * bgRed: PrintFunction | 
					
						
							|  |  |  |  * bgGreen: PrintFunction | 
					
						
							|  |  |  |  * bgYellow: PrintFunction | 
					
						
							|  |  |  |  * bgBlue: PrintFunction | 
					
						
							|  |  |  |  * bgMagenta: PrintFunction | 
					
						
							|  |  |  |  * bgCyan: PrintFunction | 
					
						
							|  |  |  |  * bgWhite: PrintFunction | 
					
						
							|  |  |  |  * blackBright: PrintFunction | 
					
						
							|  |  |  |  * redBright: PrintFunction | 
					
						
							|  |  |  |  * greenBright: PrintFunction | 
					
						
							|  |  |  |  * yellowBright: PrintFunction | 
					
						
							|  |  |  |  * blueBright: PrintFunction | 
					
						
							|  |  |  |  * magentaBright: PrintFunction | 
					
						
							|  |  |  |  * cyanBright: PrintFunction | 
					
						
							|  |  |  |  * whiteBright: PrintFunction | 
					
						
							|  |  |  |  * bgBlackBright: PrintFunction | 
					
						
							|  |  |  |  * bgRedBright: PrintFunction | 
					
						
							|  |  |  |  * bgGreenBright: PrintFunction | 
					
						
							|  |  |  |  * bgYellowBright: PrintFunction | 
					
						
							|  |  |  |  * bgBlueBright: PrintFunction | 
					
						
							|  |  |  |  * bgMagentaBright: PrintFunction | 
					
						
							|  |  |  |  * bgCyanBright: PrintFunction | 
					
						
							|  |  |  |  * bgWhiteBright: PrintFunction | 
					
						
							|  |  |  |  }} Colors */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							| 
									
										
										
										
											2025-07-18 20:28:16 +08:00
										 |  |  |  * @typedef {object} ColorsOptions | 
					
						
							|  |  |  |  * @property {boolean=} useColor force use colors | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @param {ColorsOptions=} options options | 
					
						
							| 
									
										
										
										
											2025-07-17 21:16:32 +08:00
										 |  |  |  * @returns {Colors} colors | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | const createColors = ({ useColor = isColorSupported() } = {}) => ({ | 
					
						
							|  |  |  | 	reset: useColor ? init(0, 0) : String, | 
					
						
							|  |  |  | 	bold: useColor ? init(1, 22, "\u001B[22m\u001B[1m") : String, | 
					
						
							|  |  |  | 	dim: useColor ? init(2, 22, "\u001B[22m\u001B[2m") : String, | 
					
						
							|  |  |  | 	italic: useColor ? init(3, 23) : String, | 
					
						
							|  |  |  | 	underline: useColor ? init(4, 24) : String, | 
					
						
							|  |  |  | 	inverse: useColor ? init(7, 27) : String, | 
					
						
							|  |  |  | 	hidden: useColor ? init(8, 28) : String, | 
					
						
							|  |  |  | 	strikethrough: useColor ? init(9, 29) : String, | 
					
						
							|  |  |  | 	black: useColor ? init(30, 39) : String, | 
					
						
							|  |  |  | 	red: useColor ? init(31, 39) : String, | 
					
						
							|  |  |  | 	green: useColor ? init(32, 39) : String, | 
					
						
							|  |  |  | 	yellow: useColor ? init(33, 39) : String, | 
					
						
							|  |  |  | 	blue: useColor ? init(34, 39) : String, | 
					
						
							|  |  |  | 	magenta: useColor ? init(35, 39) : String, | 
					
						
							|  |  |  | 	cyan: useColor ? init(36, 39) : String, | 
					
						
							|  |  |  | 	white: useColor ? init(37, 39) : String, | 
					
						
							|  |  |  | 	gray: useColor ? init(90, 39) : String, | 
					
						
							|  |  |  | 	bgBlack: useColor ? init(40, 49) : String, | 
					
						
							|  |  |  | 	bgRed: useColor ? init(41, 49) : String, | 
					
						
							|  |  |  | 	bgGreen: useColor ? init(42, 49) : String, | 
					
						
							|  |  |  | 	bgYellow: useColor ? init(43, 49) : String, | 
					
						
							|  |  |  | 	bgBlue: useColor ? init(44, 49) : String, | 
					
						
							|  |  |  | 	bgMagenta: useColor ? init(45, 49) : String, | 
					
						
							|  |  |  | 	bgCyan: useColor ? init(46, 49) : String, | 
					
						
							|  |  |  | 	bgWhite: useColor ? init(47, 49) : String, | 
					
						
							|  |  |  | 	blackBright: useColor ? init(90, 39) : String, | 
					
						
							|  |  |  | 	redBright: useColor ? init(91, 39) : String, | 
					
						
							|  |  |  | 	greenBright: useColor ? init(92, 39) : String, | 
					
						
							|  |  |  | 	yellowBright: useColor ? init(93, 39) : String, | 
					
						
							|  |  |  | 	blueBright: useColor ? init(94, 39) : String, | 
					
						
							|  |  |  | 	magentaBright: useColor ? init(95, 39) : String, | 
					
						
							|  |  |  | 	cyanBright: useColor ? init(96, 39) : String, | 
					
						
							|  |  |  | 	whiteBright: useColor ? init(97, 39) : String, | 
					
						
							|  |  |  | 	bgBlackBright: useColor ? init(100, 49) : String, | 
					
						
							|  |  |  | 	bgRedBright: useColor ? init(101, 49) : String, | 
					
						
							|  |  |  | 	bgGreenBright: useColor ? init(102, 49) : String, | 
					
						
							|  |  |  | 	bgYellowBright: useColor ? init(103, 49) : String, | 
					
						
							|  |  |  | 	bgBlueBright: useColor ? init(104, 49) : String, | 
					
						
							|  |  |  | 	bgMagentaBright: useColor ? init(105, 49) : String, | 
					
						
							|  |  |  | 	bgCyanBright: useColor ? init(106, 49) : String, | 
					
						
							|  |  |  | 	bgWhiteBright: useColor ? init(107, 49) : String | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | module.exports.createColors = createColors; | 
					
						
							| 
									
										
										
										
											2024-07-31 04:54:55 +08:00
										 |  |  | module.exports.getArguments = getArguments; | 
					
						
							| 
									
										
										
										
											2025-07-17 21:16:32 +08:00
										 |  |  | module.exports.isColorSupported = isColorSupported; | 
					
						
							| 
									
										
										
										
											2024-07-31 04:54:55 +08:00
										 |  |  | module.exports.processArguments = processArguments; |