registry/src/utils/validator.js
Cheney f9f3184f98
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 31s
fix
2026-08-07 14:46:52 +08:00

125 lines
4.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 配置值校验工具
* 根据配置类型校验值的格式,编辑模式下额外校验值范围
*/
/**
* 支持的值类型列表
*/
const VALID_TYPES = ["string", "number", "boolean", "json"];
/**
* 校验配置值是否符合指定的类型
* @param {any} value - 配置值
* @param {string} type - 配置类型string/number/boolean/json
* @returns {{ valid: boolean, message: string }} 校验结果
*/
function validateByType(value, type) {
if (!VALID_TYPES.includes(type)) {
return { valid: false, message: `不支持的类型: ${type},支持的类型: ${VALID_TYPES.join(", ")}` };
}
switch (type) {
case "string":
if (typeof value !== "string") {
return { valid: false, message: "值必须是字符串类型" };
}
break;
case "number": {
if (value === null || value === undefined || String(value).trim() === "") {
return { valid: false, message: "值必须是有效的数字" };
}
const num = Number(value);
if (isNaN(num)) {
return { valid: false, message: "值必须是有效的数字" };
}
break;
}
case "boolean":
if (typeof value !== "boolean" && value !== "true" && value !== "false") {
return { valid: false, message: "值必须是布尔类型true 或 false" };
}
break;
case "json":
try {
JSON.parse(typeof value === "string" ? value : JSON.stringify(value));
} catch {
return { valid: false, message: "值必须是有效的 JSON 格式" };
}
break;
}
return { valid: true, message: "" };
}
/**
* 校验值范围约束(仅在编辑模式下生效)
* 支持:
* - 正则约束string 类型常用):"/正则/flags",如 /^1[3-9]\d{9}$/(手机号)
* - 区间范围:"1-100" 或 "0.0-1.0"
* - 枚举范围:"枚举: A,B,C"
* - 描述性范围(如 "合法 IPv4 地址")仅作提示,不做强制校验
* @param {any} value - 配置值
* @param {string} valueRange - 值范围描述
* @returns {{ valid: boolean, message: string }} 校验结果
*/
function validateRange(value, valueRange) {
if (!valueRange || valueRange.trim() === "") {
return { valid: true, message: "" };
}
const range = valueRange.trim();
// 正则约束: "/pattern/flags",如 /^1[3-9]\d{9}$/(手机号)
if (range.startsWith("/")) {
// pattern 中未转义的 / 不允许(与 JS 正则字面量一致flags 仅允许字母
const regexMatch = range.match(/^\/((?:\\.|[^\\/])*)\/([a-z]*)$/);
if (!regexMatch) {
return { valid: false, message: `正则格式无效: ${range},正确格式为 /pattern/flags` };
}
const pattern = regexMatch[1];
const flags = regexMatch[2] || "";
let re;
try {
re = new RegExp(pattern, flags);
} catch (e) {
return { valid: false, message: `正则表达式无效: /${pattern}/` };
}
// 保留 g/y 标志语义test 前重置 lastIndex避免状态残留
re.lastIndex = 0;
if (!re.test(String(value))) {
return { valid: false, message: `值不符合格式要求: /${pattern}/` };
}
return { valid: true, message: "" };
}
// 区间范围: "1-100" 或 "0.0-1.0"
const rangeMatch = range.match(/^(-?\d+(\.\d+)?)\s*-\s*(-?\d+(\.\d+)?)$/);
if (rangeMatch) {
const min = Number(rangeMatch[1]);
const max = Number(rangeMatch[3]);
if (min > max) {
return { valid: false, message: `范围下限 ${min} 大于上限 ${max}` };
}
const num = Number(value);
if (isNaN(num) || num < min || num > max) {
return { valid: false, message: `值必须在 ${min}${max} 之间` };
}
return { valid: true, message: "" };
}
// 枚举范围: "枚举: A,B,C"
const enumMatch = range.match(/^枚举[:]\s*(.+)$/);
if (enumMatch) {
const options = enumMatch[1].split(/[,]/).map((s) => s.trim());
if (!options.includes(String(value).trim())) {
return { valid: false, message: `值必须是以下选项之一: ${options.join(", ")}` };
}
return { valid: true, message: "" };
}
// 其他描述性范围(如 "合法 IPv4 地址")目前不做强制校验,仅作提示
return { valid: true, message: "" };
}
module.exports = { VALID_TYPES, validateByType, validateRange };