@plasius/schema 1.2.17 → 1.2.18

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/README.md CHANGED
@@ -88,6 +88,21 @@ const UserFields = {
88
88
  ```
89
89
 
90
90
  Common methods (non‑exhaustive): `.required()`, `.optional()`, `.default(v|fn)`, `.description(text)`, and type‑specific helpers like `.email()`, `.uuid()`, `.min()`, `.max()`, `.enum([...])`.
91
+
92
+ Validation standards notes:
93
+
94
+ - `languageCode()` checks a documented RFC 5646/BCP 47 subset
95
+ case-insensitively, including grandfathered and private-use tags;
96
+ two-letter primaries are checked against the package's ISO 639-1 registry.
97
+ Registered 4-8 letter primaries remain outside this dependency-free subset.
98
+ - `uuid()` accepts the RFC 9562 versions 1-8, Nil, and Max text forms. Legacy
99
+ RFC 4122-named module paths remain compatibility aliases.
100
+ - `email()` is a pragmatic dot-domain mailbox subset, not a claim of complete
101
+ RFC 5322 grammar support.
102
+
103
+ Runtime rollout inherits `governance.rfc-compliance-remediation.enabled`;
104
+ disabled consumers may retain the prior validators only during a documented
105
+ migration window.
91
106
  Defaults are applied during validation when inputs are missing/`undefined`.
92
107
  Fields are required by default; call `.optional()` (or provide `.default()`) to allow omission.
93
108
  Use `.internal()` or `.exposure("internal")` on fields that the server may validate/store but must not include in client-facing payloads.
package/dist/index.cjs CHANGED
@@ -284,8 +284,8 @@ var validateUrl = (value) => {
284
284
  // src/validation/uuid.RFC4122.ts
285
285
  var validateUUID = (value) => {
286
286
  if (typeof value !== "string") return false;
287
- const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
288
- return uuidRegex.test(value);
287
+ const standard = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
288
+ return standard.test(value) || value.toLowerCase() === "00000000-0000-0000-0000-000000000000" || value.toLowerCase() === "ffffffff-ffff-ffff-ffff-ffffffffffff";
289
289
  };
290
290
 
291
291
  // src/validation/dateTime.ISO8601.ts
@@ -1032,10 +1032,10 @@ function isIsoLanguageCode(value) {
1032
1032
  return typeof value === "string" && ISO_LANGUAGE_SET.has(value.toLowerCase());
1033
1033
  }
1034
1034
  function isRegionSubtag(value) {
1035
- return /^[A-Z]{2}$/.test(value) || /^\d{3}$/.test(value);
1035
+ return /^[A-Za-z]{2}$/.test(value) || /^\d{3}$/.test(value);
1036
1036
  }
1037
1037
  function isScriptSubtag(value) {
1038
- return /^[A-Z][a-z]{3}$/.test(value);
1038
+ return /^[A-Za-z]{4}$/.test(value);
1039
1039
  }
1040
1040
  function isVariantSubtag(value) {
1041
1041
  return /^([0-9][A-Za-z0-9]{3}|[A-Za-z0-9]{5,8})$/.test(value);
@@ -1055,20 +1055,42 @@ function isPrivateUseSubtag(value) {
1055
1055
  function validateLanguage(value) {
1056
1056
  if (typeof value !== "string" || value.length === 0) return false;
1057
1057
  const parts = value.split("-");
1058
+ if (parts.some((part) => part.length === 0)) return false;
1059
+ const lowerTag = value.toLowerCase();
1060
+ if (GRANDFATHERED_TAGS.has(lowerTag)) return true;
1061
+ if (parts[0]?.toLowerCase() === "x") {
1062
+ return parts.length > 1 && parts.slice(1).every(isPrivateUseSubtag);
1063
+ }
1058
1064
  let i = 0;
1059
1065
  const lang = parts[i];
1060
- if (!lang || !isIsoLanguageCode(lang)) return false;
1066
+ if (!lang || !/^[A-Za-z]{2,3}$/.test(lang)) return false;
1067
+ if (lang.length === 2 && !isIsoLanguageCode(lang)) return false;
1061
1068
  i += 1;
1069
+ if (lang.length <= 3) {
1070
+ let extlangCount = 0;
1071
+ while (i < parts.length && extlangCount < 3 && /^[A-Za-z]{3}$/.test(parts[i])) {
1072
+ i += 1;
1073
+ extlangCount += 1;
1074
+ }
1075
+ }
1062
1076
  if (i < parts.length && isScriptSubtag(parts[i])) {
1063
1077
  i += 1;
1064
1078
  }
1065
1079
  if (i < parts.length && isRegionSubtag(parts[i].toUpperCase())) {
1066
1080
  i += 1;
1067
1081
  }
1082
+ const variants = /* @__PURE__ */ new Set();
1068
1083
  while (i < parts.length && isVariantSubtag(parts[i])) {
1084
+ const variant = parts[i].toLowerCase();
1085
+ if (variants.has(variant)) return false;
1086
+ variants.add(variant);
1069
1087
  i += 1;
1070
1088
  }
1089
+ const extensionSingletons = /* @__PURE__ */ new Set();
1071
1090
  while (i < parts.length && isExtensionSingleton(parts[i])) {
1091
+ const singleton = parts[i].toLowerCase();
1092
+ if (extensionSingletons.has(singleton)) return false;
1093
+ extensionSingletons.add(singleton);
1072
1094
  i += 1;
1073
1095
  if (!(i < parts.length && isExtensionSubtag(parts[i]))) return false;
1074
1096
  while (i < parts.length && isExtensionSubtag(parts[i])) {
@@ -1084,6 +1106,34 @@ function validateLanguage(value) {
1084
1106
  }
1085
1107
  return i === parts.length;
1086
1108
  }
1109
+ var GRANDFATHERED_TAGS = /* @__PURE__ */ new Set([
1110
+ "art-lojban",
1111
+ "cel-gaulish",
1112
+ "en-gb-oed",
1113
+ "i-ami",
1114
+ "i-bnn",
1115
+ "i-default",
1116
+ "i-enochian",
1117
+ "i-hak",
1118
+ "i-klingon",
1119
+ "i-lux",
1120
+ "i-mingo",
1121
+ "i-navajo",
1122
+ "i-pwn",
1123
+ "i-tao",
1124
+ "i-tay",
1125
+ "i-tsu",
1126
+ "no-bok",
1127
+ "no-nyn",
1128
+ "sgn-be-fr",
1129
+ "sgn-be-nl",
1130
+ "sgn-ch-de",
1131
+ "zh-guoyu",
1132
+ "zh-hakka",
1133
+ "zh-min",
1134
+ "zh-min-nan",
1135
+ "zh-xiang"
1136
+ ]);
1087
1137
 
1088
1138
  // src/field.ts
1089
1139
  var field = {