befly 3.15.17 → 3.15.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/befly.js +311 -146
- package/dist/befly.min.js +13 -13
- package/dist/checks/checkTable.js +77 -81
- package/dist/configs/presetRegexp.js +19 -3
- package/dist/lib/validator.js +21 -47
- package/dist/sync/syncTable.d.ts +3 -1
- package/dist/sync/syncTable.js +104 -17
- package/dist/types/validate.d.ts +11 -1
- package/dist/utils/normalizeFieldDefinition.d.ts +2 -0
- package/dist/utils/normalizeFieldDefinition.js +6 -0
- package/dist/utils/util.d.ts +77 -0
- package/dist/utils/util.js +181 -0
- package/package.json +2 -2
package/dist/befly.js
CHANGED
|
@@ -49,6 +49,84 @@ function isPlainObject(value) {
|
|
|
49
49
|
const proto = Object.getPrototypeOf(value);
|
|
50
50
|
return proto === Object.prototype || proto === null;
|
|
51
51
|
}
|
|
52
|
+
function isJsonPrimitive(value) {
|
|
53
|
+
if (value === null) {
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
return typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
57
|
+
}
|
|
58
|
+
function isJsonObject(value) {
|
|
59
|
+
if (!value || typeof value !== "object") {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
if (value instanceof Date) {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
if (Array.isArray(value)) {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
function isJsonStructure(value) {
|
|
71
|
+
return Array.isArray(value) || isJsonObject(value);
|
|
72
|
+
}
|
|
73
|
+
function isJsonValue(value) {
|
|
74
|
+
if (isJsonPrimitive(value)) {
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
if (Array.isArray(value)) {
|
|
78
|
+
for (const item of value) {
|
|
79
|
+
if (!isJsonValue(item)) {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
if (isJsonObject(value)) {
|
|
86
|
+
for (const v of Object.values(value)) {
|
|
87
|
+
if (v === undefined) {
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
if (!isJsonValue(v)) {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
function isFiniteNumber(value) {
|
|
99
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
100
|
+
}
|
|
101
|
+
function isIntegerNumber(value) {
|
|
102
|
+
return typeof value === "number" && Number.isFinite(value) && Number.isInteger(value);
|
|
103
|
+
}
|
|
104
|
+
function formatValuePreview(value) {
|
|
105
|
+
if (value === null) {
|
|
106
|
+
return "null";
|
|
107
|
+
}
|
|
108
|
+
if (value === undefined) {
|
|
109
|
+
return "undefined";
|
|
110
|
+
}
|
|
111
|
+
if (typeof value === "string") {
|
|
112
|
+
const s2 = value.length > 80 ? `${value.slice(0, 80)}...` : value;
|
|
113
|
+
return JSON.stringify(s2);
|
|
114
|
+
}
|
|
115
|
+
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
|
|
116
|
+
return String(value);
|
|
117
|
+
}
|
|
118
|
+
if (typeof value === "function") {
|
|
119
|
+
return "[Function]";
|
|
120
|
+
}
|
|
121
|
+
try {
|
|
122
|
+
const s2 = JSON.stringify(value);
|
|
123
|
+
if (typeof s2 === "string") {
|
|
124
|
+
return s2.length > 120 ? `${s2.slice(0, 120)}...` : s2;
|
|
125
|
+
}
|
|
126
|
+
} catch {}
|
|
127
|
+
const s = String(value);
|
|
128
|
+
return s.length > 120 ? `${s.slice(0, 120)}...` : s;
|
|
129
|
+
}
|
|
52
130
|
function getTypeTag(value) {
|
|
53
131
|
if (value === null)
|
|
54
132
|
return "null";
|
|
@@ -71,6 +149,38 @@ function getTypeTag(value) {
|
|
|
71
149
|
return "function";
|
|
72
150
|
return "object";
|
|
73
151
|
}
|
|
152
|
+
function isRegexLiteral(input) {
|
|
153
|
+
const trimmed = String(input || "").trim();
|
|
154
|
+
if (trimmed.length < 2) {
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
if (!trimmed.startsWith("/")) {
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
const lastSlash = trimmed.lastIndexOf("/");
|
|
161
|
+
if (lastSlash <= 0) {
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
const flags = trimmed.slice(lastSlash + 1);
|
|
165
|
+
if (flags !== "" && !/^[gimsuy]+$/.test(flags)) {
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
function isRegexInput(input) {
|
|
171
|
+
const trimmed = String(input || "").trim();
|
|
172
|
+
return isRegexLiteral(trimmed) || trimmed.startsWith("@");
|
|
173
|
+
}
|
|
174
|
+
function isEnumInput(input) {
|
|
175
|
+
const trimmed = String(input || "").trim();
|
|
176
|
+
if (trimmed.length === 0) {
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
return !trimmed.startsWith("/") && trimmed.includes("|");
|
|
180
|
+
}
|
|
181
|
+
function isAliasInput(input) {
|
|
182
|
+
return String(input || "").trim().startsWith("@");
|
|
183
|
+
}
|
|
74
184
|
function normalizePositiveInt(value, fallback, min, max) {
|
|
75
185
|
if (typeof value !== "number")
|
|
76
186
|
return fallback;
|
|
@@ -8181,79 +8291,13 @@ async function checkPlugin(plugins) {
|
|
|
8181
8291
|
|
|
8182
8292
|
// checks/checkTable.ts
|
|
8183
8293
|
init_logger();
|
|
8184
|
-
|
|
8185
|
-
if (value === null)
|
|
8186
|
-
return true;
|
|
8187
|
-
return typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
8188
|
-
}
|
|
8189
|
-
function isJsonObject(value) {
|
|
8190
|
-
if (!value || typeof value !== "object")
|
|
8191
|
-
return false;
|
|
8192
|
-
if (value instanceof Date)
|
|
8193
|
-
return false;
|
|
8194
|
-
if (Array.isArray(value))
|
|
8195
|
-
return false;
|
|
8196
|
-
return true;
|
|
8197
|
-
}
|
|
8198
|
-
function isJsonValue(value) {
|
|
8199
|
-
if (isJsonPrimitive(value))
|
|
8200
|
-
return true;
|
|
8201
|
-
if (Array.isArray(value)) {
|
|
8202
|
-
for (const item of value) {
|
|
8203
|
-
if (!isJsonValue(item))
|
|
8204
|
-
return false;
|
|
8205
|
-
}
|
|
8206
|
-
return true;
|
|
8207
|
-
}
|
|
8208
|
-
if (isJsonObject(value)) {
|
|
8209
|
-
for (const v of Object.values(value)) {
|
|
8210
|
-
if (v === undefined)
|
|
8211
|
-
continue;
|
|
8212
|
-
if (!isJsonValue(v))
|
|
8213
|
-
return false;
|
|
8214
|
-
}
|
|
8215
|
-
return true;
|
|
8216
|
-
}
|
|
8217
|
-
return false;
|
|
8218
|
-
}
|
|
8219
|
-
function formatValuePreview(value) {
|
|
8220
|
-
if (value === null)
|
|
8221
|
-
return "null";
|
|
8222
|
-
if (value === undefined)
|
|
8223
|
-
return "undefined";
|
|
8224
|
-
if (typeof value === "string") {
|
|
8225
|
-
const s2 = value.length > 80 ? `${value.slice(0, 80)}...` : value;
|
|
8226
|
-
return JSON.stringify(s2);
|
|
8227
|
-
}
|
|
8228
|
-
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
|
|
8229
|
-
return String(value);
|
|
8230
|
-
}
|
|
8231
|
-
if (typeof value === "function") {
|
|
8232
|
-
return "[Function]";
|
|
8233
|
-
}
|
|
8234
|
-
try {
|
|
8235
|
-
const s2 = JSON.stringify(value);
|
|
8236
|
-
if (typeof s2 === "string") {
|
|
8237
|
-
return s2.length > 120 ? `${s2.slice(0, 120)}...` : s2;
|
|
8238
|
-
}
|
|
8239
|
-
} catch {}
|
|
8240
|
-
const s = String(value);
|
|
8241
|
-
return s.length > 120 ? `${s.slice(0, 120)}...` : s;
|
|
8242
|
-
}
|
|
8294
|
+
init_util();
|
|
8243
8295
|
var RESERVED_FIELDS = ["id", "created_at", "updated_at", "deleted_at", "state"];
|
|
8244
8296
|
var RESERVED_FIELD_SET = new Set(RESERVED_FIELDS);
|
|
8245
|
-
var FIELD_TYPES = ["tinyint", "smallint", "mediumint", "int", "bigint", "char", "varchar", "tinytext", "text", "mediumtext", "longtext", "datetime", "json"];
|
|
8297
|
+
var FIELD_TYPES = ["tinyint", "smallint", "mediumint", "int", "bigint", "decimal", "float", "double", "char", "varchar", "tinytext", "text", "mediumtext", "longtext", "datetime", "json"];
|
|
8246
8298
|
var FIELD_TYPE_SET = new Set(FIELD_TYPES);
|
|
8247
8299
|
var INPUT_TYPES = ["number", "integer", "string", "char", "array", "array_number", "array_integer", "json", "json_number", "json_integer"];
|
|
8248
8300
|
var INPUT_TYPE_SET = new Set(INPUT_TYPES);
|
|
8249
|
-
function isRegexInput(input) {
|
|
8250
|
-
if (input.startsWith("@"))
|
|
8251
|
-
return true;
|
|
8252
|
-
return /[\\^$.*+?()[\]{}]/.test(input);
|
|
8253
|
-
}
|
|
8254
|
-
function isEnumInput(input) {
|
|
8255
|
-
return input.includes("|") && !isRegexInput(input);
|
|
8256
|
-
}
|
|
8257
8301
|
function inferInputByType(dbType) {
|
|
8258
8302
|
switch (dbType.toLowerCase()) {
|
|
8259
8303
|
case "tinyint":
|
|
@@ -8262,6 +8306,10 @@ function inferInputByType(dbType) {
|
|
|
8262
8306
|
case "int":
|
|
8263
8307
|
case "bigint":
|
|
8264
8308
|
return "integer";
|
|
8309
|
+
case "decimal":
|
|
8310
|
+
case "float":
|
|
8311
|
+
case "double":
|
|
8312
|
+
return "number";
|
|
8265
8313
|
case "char":
|
|
8266
8314
|
case "varchar":
|
|
8267
8315
|
case "tinytext":
|
|
@@ -8285,7 +8333,7 @@ function normalizeTypeAndInput(type, input) {
|
|
|
8285
8333
|
input: rawInput || inferInputByType(rawType)
|
|
8286
8334
|
};
|
|
8287
8335
|
}
|
|
8288
|
-
var ALLOWED_FIELD_PROPERTIES = ["name", "type", "input", "min", "max", "default", "detail", "index", "unique", "nullable", "unsigned"];
|
|
8336
|
+
var ALLOWED_FIELD_PROPERTIES = ["name", "type", "input", "min", "max", "default", "detail", "precision", "scale", "index", "unique", "nullable", "unsigned"];
|
|
8289
8337
|
var ALLOWED_FIELD_PROPERTY_SET = new Set(ALLOWED_FIELD_PROPERTIES);
|
|
8290
8338
|
var LOWER_CAMEL_CASE_REGEX = /^_?[a-z][a-z0-9]*(?:[A-Z][a-z0-9]*)*$/;
|
|
8291
8339
|
var FIELD_NAME_REGEX = /^[\u4e00-\u9fa5a-zA-Z0-9 _-]+$/;
|
|
@@ -8324,8 +8372,9 @@ async function checkTable(tables, config2) {
|
|
|
8324
8372
|
hasError = true;
|
|
8325
8373
|
continue;
|
|
8326
8374
|
}
|
|
8327
|
-
|
|
8328
|
-
|
|
8375
|
+
const dbFieldName = snakeCase(colKey);
|
|
8376
|
+
if (RESERVED_FIELD_SET.has(colKey) || RESERVED_FIELD_SET.has(dbFieldName)) {
|
|
8377
|
+
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6\u5305\u542B\u4FDD\u7559\u5B57\u6BB5 ${colKey}\uFF08\u6620\u5C04\u5217\u540D: ${dbFieldName}\uFF09\uFF0C` + `\u4E0D\u80FD\u5728\u8868\u5B9A\u4E49\u4E2D\u4F7F\u7528\u4EE5\u4E0B\u5B57\u6BB5: ${RESERVED_FIELDS.join(", ")}`);
|
|
8329
8378
|
hasError = true;
|
|
8330
8379
|
}
|
|
8331
8380
|
const field = fieldDef;
|
|
@@ -8361,6 +8410,14 @@ async function checkTable(tables, config2) {
|
|
|
8361
8410
|
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u5B57\u6BB5 detail \u7C7B\u578B\u9519\u8BEF\uFF0C\u5FC5\u987B\u4E3A\u5B57\u7B26\u4E32`);
|
|
8362
8411
|
hasError = true;
|
|
8363
8412
|
}
|
|
8413
|
+
if (field.precision !== undefined && !(field.precision === null || typeof field.precision === "number")) {
|
|
8414
|
+
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u5B57\u6BB5 precision \u7C7B\u578B\u9519\u8BEF\uFF0C\u5FC5\u987B\u4E3A null \u6216\u6570\u5B57`);
|
|
8415
|
+
hasError = true;
|
|
8416
|
+
}
|
|
8417
|
+
if (field.scale !== undefined && !(field.scale === null || typeof field.scale === "number")) {
|
|
8418
|
+
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u5B57\u6BB5 scale \u7C7B\u578B\u9519\u8BEF\uFF0C\u5FC5\u987B\u4E3A null \u6216\u6570\u5B57`);
|
|
8419
|
+
hasError = true;
|
|
8420
|
+
}
|
|
8364
8421
|
if (field.index !== undefined && typeof field.index !== "boolean") {
|
|
8365
8422
|
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u5B57\u6BB5 index \u7C7B\u578B\u9519\u8BEF\uFF0C\u5FC5\u987B\u4E3A\u5E03\u5C14\u503C`);
|
|
8366
8423
|
hasError = true;
|
|
@@ -8398,25 +8455,32 @@ async function checkTable(tables, config2) {
|
|
|
8398
8455
|
if (normalizedInput === "") {
|
|
8399
8456
|
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u5B57\u6BB5 input \u65E0\u6CD5\u63A8\u5BFC`);
|
|
8400
8457
|
hasError = true;
|
|
8401
|
-
} else if (!INPUT_TYPE_SET.has(normalizedInput) && !isRegexInput(normalizedInput) && !isEnumInput(normalizedInput)) {
|
|
8402
|
-
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u5B57\u6BB5 input "${normalizedInput}" \u4E0D\u5408\u6CD5\uFF0C` + `\u5FC5\u987B\u4E3A${INPUT_TYPES.join("\u3001")}\u4E4B\u4E00\uFF0C\u6216\u6B63\u5219/\u679A\u4E3E`);
|
|
8458
|
+
} else if (!INPUT_TYPE_SET.has(normalizedInput) && !isRegexInput(normalizedInput) && !isEnumInput(normalizedInput) && !isAliasInput(normalizedInput)) {
|
|
8459
|
+
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u5B57\u6BB5 input "${normalizedInput}" \u4E0D\u5408\u6CD5\uFF0C` + `\u5FC5\u987B\u4E3A${INPUT_TYPES.join("\u3001")}\u4E4B\u4E00\uFF0C\u6216\u6B63\u5219/\u679A\u4E3E/\u6B63\u5219\u522B\u540D`);
|
|
8403
8460
|
hasError = true;
|
|
8404
8461
|
}
|
|
8405
8462
|
const isStringDbType = ["char", "varchar", "tinytext", "text", "mediumtext", "longtext"].includes(effectiveType);
|
|
8406
8463
|
const isTextDbType = ["tinytext", "text", "mediumtext", "longtext"].includes(effectiveType);
|
|
8407
8464
|
const isIntDbType = ["tinyint", "smallint", "mediumint", "int", "bigint"].includes(effectiveType);
|
|
8465
|
+
const isDecimalDbType = effectiveType === "decimal";
|
|
8466
|
+
const isFloatDbType = effectiveType === "float" || effectiveType === "double";
|
|
8408
8467
|
const isJsonDbType = effectiveType === "json";
|
|
8409
|
-
|
|
8468
|
+
const isNumericDbType = isIntDbType || isDecimalDbType || isFloatDbType;
|
|
8469
|
+
if (isRegexInput(normalizedInput) || isEnumInput(normalizedInput) || isAliasInput(normalizedInput)) {
|
|
8410
8470
|
if (!isStringDbType) {
|
|
8411
|
-
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u5B57\u6BB5 input \u4F7F\u7528\u6B63\u5219/\u679A\u4E3E\uFF0C\u4EC5\u5141\u8BB8\u5B57\u7B26\u4E32\u7C7B\u5B57\u6BB5\uFF08char/varchar/text\uFF09`);
|
|
8471
|
+
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u5B57\u6BB5 input \u4F7F\u7528\u6B63\u5219/\u679A\u4E3E/\u6B63\u5219\u522B\u540D\uFF0C\u4EC5\u5141\u8BB8\u5B57\u7B26\u4E32\u7C7B\u5B57\u6BB5\uFF08char/varchar/text\uFF09`);
|
|
8412
8472
|
hasError = true;
|
|
8413
8473
|
}
|
|
8414
8474
|
}
|
|
8415
8475
|
if (normalizedInput === "number" || normalizedInput === "integer") {
|
|
8416
|
-
if (!isIntDbType) {
|
|
8476
|
+
if (normalizedInput === "integer" && !isIntDbType) {
|
|
8417
8477
|
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u5B57\u6BB5 input=${normalizedInput} \u4EC5\u5141\u8BB8\u6574\u6570\u7C7B\u5B57\u6BB5\uFF08tinyint/smallint/mediumint/int/bigint\uFF09`);
|
|
8418
8478
|
hasError = true;
|
|
8419
8479
|
}
|
|
8480
|
+
if (normalizedInput === "number" && !isNumericDbType) {
|
|
8481
|
+
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u5B57\u6BB5 input=${normalizedInput} \u4EC5\u5141\u8BB8\u6570\u503C\u7C7B\u5B57\u6BB5\uFF08tinyint/smallint/mediumint/int/bigint/decimal\uFF09`);
|
|
8482
|
+
hasError = true;
|
|
8483
|
+
}
|
|
8420
8484
|
}
|
|
8421
8485
|
if (normalizedInput === "array" || normalizedInput === "array_number" || normalizedInput === "array_integer") {
|
|
8422
8486
|
if (!isStringDbType) {
|
|
@@ -8430,8 +8494,8 @@ async function checkTable(tables, config2) {
|
|
|
8430
8494
|
hasError = true;
|
|
8431
8495
|
}
|
|
8432
8496
|
}
|
|
8433
|
-
if (!
|
|
8434
|
-
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u5B57\u6BB5\u7C7B\u578B\u4E3A ${effectiveType}\uFF0C\u4E0D\u5141\u8BB8\u8BBE\u7F6E unsigned\uFF08\u4EC5\
|
|
8497
|
+
if (!isNumericDbType && field.unsigned !== undefined) {
|
|
8498
|
+
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u5B57\u6BB5\u7C7B\u578B\u4E3A ${effectiveType}\uFF0C\u4E0D\u5141\u8BB8\u8BBE\u7F6E unsigned\uFF08\u4EC5\u6570\u503C\u7C7B\u578B\u6709\u6548\uFF09`);
|
|
8435
8499
|
hasError = true;
|
|
8436
8500
|
}
|
|
8437
8501
|
if (field.unique === true && field.index === true) {
|
|
@@ -8482,6 +8546,31 @@ async function checkTable(tables, config2) {
|
|
|
8482
8546
|
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A datetime \u7C7B\u578B\uFF0C\u4E0D\u5141\u8BB8\u8BBE\u7F6E unsigned`);
|
|
8483
8547
|
hasError = true;
|
|
8484
8548
|
}
|
|
8549
|
+
} else if (isDecimalDbType) {
|
|
8550
|
+
const precision = field.precision;
|
|
8551
|
+
const scale = field.scale;
|
|
8552
|
+
if (typeof precision !== "number") {
|
|
8553
|
+
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A decimal \u7C7B\u578B\uFF0C\u5FC5\u987B\u8BBE\u7F6E precision\uFF08\u603B\u4F4D\u6570\uFF09`);
|
|
8554
|
+
hasError = true;
|
|
8555
|
+
} else if (precision < 1 || precision > 65) {
|
|
8556
|
+
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A decimal \u7C7B\u578B\uFF0Cprecision \u5FC5\u987B\u5728 1..65 \u8303\u56F4\u5185\uFF0C\u5F53\u524D\u4E3A ${precision}`);
|
|
8557
|
+
hasError = true;
|
|
8558
|
+
}
|
|
8559
|
+
if (typeof scale !== "number") {
|
|
8560
|
+
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A decimal \u7C7B\u578B\uFF0C\u5FC5\u987B\u8BBE\u7F6E scale\uFF08\u5C0F\u6570\u4F4D\u6570\uFF09`);
|
|
8561
|
+
hasError = true;
|
|
8562
|
+
} else if (scale < 0 || scale > 30) {
|
|
8563
|
+
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A decimal \u7C7B\u578B\uFF0Cscale \u5FC5\u987B\u5728 0..30 \u8303\u56F4\u5185\uFF0C\u5F53\u524D\u4E3A ${scale}`);
|
|
8564
|
+
hasError = true;
|
|
8565
|
+
}
|
|
8566
|
+
if (typeof precision === "number" && typeof scale === "number" && scale > precision) {
|
|
8567
|
+
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A decimal \u7C7B\u578B\uFF0Cscale \u4E0D\u80FD\u5927\u4E8E precision\uFF08precision=${precision}, scale=${scale}\uFF09`);
|
|
8568
|
+
hasError = true;
|
|
8569
|
+
}
|
|
8570
|
+
if (field.default !== undefined && field.default !== null && typeof field.default !== "number") {
|
|
8571
|
+
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A decimal \u7C7B\u578B\uFF0C\u9ED8\u8BA4\u503C\u5FC5\u987B\u4E3A\u6570\u5B57\u6216 null` + `\uFF08typeof=${typeof field.default}\uFF0Cvalue=${formatValuePreview(field.default)}\uFF09`);
|
|
8572
|
+
hasError = true;
|
|
8573
|
+
}
|
|
8485
8574
|
} else if (effectiveType === "char" || effectiveType === "varchar") {
|
|
8486
8575
|
if (field.max === undefined || field.max === null || typeof field.max !== "number") {
|
|
8487
8576
|
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A ${effectiveType} \u7C7B\u578B\uFF0C` + `\u5FC5\u987B\u8BBE\u7F6E max \u4E14\u7C7B\u578B\u4E3A\u6570\u5B57\uFF0C\u5F53\u524D\u4E3A "${field.max}"`);
|
|
@@ -8512,6 +8601,11 @@ async function checkTable(tables, config2) {
|
|
|
8512
8601
|
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A ${effectiveType} \u7C7B\u578B\uFF0C\u9ED8\u8BA4\u503C\u5FC5\u987B\u4E3A\u6570\u5B57\u6216 null` + `\uFF08typeof=${typeof field.default}\uFF0Cvalue=${formatValuePreview(field.default)}\uFF09`);
|
|
8513
8602
|
hasError = true;
|
|
8514
8603
|
}
|
|
8604
|
+
} else if (isFloatDbType) {
|
|
8605
|
+
if (field.default !== undefined && field.default !== null && typeof field.default !== "number") {
|
|
8606
|
+
Logger.warn(`${tablePrefix}${fileName} \u6587\u4EF6 ${colKey} \u4E3A ${effectiveType} \u7C7B\u578B\uFF0C\u9ED8\u8BA4\u503C\u5FC5\u987B\u4E3A\u6570\u5B57\u6216 null` + `\uFF08typeof=${typeof field.default}\uFF0Cvalue=${formatValuePreview(field.default)}\uFF09`);
|
|
8607
|
+
hasError = true;
|
|
8608
|
+
}
|
|
8515
8609
|
}
|
|
8516
8610
|
}
|
|
8517
8611
|
} catch (error) {
|
|
@@ -9900,6 +9994,10 @@ function inferInputByType2(dbType) {
|
|
|
9900
9994
|
case "int":
|
|
9901
9995
|
case "bigint":
|
|
9902
9996
|
return "integer";
|
|
9997
|
+
case "decimal":
|
|
9998
|
+
case "float":
|
|
9999
|
+
case "double":
|
|
10000
|
+
return "number";
|
|
9903
10001
|
case "char":
|
|
9904
10002
|
case "varchar":
|
|
9905
10003
|
case "tinytext":
|
|
@@ -9936,6 +10034,8 @@ function normalizeFieldDefinition(fieldDef) {
|
|
|
9936
10034
|
detail: fieldDef.detail ?? "",
|
|
9937
10035
|
min: fieldDef.min ?? null,
|
|
9938
10036
|
max: fieldDef.max ?? null,
|
|
10037
|
+
precision: fieldDef.precision ?? null,
|
|
10038
|
+
scale: fieldDef.scale ?? null,
|
|
9939
10039
|
default: normalizedDefault,
|
|
9940
10040
|
index: fieldDef.index ?? false,
|
|
9941
10041
|
unique: fieldDef.unique ?? false,
|
|
@@ -10093,6 +10193,9 @@ class SyncTable {
|
|
|
10093
10193
|
mediumint: "MEDIUMINT",
|
|
10094
10194
|
int: "INT",
|
|
10095
10195
|
bigint: "BIGINT",
|
|
10196
|
+
decimal: "DECIMAL",
|
|
10197
|
+
float: "FLOAT",
|
|
10198
|
+
double: "DOUBLE",
|
|
10096
10199
|
char: "CHAR",
|
|
10097
10200
|
varchar: "VARCHAR",
|
|
10098
10201
|
datetime: "DATETIME",
|
|
@@ -10104,6 +10207,8 @@ class SyncTable {
|
|
|
10104
10207
|
};
|
|
10105
10208
|
static TEXT_FAMILY = new Set(["tinytext", "text", "mediumtext", "longtext"]);
|
|
10106
10209
|
static INT_TYPES = new Set(["tinyint", "smallint", "mediumint", "int", "bigint"]);
|
|
10210
|
+
static DECIMAL_TYPES = new Set(["decimal"]);
|
|
10211
|
+
static FLOAT_TYPES = new Set(["float", "double"]);
|
|
10107
10212
|
db;
|
|
10108
10213
|
dbName;
|
|
10109
10214
|
constructor(ctx) {
|
|
@@ -10187,6 +10292,8 @@ class SyncTable {
|
|
|
10187
10292
|
fieldDef.detail = normalized.detail;
|
|
10188
10293
|
fieldDef.min = normalized.min;
|
|
10189
10294
|
fieldDef.max = normalized.max;
|
|
10295
|
+
fieldDef.precision = normalized.precision;
|
|
10296
|
+
fieldDef.scale = normalized.scale;
|
|
10190
10297
|
fieldDef.default = normalized.default;
|
|
10191
10298
|
fieldDef.index = normalized.index;
|
|
10192
10299
|
fieldDef.unique = normalized.unique;
|
|
@@ -10207,7 +10314,7 @@ class SyncTable {
|
|
|
10207
10314
|
}
|
|
10208
10315
|
return `\`${trimmed}\``;
|
|
10209
10316
|
}
|
|
10210
|
-
static getSqlType(fieldType, fieldMax, unsigned = false) {
|
|
10317
|
+
static getSqlType(fieldType, fieldMax, unsigned = false, precision = null, scale = null) {
|
|
10211
10318
|
const normalizedType = String(fieldType || "").toLowerCase();
|
|
10212
10319
|
const typeMapping = SyncTable.TYPE_MAPPING;
|
|
10213
10320
|
if (SyncTable.isStringOrArrayType(normalizedType)) {
|
|
@@ -10216,8 +10323,15 @@ class SyncTable {
|
|
|
10216
10323
|
}
|
|
10217
10324
|
return `${typeMapping[normalizedType]}(${fieldMax})`;
|
|
10218
10325
|
}
|
|
10326
|
+
if (SyncTable.DECIMAL_TYPES.has(normalizedType)) {
|
|
10327
|
+
if (typeof precision !== "number" || typeof scale !== "number") {
|
|
10328
|
+
throw new Error(`\u540C\u6B65\u8868\uFF1A\u5185\u90E8\u9519\u8BEF\uFF1Adecimal \u7C7B\u578B\u7F3A\u5931 precision/scale\uFF08\u5E94\u7531 checkTable \u963B\u65AD\uFF09`);
|
|
10329
|
+
}
|
|
10330
|
+
const base = `${typeMapping[normalizedType]}(${precision},${scale})`;
|
|
10331
|
+
return unsigned ? `${base} UNSIGNED` : base;
|
|
10332
|
+
}
|
|
10219
10333
|
const baseType = typeMapping[normalizedType] || "TEXT";
|
|
10220
|
-
if (SyncTable.INT_TYPES.has(normalizedType) && unsigned) {
|
|
10334
|
+
if ((SyncTable.INT_TYPES.has(normalizedType) || SyncTable.FLOAT_TYPES.has(normalizedType)) && unsigned) {
|
|
10221
10335
|
return `${baseType} UNSIGNED`;
|
|
10222
10336
|
}
|
|
10223
10337
|
return baseType;
|
|
@@ -10233,6 +10347,9 @@ class SyncTable {
|
|
|
10233
10347
|
case "mediumint":
|
|
10234
10348
|
case "int":
|
|
10235
10349
|
case "bigint":
|
|
10350
|
+
case "decimal":
|
|
10351
|
+
case "float":
|
|
10352
|
+
case "double":
|
|
10236
10353
|
return 0;
|
|
10237
10354
|
case "char":
|
|
10238
10355
|
case "varchar":
|
|
@@ -10254,7 +10371,7 @@ class SyncTable {
|
|
|
10254
10371
|
if (SyncTable.TEXT_FAMILY.has(normalizedType) || normalizedType === "json" || actualDefault === "null") {
|
|
10255
10372
|
return "";
|
|
10256
10373
|
}
|
|
10257
|
-
if (SyncTable.INT_TYPES.has(normalizedType) || SyncTable.isStringOrArrayType(normalizedType)) {
|
|
10374
|
+
if (SyncTable.INT_TYPES.has(normalizedType) || SyncTable.DECIMAL_TYPES.has(normalizedType) || SyncTable.FLOAT_TYPES.has(normalizedType) || SyncTable.isStringOrArrayType(normalizedType)) {
|
|
10258
10375
|
if (typeof actualDefault === "number" && !Number.isNaN(actualDefault)) {
|
|
10259
10376
|
return ` DEFAULT ${actualDefault}`;
|
|
10260
10377
|
} else {
|
|
@@ -10276,10 +10393,31 @@ class SyncTable {
|
|
|
10276
10393
|
}
|
|
10277
10394
|
return "";
|
|
10278
10395
|
}
|
|
10279
|
-
static normalizeDefaultForCompare(value) {
|
|
10396
|
+
static normalizeDefaultForCompare(value, fieldType) {
|
|
10280
10397
|
if (value === null || value === undefined)
|
|
10281
10398
|
return "null";
|
|
10282
|
-
|
|
10399
|
+
const normalizedType = String(fieldType || "").toLowerCase();
|
|
10400
|
+
const raw = String(value).trim();
|
|
10401
|
+
if (SyncTable.INT_TYPES.has(normalizedType) || SyncTable.DECIMAL_TYPES.has(normalizedType) || SyncTable.FLOAT_TYPES.has(normalizedType)) {
|
|
10402
|
+
if (/^[+-]?\d+(?:\.\d+)?$/.test(raw)) {
|
|
10403
|
+
let sign = "";
|
|
10404
|
+
let body = raw;
|
|
10405
|
+
if (body.startsWith("+") || body.startsWith("-")) {
|
|
10406
|
+
sign = body.startsWith("-") ? "-" : "";
|
|
10407
|
+
body = body.slice(1);
|
|
10408
|
+
}
|
|
10409
|
+
const parts = body.split(".");
|
|
10410
|
+
const intPart = parts[0] || "0";
|
|
10411
|
+
const fracPart = parts[1] || "";
|
|
10412
|
+
const normalizedInt = intPart.replace(/^0+(\d)/, "$1");
|
|
10413
|
+
const normalizedFrac = fracPart.replace(/0+$/g, "");
|
|
10414
|
+
const mergedInt = normalizedInt === "" ? "0" : normalizedInt;
|
|
10415
|
+
const merged = normalizedFrac.length > 0 ? `${mergedInt}.${normalizedFrac}` : mergedInt;
|
|
10416
|
+
const normalized = sign === "-" && merged !== "0" ? `-${merged}` : merged;
|
|
10417
|
+
return normalized;
|
|
10418
|
+
}
|
|
10419
|
+
}
|
|
10420
|
+
return raw;
|
|
10283
10421
|
}
|
|
10284
10422
|
static buildIndexClause(indexName, fieldName, action) {
|
|
10285
10423
|
const indexQuoted = SyncTable.quoteIdentifier(indexName);
|
|
@@ -10337,7 +10475,7 @@ class SyncTable {
|
|
|
10337
10475
|
const normalized = normalizeFieldDefinition(fieldDef);
|
|
10338
10476
|
const dbFieldName = snakeCase(fieldKey);
|
|
10339
10477
|
const colQuoted = SyncTable.quoteIdentifier(dbFieldName);
|
|
10340
|
-
const sqlType = SyncTable.getSqlType(normalized.type, normalized.max, normalized.unsigned);
|
|
10478
|
+
const sqlType = SyncTable.getSqlType(normalized.type, normalized.max, normalized.unsigned, normalized.precision, normalized.scale);
|
|
10341
10479
|
const actualDefault = SyncTable.resolveDefaultValue(normalized.default, normalized.type);
|
|
10342
10480
|
const defaultSql = SyncTable.generateDefaultSql(actualDefault, normalized.type);
|
|
10343
10481
|
const uniqueSql = normalized.unique ? " UNIQUE" : "";
|
|
@@ -10381,6 +10519,10 @@ class SyncTable {
|
|
|
10381
10519
|
addedSystem,
|
|
10382
10520
|
modified,
|
|
10383
10521
|
indexChanges: indexActions.length
|
|
10522
|
+
},
|
|
10523
|
+
details: {
|
|
10524
|
+
fieldChanges: fieldPlan.changeDetails,
|
|
10525
|
+
indexChanges: indexPlan.indexActions
|
|
10384
10526
|
}
|
|
10385
10527
|
};
|
|
10386
10528
|
}
|
|
@@ -10388,12 +10530,14 @@ class SyncTable {
|
|
|
10388
10530
|
const alterClauses = [];
|
|
10389
10531
|
let addedBusiness = 0;
|
|
10390
10532
|
let modified = 0;
|
|
10533
|
+
const changeDetails = [];
|
|
10391
10534
|
for (const [fieldKey, fieldDef] of Object.entries(options.fields)) {
|
|
10392
10535
|
const dbFieldName = snakeCase(fieldKey);
|
|
10393
10536
|
if (options.existingColumns[dbFieldName]) {
|
|
10394
10537
|
const comparison = SyncTable.compareFieldDefinition(options.existingColumns[dbFieldName], fieldDef);
|
|
10395
10538
|
if (comparison.length > 0) {
|
|
10396
10539
|
modified = modified + 1;
|
|
10540
|
+
changeDetails.push({ fieldKey, dbFieldName, changes: comparison });
|
|
10397
10541
|
SyncTable.assertCompatibleTypeChange(options.tableName, dbFieldName, comparison, fieldDef);
|
|
10398
10542
|
alterClauses.push(SyncTable.generateDDLClause(fieldKey, fieldDef, false));
|
|
10399
10543
|
}
|
|
@@ -10402,7 +10546,7 @@ class SyncTable {
|
|
|
10402
10546
|
alterClauses.push(SyncTable.generateDDLClause(fieldKey, fieldDef, true));
|
|
10403
10547
|
}
|
|
10404
10548
|
}
|
|
10405
|
-
return { alterClauses, addedBusiness, modified };
|
|
10549
|
+
return { alterClauses, addedBusiness, modified, changeDetails };
|
|
10406
10550
|
}
|
|
10407
10551
|
static buildSystemFieldPlan(options) {
|
|
10408
10552
|
const alterClauses = [];
|
|
@@ -10443,7 +10587,7 @@ class SyncTable {
|
|
|
10443
10587
|
if (!typeChange)
|
|
10444
10588
|
return;
|
|
10445
10589
|
const currentType = String(typeChange.current || "").toLowerCase();
|
|
10446
|
-
const expectedType = SyncTable.getSqlType(fieldDef.type, fieldDef.max ?? null, fieldDef.unsigned ?? false).toLowerCase();
|
|
10590
|
+
const expectedType = SyncTable.getSqlType(fieldDef.type, fieldDef.max ?? null, fieldDef.unsigned ?? false, fieldDef.precision ?? null, fieldDef.scale ?? null).toLowerCase();
|
|
10447
10591
|
const currentBase = currentType.replace(/\s*unsigned/gi, "").replace(/\([^)]*\)/g, "").trim();
|
|
10448
10592
|
const expectedBase = expectedType.replace(/\s*unsigned/gi, "").replace(/\([^)]*\)/g, "").trim();
|
|
10449
10593
|
if (currentBase !== expectedBase && !SyncTable.isCompatibleTypeChange(currentType, expectedType))
|
|
@@ -10554,6 +10698,8 @@ SQL: ${sqlLine}
|
|
|
10554
10698
|
if (nIntIdx > cIntIdx)
|
|
10555
10699
|
return true;
|
|
10556
10700
|
}
|
|
10701
|
+
if (cBase === "float" && nBase === "double")
|
|
10702
|
+
return true;
|
|
10557
10703
|
if (cBase === "varchar" && (nBase === "text" || nBase === "mediumtext" || nBase === "longtext"))
|
|
10558
10704
|
return true;
|
|
10559
10705
|
if (cBase === "char" && nBase === "varchar" || cBase === "varchar" && nBase === "char") {
|
|
@@ -10567,12 +10713,14 @@ SQL: ${sqlLine}
|
|
|
10567
10713
|
static compareFieldDefinition(existingColumn, fieldDef) {
|
|
10568
10714
|
const changes = [];
|
|
10569
10715
|
const normalized = normalizeFieldDefinition(fieldDef);
|
|
10570
|
-
const expectedType = SyncTable.getSqlType(normalized.type, normalized.max, normalized.unsigned).toLowerCase().replace(/\s+/g, " ").trim();
|
|
10716
|
+
const expectedType = SyncTable.getSqlType(normalized.type, normalized.max, normalized.unsigned, normalized.precision, normalized.scale).toLowerCase().replace(/\s+/g, " ").trim();
|
|
10571
10717
|
const currentType = (typeof existingColumn.columnType === "string" && existingColumn.columnType.trim() !== "" ? existingColumn.columnType : typeof existingColumn.type === "string" && existingColumn.type.trim() !== "" ? SyncTable.isStringOrArrayType(normalized.type) && typeof existingColumn.max === "number" ? `${existingColumn.type.trim()}(${existingColumn.max})` : existingColumn.type.trim() : String(existingColumn.type ?? "")).toLowerCase().replace(/\s+/g, " ").trim();
|
|
10572
|
-
|
|
10718
|
+
const currentBase = currentType.replace(/\s*unsigned/gi, "").replace(/\([^)]*\)/g, "").trim();
|
|
10719
|
+
const normalizedCurrentType = SyncTable.INT_TYPES.has(currentBase) ? currentType.replace(/\([^)]*\)/g, "").replace(/\s+/g, " ").trim() : currentType;
|
|
10720
|
+
if (normalizedCurrentType !== expectedType) {
|
|
10573
10721
|
changes.push({
|
|
10574
10722
|
type: "datatype",
|
|
10575
|
-
current:
|
|
10723
|
+
current: normalizedCurrentType,
|
|
10576
10724
|
expected: expectedType
|
|
10577
10725
|
});
|
|
10578
10726
|
}
|
|
@@ -10584,12 +10732,26 @@ SQL: ${sqlLine}
|
|
|
10584
10732
|
expected: expectedNullable
|
|
10585
10733
|
});
|
|
10586
10734
|
}
|
|
10587
|
-
const
|
|
10588
|
-
if (SyncTable.
|
|
10735
|
+
const normalizedType = String(normalized.type || "").toLowerCase();
|
|
10736
|
+
if (!SyncTable.TEXT_FAMILY.has(normalizedType) && normalizedType !== "json") {
|
|
10737
|
+
const expectedDefault = SyncTable.resolveDefaultValue(normalized.default, normalized.type);
|
|
10738
|
+
const currentDefaultNormalized = SyncTable.normalizeDefaultForCompare(existingColumn.defaultValue, normalized.type);
|
|
10739
|
+
const expectedDefaultNormalized = SyncTable.normalizeDefaultForCompare(expectedDefault, normalized.type);
|
|
10740
|
+
if (currentDefaultNormalized !== expectedDefaultNormalized) {
|
|
10741
|
+
changes.push({
|
|
10742
|
+
type: "default",
|
|
10743
|
+
current: existingColumn.defaultValue,
|
|
10744
|
+
expected: expectedDefault
|
|
10745
|
+
});
|
|
10746
|
+
}
|
|
10747
|
+
}
|
|
10748
|
+
const currentComment = String(existingColumn.comment ?? "");
|
|
10749
|
+
const expectedComment = String(normalized.name ?? "");
|
|
10750
|
+
if (currentComment !== expectedComment) {
|
|
10589
10751
|
changes.push({
|
|
10590
|
-
type: "
|
|
10591
|
-
current:
|
|
10592
|
-
expected:
|
|
10752
|
+
type: "comment",
|
|
10753
|
+
current: currentComment,
|
|
10754
|
+
expected: expectedComment
|
|
10593
10755
|
});
|
|
10594
10756
|
}
|
|
10595
10757
|
return changes;
|
|
@@ -10703,7 +10865,7 @@ SQL: ${sqlLine}
|
|
|
10703
10865
|
static async modifyTable(db, dbName, tableName, fields) {
|
|
10704
10866
|
const existingColumns = await SyncTable.getTableColumns(db, dbName, tableName);
|
|
10705
10867
|
const existingIndexes = await SyncTable.getTableIndexes(db, dbName, tableName);
|
|
10706
|
-
const { plan, summary } = SyncTable.buildTablePlan({
|
|
10868
|
+
const { plan, summary, details } = SyncTable.buildTablePlan({
|
|
10707
10869
|
tableName,
|
|
10708
10870
|
fields,
|
|
10709
10871
|
existingColumns,
|
|
@@ -10711,7 +10873,23 @@ SQL: ${sqlLine}
|
|
|
10711
10873
|
});
|
|
10712
10874
|
if (plan.changed) {
|
|
10713
10875
|
const msg = `[\u8868 ${tableName}] \u53D8\u66F4\u6C47\u603B\uFF0C\u65B0\u589E\u5B57\u6BB5=${summary.addedBusiness}\uFF0C\u65B0\u589E\u7CFB\u7EDF\u5B57\u6BB5=${summary.addedSystem}\uFF0C\u4FEE\u6539\u5B57\u6BB5=${summary.modified}\uFF0C\u7D22\u5F15\u53D8\u66F4=${summary.indexChanges}`;
|
|
10876
|
+
const detailLines = details.fieldChanges.flatMap((item) => item.changes.map((change) => {
|
|
10877
|
+
const current = String(change.current ?? "");
|
|
10878
|
+
const expected = String(change.expected ?? "");
|
|
10879
|
+
return `- ${item.dbFieldName}.${change.type}: ${current} -> ${expected}`;
|
|
10880
|
+
}));
|
|
10881
|
+
const indexLines = details.indexChanges.map((change) => {
|
|
10882
|
+
const indexLabel = `idx_${change.fieldName}` === change.indexName ? change.indexName : change.indexName;
|
|
10883
|
+
if (change.action === "create") {
|
|
10884
|
+
return `- index.${indexLabel}: \u65E0 -> ${change.indexName}(${change.fieldName})`;
|
|
10885
|
+
}
|
|
10886
|
+
return `- index.${indexLabel}: ${change.indexName}(${change.fieldName}) -> \u65E0`;
|
|
10887
|
+
});
|
|
10888
|
+
const allLines = [...detailLines, ...indexLines];
|
|
10714
10889
|
Logger.debug(msg);
|
|
10890
|
+
for (const line of allLines) {
|
|
10891
|
+
Logger.debug(`[\u8868 ${tableName}] \u53D8\u66F4\u660E\u7EC6 ${line}`);
|
|
10892
|
+
}
|
|
10715
10893
|
await SyncTable.applyTablePlan(db, tableName, plan);
|
|
10716
10894
|
}
|
|
10717
10895
|
return plan;
|
|
@@ -12473,12 +12651,28 @@ function getRegex(name) {
|
|
|
12473
12651
|
}
|
|
12474
12652
|
return name;
|
|
12475
12653
|
}
|
|
12654
|
+
function parseRegexLiteral(pattern) {
|
|
12655
|
+
const trimmed = String(pattern || "").trim();
|
|
12656
|
+
if (trimmed.length < 2)
|
|
12657
|
+
return null;
|
|
12658
|
+
if (!trimmed.startsWith("/"))
|
|
12659
|
+
return null;
|
|
12660
|
+
const lastSlash = trimmed.lastIndexOf("/");
|
|
12661
|
+
if (lastSlash <= 0)
|
|
12662
|
+
return null;
|
|
12663
|
+
const flags = trimmed.slice(lastSlash + 1);
|
|
12664
|
+
if (flags !== "" && !/^[gimsuy]+$/.test(flags))
|
|
12665
|
+
return null;
|
|
12666
|
+
return { source: trimmed.slice(1, lastSlash), flags };
|
|
12667
|
+
}
|
|
12476
12668
|
function getCompiledRegex(pattern, flags) {
|
|
12477
|
-
const
|
|
12478
|
-
const
|
|
12669
|
+
const literal = parseRegexLiteral(pattern);
|
|
12670
|
+
const regexStr = literal ? literal.source : getRegex(pattern);
|
|
12671
|
+
const useFlags = literal && literal.flags !== "" ? literal.flags : flags || "";
|
|
12672
|
+
const cacheKey = `${regexStr}:${useFlags}`;
|
|
12479
12673
|
let cached = regexCache.get(cacheKey);
|
|
12480
12674
|
if (!cached) {
|
|
12481
|
-
cached = new RegExp(regexStr,
|
|
12675
|
+
cached = new RegExp(regexStr, useFlags);
|
|
12482
12676
|
regexCache.set(cacheKey, cached);
|
|
12483
12677
|
}
|
|
12484
12678
|
return cached;
|
|
@@ -12487,39 +12681,8 @@ function getCompiledRegex(pattern, flags) {
|
|
|
12487
12681
|
// lib/validator.ts
|
|
12488
12682
|
init_util();
|
|
12489
12683
|
var INPUT_TYPE_SET2 = new Set(["number", "integer", "string", "char", "array", "array_number", "array_integer", "json", "json_number", "json_integer"]);
|
|
12490
|
-
function isRegexInput2(input) {
|
|
12491
|
-
if (input.startsWith("@"))
|
|
12492
|
-
return true;
|
|
12493
|
-
return /[\\^$.*+?()[\]{}]/.test(input);
|
|
12494
|
-
}
|
|
12495
|
-
function isEnumInput2(input) {
|
|
12496
|
-
return input.includes("|") && !isRegexInput2(input);
|
|
12497
|
-
}
|
|
12498
|
-
function isJsonPrimitive3(value) {
|
|
12499
|
-
if (value === null)
|
|
12500
|
-
return true;
|
|
12501
|
-
return typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
12502
|
-
}
|
|
12503
|
-
function isJsonObject3(value) {
|
|
12504
|
-
if (!value || typeof value !== "object")
|
|
12505
|
-
return false;
|
|
12506
|
-
if (value instanceof Date)
|
|
12507
|
-
return false;
|
|
12508
|
-
if (Array.isArray(value))
|
|
12509
|
-
return false;
|
|
12510
|
-
return true;
|
|
12511
|
-
}
|
|
12512
|
-
function isJsonStructure(value) {
|
|
12513
|
-
return Array.isArray(value) || isJsonObject3(value);
|
|
12514
|
-
}
|
|
12515
|
-
function isFiniteNumber(value) {
|
|
12516
|
-
return typeof value === "number" && Number.isFinite(value);
|
|
12517
|
-
}
|
|
12518
|
-
function isIntegerNumber(value) {
|
|
12519
|
-
return typeof value === "number" && Number.isFinite(value) && Number.isInteger(value);
|
|
12520
|
-
}
|
|
12521
12684
|
function checkJsonLeaves(value, rule) {
|
|
12522
|
-
if (
|
|
12685
|
+
if (isJsonPrimitive(value)) {
|
|
12523
12686
|
if (rule === "number")
|
|
12524
12687
|
return isFiniteNumber(value);
|
|
12525
12688
|
return isIntegerNumber(value);
|
|
@@ -12531,7 +12694,7 @@ function checkJsonLeaves(value, rule) {
|
|
|
12531
12694
|
}
|
|
12532
12695
|
return true;
|
|
12533
12696
|
}
|
|
12534
|
-
if (
|
|
12697
|
+
if (isJsonObject(value)) {
|
|
12535
12698
|
for (const v of Object.values(value)) {
|
|
12536
12699
|
if (v === undefined)
|
|
12537
12700
|
continue;
|
|
@@ -12657,14 +12820,15 @@ class Validator {
|
|
|
12657
12820
|
return error ? `${label}${error}` : null;
|
|
12658
12821
|
}
|
|
12659
12822
|
static convert(value, input, dbType) {
|
|
12660
|
-
const
|
|
12661
|
-
|
|
12823
|
+
const inputRaw = String(input || "").trim();
|
|
12824
|
+
const inputKey = inputRaw.toLowerCase();
|
|
12825
|
+
if (!INPUT_TYPE_SET2.has(inputKey) && isRegexInput(inputRaw)) {
|
|
12662
12826
|
return typeof value === "string" ? { value, error: null } : { value: null, error: "\u5FC5\u987B\u662F\u5B57\u7B26\u4E32" };
|
|
12663
12827
|
}
|
|
12664
|
-
if (!INPUT_TYPE_SET2.has(
|
|
12828
|
+
if (!INPUT_TYPE_SET2.has(inputKey) && isEnumInput(inputRaw)) {
|
|
12665
12829
|
return typeof value === "string" ? { value, error: null } : { value: null, error: "\u5FC5\u987B\u662F\u5B57\u7B26\u4E32" };
|
|
12666
12830
|
}
|
|
12667
|
-
switch (
|
|
12831
|
+
switch (inputKey) {
|
|
12668
12832
|
case "number": {
|
|
12669
12833
|
if (isFiniteNumber(value))
|
|
12670
12834
|
return { value, error: null };
|
|
@@ -12749,43 +12913,44 @@ class Validator {
|
|
|
12749
12913
|
const input = normalized.input;
|
|
12750
12914
|
const min = normalized.min;
|
|
12751
12915
|
const max = normalized.max;
|
|
12752
|
-
const
|
|
12753
|
-
const
|
|
12754
|
-
const
|
|
12755
|
-
|
|
12916
|
+
const inputRaw = String(input || "").trim();
|
|
12917
|
+
const inputKey = inputRaw.toLowerCase();
|
|
12918
|
+
const isRegex = !INPUT_TYPE_SET2.has(inputKey) && isRegexInput(inputRaw);
|
|
12919
|
+
const isEnum = !INPUT_TYPE_SET2.has(inputKey) && isEnumInput(inputRaw);
|
|
12920
|
+
if (inputKey === "number" || inputKey === "integer") {
|
|
12756
12921
|
if (typeof value !== "number")
|
|
12757
|
-
return
|
|
12922
|
+
return inputKey === "integer" ? "\u5FC5\u987B\u662F\u6574\u6570" : "\u5FC5\u987B\u662F\u6570\u5B57";
|
|
12758
12923
|
if (min !== null && value < min)
|
|
12759
12924
|
return `\u4E0D\u80FD\u5C0F\u4E8E${min}`;
|
|
12760
12925
|
if (max !== null && max > 0 && value > max)
|
|
12761
12926
|
return `\u4E0D\u80FD\u5927\u4E8E${max}`;
|
|
12762
|
-
} else if (
|
|
12927
|
+
} else if (inputKey === "string" || inputKey === "char" || isRegex || isEnum) {
|
|
12763
12928
|
if (typeof value !== "string")
|
|
12764
12929
|
return "\u5FC5\u987B\u662F\u5B57\u7B26\u4E32";
|
|
12765
|
-
if (
|
|
12930
|
+
if (inputKey === "char" && value.length !== 1)
|
|
12766
12931
|
return "\u5FC5\u987B\u662F\u5355\u5B57\u7B26";
|
|
12767
12932
|
if (min !== null && value.length < min)
|
|
12768
12933
|
return `\u957F\u5EA6\u4E0D\u80FD\u5C11\u4E8E${min}\u4E2A\u5B57\u7B26`;
|
|
12769
12934
|
if (max !== null && max > 0 && value.length > max)
|
|
12770
12935
|
return `\u957F\u5EA6\u4E0D\u80FD\u8D85\u8FC7${max}\u4E2A\u5B57\u7B26`;
|
|
12771
12936
|
if (isRegex) {
|
|
12772
|
-
const regex = this.resolveRegex(
|
|
12937
|
+
const regex = this.resolveRegex(inputRaw);
|
|
12773
12938
|
if (!this.testRegex(regex, value))
|
|
12774
12939
|
return "\u683C\u5F0F\u4E0D\u6B63\u786E";
|
|
12775
12940
|
}
|
|
12776
12941
|
if (isEnum) {
|
|
12777
|
-
const enums =
|
|
12942
|
+
const enums = inputRaw.split("|").map((item) => item.trim()).filter((item) => item !== "");
|
|
12778
12943
|
if (!enums.includes(value))
|
|
12779
12944
|
return "\u503C\u4E0D\u5728\u679A\u4E3E\u8303\u56F4\u5185";
|
|
12780
12945
|
}
|
|
12781
|
-
} else if (
|
|
12946
|
+
} else if (inputKey === "array" || inputKey === "array_number" || inputKey === "array_integer") {
|
|
12782
12947
|
if (!Array.isArray(value))
|
|
12783
12948
|
return "\u5FC5\u987B\u662F\u6570\u7EC4";
|
|
12784
12949
|
if (min !== null && value.length < min)
|
|
12785
12950
|
return `\u81F3\u5C11\u9700\u8981${min}\u4E2A\u5143\u7D20`;
|
|
12786
12951
|
if (max !== null && max > 0 && value.length > max)
|
|
12787
12952
|
return `\u6700\u591A\u53EA\u80FD\u6709${max}\u4E2A\u5143\u7D20`;
|
|
12788
|
-
} else if (
|
|
12953
|
+
} else if (inputKey === "json" || inputKey === "json_number" || inputKey === "json_integer") {
|
|
12789
12954
|
if (!isJsonStructure(value))
|
|
12790
12955
|
return "\u5FC5\u987B\u662FJSON\u5BF9\u8C61\u6216\u6570\u7EC4";
|
|
12791
12956
|
}
|