@famgia/omnify-core 0.0.136 → 0.0.137

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/index.cjs CHANGED
@@ -1217,10 +1217,89 @@ var BASE_PROPERTY_FIELDS = [
1217
1217
  // Per-field settings for compound types
1218
1218
  ];
1219
1219
  var VALID_RULES_FIELDS = [
1220
+ // Basic
1220
1221
  "required",
1222
+ // String length
1221
1223
  "minLength",
1222
- "maxLength"
1224
+ "maxLength",
1225
+ // Format (String only)
1226
+ "url",
1227
+ "uuid",
1228
+ "ip",
1229
+ "ipv4",
1230
+ "ipv6",
1231
+ // Character pattern (String only)
1232
+ "alpha",
1233
+ "alphaNum",
1234
+ "alphaDash",
1235
+ "numeric",
1236
+ "digits",
1237
+ "digitsBetween",
1238
+ // String matching (String only)
1239
+ "startsWith",
1240
+ "endsWith",
1241
+ "lowercase",
1242
+ "uppercase",
1243
+ // Numeric (Int/Float only)
1244
+ "min",
1245
+ "max",
1246
+ "between",
1247
+ "gt",
1248
+ "lt",
1249
+ "multipleOf",
1250
+ // Array
1251
+ "arrayMin",
1252
+ "arrayMax"
1223
1253
  ];
1254
+ var RULES_TYPE_GROUPS = {
1255
+ string: ["String", "Text", "MediumText", "LongText", "Password", "Email"],
1256
+ numeric: ["TinyInt", "Int", "BigInt", "Float", "Decimal"],
1257
+ date: ["Date", "DateTime", "Time", "Timestamp"],
1258
+ any: []
1259
+ // 全タイプに適用可能
1260
+ };
1261
+ var RULES_TYPE_COMPATIBILITY = {
1262
+ // Basic - any type
1263
+ required: "any",
1264
+ // String length rules
1265
+ minLength: "string",
1266
+ maxLength: "string",
1267
+ // Format rules (String only)
1268
+ url: "string",
1269
+ uuid: "string",
1270
+ ip: "string",
1271
+ ipv4: "string",
1272
+ ipv6: "string",
1273
+ // Character pattern rules (String only)
1274
+ alpha: "string",
1275
+ alphaNum: "string",
1276
+ alphaDash: "string",
1277
+ numeric: "string",
1278
+ digits: "string",
1279
+ digitsBetween: "string",
1280
+ // String matching rules (String only)
1281
+ startsWith: "string",
1282
+ endsWith: "string",
1283
+ lowercase: "string",
1284
+ uppercase: "string",
1285
+ // Numeric rules (Int/Float only)
1286
+ min: "numeric",
1287
+ max: "numeric",
1288
+ between: "numeric",
1289
+ gt: "numeric",
1290
+ lt: "numeric",
1291
+ multipleOf: "numeric",
1292
+ // Array rules - handled separately
1293
+ arrayMin: "any",
1294
+ arrayMax: "any"
1295
+ };
1296
+ function isRuleCompatibleWithType(rule, propertyType) {
1297
+ const category = RULES_TYPE_COMPATIBILITY[rule];
1298
+ if (!category) return false;
1299
+ if (category === "any") return true;
1300
+ const allowedTypes = RULES_TYPE_GROUPS[category];
1301
+ return allowedTypes.includes(propertyType);
1302
+ }
1224
1303
  function createValidFields(additionalFields) {
1225
1304
  return [...BASE_PROPERTY_FIELDS, ...additionalFields];
1226
1305
  }
@@ -2693,13 +2772,13 @@ Example:
2693
2772
  }
2694
2773
  return `Unknown field '${field}'. Valid property fields: type, displayName, placeholder, nullable, default, unique, primary, description, length, unsigned, precision, scale, enum, relation, target, onDelete, onUpdate, joinTable, rules, hidden, fillable, fields`;
2695
2774
  }
2696
- var STRING_TYPES_WITH_LENGTH_RULES = ["String", "Email", "Password"];
2697
2775
  function validateRules(propertyName, property, filePath) {
2698
2776
  const errors = [];
2699
2777
  const rules = property.rules;
2700
2778
  if (!rules || typeof rules !== "object") {
2701
2779
  return errors;
2702
2780
  }
2781
+ const propertyType = property.type;
2703
2782
  const validRulesSet = new Set(VALID_RULES_FIELDS);
2704
2783
  for (const field of Object.keys(rules)) {
2705
2784
  if (!validRulesSet.has(field)) {
@@ -2712,77 +2791,260 @@ function validateRules(propertyName, property, filePath) {
2712
2791
  );
2713
2792
  }
2714
2793
  }
2715
- const { required, minLength, maxLength } = rules;
2716
- if (required !== void 0 && typeof required !== "boolean") {
2794
+ for (const [ruleName, ruleValue] of Object.entries(rules)) {
2795
+ if (ruleValue === void 0 || ruleValue === null) continue;
2796
+ if (!validRulesSet.has(ruleName)) continue;
2797
+ if (!isRuleCompatibleWithType(ruleName, propertyType)) {
2798
+ const stringTypes = RULES_TYPE_GROUPS.string.join(", ");
2799
+ const numericTypes2 = RULES_TYPE_GROUPS.numeric.join(", ");
2800
+ let allowedTypes = "";
2801
+ if ([
2802
+ "minLength",
2803
+ "maxLength",
2804
+ "url",
2805
+ "uuid",
2806
+ "ip",
2807
+ "ipv4",
2808
+ "ipv6",
2809
+ "alpha",
2810
+ "alphaNum",
2811
+ "alphaDash",
2812
+ "numeric",
2813
+ "digits",
2814
+ "digitsBetween",
2815
+ "startsWith",
2816
+ "endsWith",
2817
+ "lowercase",
2818
+ "uppercase"
2819
+ ].includes(ruleName)) {
2820
+ allowedTypes = stringTypes;
2821
+ } else if (["min", "max", "between", "gt", "lt", "multipleOf"].includes(ruleName)) {
2822
+ allowedTypes = numericTypes2;
2823
+ }
2824
+ if (allowedTypes) {
2825
+ errors.push(
2826
+ validationError(
2827
+ `Property '${propertyName}' of type '${propertyType}' cannot use rules.${ruleName}`,
2828
+ buildLocation7(filePath),
2829
+ `rules.${ruleName} is only valid for types: ${allowedTypes}`
2830
+ )
2831
+ );
2832
+ }
2833
+ }
2834
+ }
2835
+ const {
2836
+ required,
2837
+ minLength,
2838
+ maxLength,
2839
+ url,
2840
+ uuid,
2841
+ ip,
2842
+ ipv4,
2843
+ ipv6,
2844
+ alpha,
2845
+ alphaNum,
2846
+ alphaDash,
2847
+ numeric,
2848
+ lowercase,
2849
+ uppercase,
2850
+ digits,
2851
+ digitsBetween,
2852
+ startsWith,
2853
+ endsWith,
2854
+ min,
2855
+ max,
2856
+ between,
2857
+ gt,
2858
+ lt,
2859
+ multipleOf,
2860
+ arrayMin,
2861
+ arrayMax
2862
+ } = rules;
2863
+ const booleanRules = { required, url, uuid, ip, ipv4, ipv6, alpha, alphaNum, alphaDash, numeric, lowercase, uppercase };
2864
+ for (const [name, value] of Object.entries(booleanRules)) {
2865
+ if (value !== void 0 && typeof value !== "boolean") {
2866
+ errors.push(
2867
+ validationError(
2868
+ `Property '${propertyName}' has invalid rules.${name} value`,
2869
+ buildLocation7(filePath),
2870
+ `rules.${name} must be a boolean (true or false)`
2871
+ )
2872
+ );
2873
+ }
2874
+ }
2875
+ if (minLength !== void 0 && isRuleCompatibleWithType("minLength", propertyType)) {
2876
+ if (typeof minLength !== "number" || minLength < 0 || !Number.isInteger(minLength)) {
2877
+ errors.push(
2878
+ validationError(
2879
+ `Property '${propertyName}' has invalid rules.minLength '${minLength}'`,
2880
+ buildLocation7(filePath),
2881
+ "rules.minLength must be a non-negative integer"
2882
+ )
2883
+ );
2884
+ }
2885
+ }
2886
+ if (maxLength !== void 0 && isRuleCompatibleWithType("maxLength", propertyType)) {
2887
+ if (typeof maxLength !== "number" || maxLength < 1 || !Number.isInteger(maxLength)) {
2888
+ errors.push(
2889
+ validationError(
2890
+ `Property '${propertyName}' has invalid rules.maxLength '${maxLength}'`,
2891
+ buildLocation7(filePath),
2892
+ "rules.maxLength must be a positive integer"
2893
+ )
2894
+ );
2895
+ } else {
2896
+ const dbLength = property.length;
2897
+ if (dbLength !== void 0 && typeof dbLength === "number" && maxLength > dbLength) {
2898
+ errors.push(
2899
+ validationError(
2900
+ `Property '${propertyName}' has rules.maxLength (${maxLength}) greater than length (${dbLength})`,
2901
+ buildLocation7(filePath),
2902
+ "rules.maxLength must be <= length (database column size)"
2903
+ )
2904
+ );
2905
+ }
2906
+ }
2907
+ }
2908
+ if (typeof minLength === "number" && typeof maxLength === "number" && minLength > maxLength) {
2717
2909
  errors.push(
2718
2910
  validationError(
2719
- `Property '${propertyName}' has invalid rules.required value`,
2911
+ `Property '${propertyName}' has rules.minLength (${minLength}) > rules.maxLength (${maxLength})`,
2720
2912
  buildLocation7(filePath),
2721
- "rules.required must be a boolean (true or false)"
2913
+ "rules.minLength must be <= rules.maxLength"
2722
2914
  )
2723
2915
  );
2724
2916
  }
2725
- const propertyType = property.type;
2726
- const allowsLengthRules = STRING_TYPES_WITH_LENGTH_RULES.includes(
2727
- propertyType
2728
- );
2729
- if (minLength !== void 0 && !allowsLengthRules) {
2917
+ if (digits !== void 0) {
2918
+ if (typeof digits !== "number" || digits < 1 || !Number.isInteger(digits)) {
2919
+ errors.push(
2920
+ validationError(
2921
+ `Property '${propertyName}' has invalid rules.digits '${digits}'`,
2922
+ buildLocation7(filePath),
2923
+ "rules.digits must be a positive integer"
2924
+ )
2925
+ );
2926
+ }
2927
+ }
2928
+ if (digitsBetween !== void 0) {
2929
+ if (!Array.isArray(digitsBetween) || digitsBetween.length !== 2 || typeof digitsBetween[0] !== "number" || typeof digitsBetween[1] !== "number") {
2930
+ errors.push(
2931
+ validationError(
2932
+ `Property '${propertyName}' has invalid rules.digitsBetween`,
2933
+ buildLocation7(filePath),
2934
+ "rules.digitsBetween must be [min, max] tuple of numbers"
2935
+ )
2936
+ );
2937
+ } else if (digitsBetween[0] > digitsBetween[1]) {
2938
+ errors.push(
2939
+ validationError(
2940
+ `Property '${propertyName}' has rules.digitsBetween[0] (${digitsBetween[0]}) > [1] (${digitsBetween[1]})`,
2941
+ buildLocation7(filePath),
2942
+ "First value must be <= second value"
2943
+ )
2944
+ );
2945
+ }
2946
+ }
2947
+ if (startsWith !== void 0) {
2948
+ if (typeof startsWith !== "string" && (!Array.isArray(startsWith) || !startsWith.every((s) => typeof s === "string"))) {
2949
+ errors.push(
2950
+ validationError(
2951
+ `Property '${propertyName}' has invalid rules.startsWith`,
2952
+ buildLocation7(filePath),
2953
+ "rules.startsWith must be a string or array of strings"
2954
+ )
2955
+ );
2956
+ }
2957
+ }
2958
+ if (endsWith !== void 0) {
2959
+ if (typeof endsWith !== "string" && (!Array.isArray(endsWith) || !endsWith.every((s) => typeof s === "string"))) {
2960
+ errors.push(
2961
+ validationError(
2962
+ `Property '${propertyName}' has invalid rules.endsWith`,
2963
+ buildLocation7(filePath),
2964
+ "rules.endsWith must be a string or array of strings"
2965
+ )
2966
+ );
2967
+ }
2968
+ }
2969
+ const numericSingleRules = { min, max, gt, lt, multipleOf };
2970
+ for (const [name, value] of Object.entries(numericSingleRules)) {
2971
+ if (value !== void 0 && isRuleCompatibleWithType(name, propertyType)) {
2972
+ if (typeof value !== "number") {
2973
+ errors.push(
2974
+ validationError(
2975
+ `Property '${propertyName}' has invalid rules.${name} '${value}'`,
2976
+ buildLocation7(filePath),
2977
+ `rules.${name} must be a number`
2978
+ )
2979
+ );
2980
+ }
2981
+ }
2982
+ }
2983
+ if (between !== void 0 && isRuleCompatibleWithType("between", propertyType)) {
2984
+ if (!Array.isArray(between) || between.length !== 2 || typeof between[0] !== "number" || typeof between[1] !== "number") {
2985
+ errors.push(
2986
+ validationError(
2987
+ `Property '${propertyName}' has invalid rules.between`,
2988
+ buildLocation7(filePath),
2989
+ "rules.between must be [min, max] tuple of numbers"
2990
+ )
2991
+ );
2992
+ } else if (between[0] > between[1]) {
2993
+ errors.push(
2994
+ validationError(
2995
+ `Property '${propertyName}' has rules.between[0] (${between[0]}) > [1] (${between[1]})`,
2996
+ buildLocation7(filePath),
2997
+ "First value must be <= second value"
2998
+ )
2999
+ );
3000
+ }
3001
+ }
3002
+ if (typeof min === "number" && typeof max === "number" && min > max) {
2730
3003
  errors.push(
2731
3004
  validationError(
2732
- `Property '${propertyName}' of type '${propertyType}' cannot use rules.minLength`,
3005
+ `Property '${propertyName}' has rules.min (${min}) > rules.max (${max})`,
2733
3006
  buildLocation7(filePath),
2734
- `rules.minLength is only valid for types: ${STRING_TYPES_WITH_LENGTH_RULES.join(", ")}`
3007
+ "rules.min must be <= rules.max"
2735
3008
  )
2736
3009
  );
2737
3010
  }
2738
- if (maxLength !== void 0 && !allowsLengthRules) {
3011
+ if (typeof multipleOf === "number" && multipleOf <= 0) {
2739
3012
  errors.push(
2740
3013
  validationError(
2741
- `Property '${propertyName}' of type '${propertyType}' cannot use rules.maxLength`,
3014
+ `Property '${propertyName}' has invalid rules.multipleOf '${multipleOf}'`,
2742
3015
  buildLocation7(filePath),
2743
- `rules.maxLength is only valid for types: ${STRING_TYPES_WITH_LENGTH_RULES.join(", ")}`
3016
+ "rules.multipleOf must be a positive number"
2744
3017
  )
2745
3018
  );
2746
3019
  }
2747
- if (minLength !== void 0 && allowsLengthRules) {
2748
- if (typeof minLength !== "number" || minLength < 0 || minLength > 65535) {
3020
+ if (arrayMin !== void 0) {
3021
+ if (typeof arrayMin !== "number" || arrayMin < 0 || !Number.isInteger(arrayMin)) {
2749
3022
  errors.push(
2750
3023
  validationError(
2751
- `Property '${propertyName}' has invalid rules.minLength '${minLength}'`,
3024
+ `Property '${propertyName}' has invalid rules.arrayMin '${arrayMin}'`,
2752
3025
  buildLocation7(filePath),
2753
- "rules.minLength must be a non-negative number between 0 and 65535"
3026
+ "rules.arrayMin must be a non-negative integer"
2754
3027
  )
2755
3028
  );
2756
3029
  }
2757
3030
  }
2758
- if (maxLength !== void 0 && allowsLengthRules) {
2759
- if (typeof maxLength !== "number" || maxLength < 1 || maxLength > 65535) {
3031
+ if (arrayMax !== void 0) {
3032
+ if (typeof arrayMax !== "number" || arrayMax < 1 || !Number.isInteger(arrayMax)) {
2760
3033
  errors.push(
2761
3034
  validationError(
2762
- `Property '${propertyName}' has invalid rules.maxLength '${maxLength}'`,
3035
+ `Property '${propertyName}' has invalid rules.arrayMax '${arrayMax}'`,
2763
3036
  buildLocation7(filePath),
2764
- "rules.maxLength must be a positive number between 1 and 65535"
3037
+ "rules.arrayMax must be a positive integer"
2765
3038
  )
2766
3039
  );
2767
- } else {
2768
- const dbLength = property.length;
2769
- if (dbLength !== void 0 && typeof dbLength === "number" && maxLength > dbLength) {
2770
- errors.push(
2771
- validationError(
2772
- `Property '${propertyName}' has rules.maxLength (${maxLength}) greater than length (${dbLength})`,
2773
- buildLocation7(filePath),
2774
- "rules.maxLength must be less than or equal to length (database column size)"
2775
- )
2776
- );
2777
- }
2778
3040
  }
2779
3041
  }
2780
- if (minLength !== void 0 && maxLength !== void 0 && typeof minLength === "number" && typeof maxLength === "number" && minLength > maxLength) {
3042
+ if (typeof arrayMin === "number" && typeof arrayMax === "number" && arrayMin > arrayMax) {
2781
3043
  errors.push(
2782
3044
  validationError(
2783
- `Property '${propertyName}' has rules.minLength (${minLength}) greater than rules.maxLength (${maxLength})`,
3045
+ `Property '${propertyName}' has rules.arrayMin (${arrayMin}) > rules.arrayMax (${arrayMax})`,
2784
3046
  buildLocation7(filePath),
2785
- "rules.minLength must be less than or equal to rules.maxLength"
3047
+ "rules.arrayMin must be <= rules.arrayMax"
2786
3048
  )
2787
3049
  );
2788
3050
  }