@plasius/schema 1.1.1 → 1.2.1
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 +32 -19
- package/dist/index.cjs +511 -75
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +238 -2
- package/dist/index.d.ts +238 -2
- package/dist/index.js +500 -75
- package/dist/index.js.map +1 -1
- package/package.json +5 -2
package/dist/index.cjs
CHANGED
|
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
FieldBuilder: () => FieldBuilder,
|
|
24
|
+
IsoLanguageCode: () => IsoLanguageCode,
|
|
24
25
|
createComponentSchema: () => createComponentSchema,
|
|
25
26
|
createSchema: () => createSchema,
|
|
26
27
|
field: () => field,
|
|
@@ -28,13 +29,23 @@ __export(index_exports, {
|
|
|
28
29
|
getAllSchemas: () => getAllSchemas,
|
|
29
30
|
getComponentSchema: () => getComponentSchema,
|
|
30
31
|
getSchemaForType: () => getSchemaForType,
|
|
32
|
+
isExtensionSingleton: () => isExtensionSingleton,
|
|
33
|
+
isExtensionSubtag: () => isExtensionSubtag,
|
|
34
|
+
isIsoLanguageCode: () => isIsoLanguageCode,
|
|
35
|
+
isPrivateUseSingleton: () => isPrivateUseSingleton,
|
|
36
|
+
isPrivateUseSubtag: () => isPrivateUseSubtag,
|
|
37
|
+
isRegionSubtag: () => isRegionSubtag,
|
|
38
|
+
isScriptSubtag: () => isScriptSubtag,
|
|
39
|
+
isVariantSubtag: () => isVariantSubtag,
|
|
31
40
|
isoCountryCodes: () => isoCountryCodes,
|
|
32
41
|
isoCurrencyCodes: () => isoCurrencyCodes,
|
|
33
42
|
registerComponentSchema: () => registerComponentSchema,
|
|
43
|
+
renderSchemaDescription: () => renderSchemaDescription,
|
|
34
44
|
validateCountryCode: () => validateCountryCode,
|
|
35
45
|
validateCurrencyCode: () => validateCurrencyCode,
|
|
36
46
|
validateDateTimeISO: () => validateDateTimeISO,
|
|
37
47
|
validateEmail: () => validateEmail,
|
|
48
|
+
validateLanguage: () => validateLanguage,
|
|
38
49
|
validateName: () => validateName,
|
|
39
50
|
validatePercentage: () => validatePercentage,
|
|
40
51
|
validatePhone: () => validatePhone,
|
|
@@ -466,6 +477,7 @@ var isoCountryCodes = /* @__PURE__ */ new Set([
|
|
|
466
477
|
"PM",
|
|
467
478
|
"PN",
|
|
468
479
|
"PR",
|
|
480
|
+
"PS",
|
|
469
481
|
"PT",
|
|
470
482
|
"PW",
|
|
471
483
|
"PY",
|
|
@@ -668,6 +680,7 @@ var isoCurrencyCodes = /* @__PURE__ */ new Set([
|
|
|
668
680
|
"SEK",
|
|
669
681
|
"SGD",
|
|
670
682
|
"SHP",
|
|
683
|
+
"SLE",
|
|
671
684
|
"SLL",
|
|
672
685
|
"SOS",
|
|
673
686
|
"SRD",
|
|
@@ -1153,49 +1166,151 @@ function enforcePIIField(parentKey, key, value, def, enforcement = "none", error
|
|
|
1153
1166
|
return { shortCircuit: false };
|
|
1154
1167
|
}
|
|
1155
1168
|
function prepareForStorage(shape, input, encryptFn, hashFn) {
|
|
1156
|
-
const
|
|
1157
|
-
|
|
1158
|
-
const
|
|
1159
|
-
if (!def) continue;
|
|
1160
|
-
const value = input[key];
|
|
1169
|
+
const build = (def, value, key, out, ctx = {}) => {
|
|
1170
|
+
if (!def) return;
|
|
1171
|
+
const isMissing = value === void 0 || value === null;
|
|
1161
1172
|
if (def._pii?.action === "encrypt") {
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1173
|
+
if (!isMissing) out[key + "Encrypted"] = encryptFn(value);
|
|
1174
|
+
return;
|
|
1175
|
+
}
|
|
1176
|
+
if (def._pii?.action === "hash") {
|
|
1177
|
+
if (!isMissing) out[key + "Hash"] = hashFn(value);
|
|
1178
|
+
return;
|
|
1179
|
+
}
|
|
1180
|
+
if (def._pii?.action === "clear") {
|
|
1181
|
+
if (!isMissing) out[key] = null;
|
|
1182
|
+
return;
|
|
1183
|
+
}
|
|
1184
|
+
if (def.type === "object" && def._shape) {
|
|
1185
|
+
const obj = {};
|
|
1186
|
+
for (const [childKey, childDef] of Object.entries(def._shape)) {
|
|
1187
|
+
build(childDef, value?.[childKey], childKey, obj, { parentKey: key });
|
|
1188
|
+
}
|
|
1189
|
+
out[key] = obj;
|
|
1190
|
+
return;
|
|
1191
|
+
}
|
|
1192
|
+
if (def.type === "array" && def.itemType && Array.isArray(value)) {
|
|
1193
|
+
out[key] = value.map((item) => {
|
|
1194
|
+
const obj = {};
|
|
1195
|
+
build(def.itemType, item, key, obj, {
|
|
1196
|
+
parentKey: key,
|
|
1197
|
+
isArrayItem: true
|
|
1198
|
+
});
|
|
1199
|
+
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
1200
|
+
return obj[key];
|
|
1201
|
+
}
|
|
1202
|
+
return Object.keys(obj).length > 0 ? obj : item;
|
|
1203
|
+
});
|
|
1204
|
+
return;
|
|
1205
|
+
}
|
|
1206
|
+
if (def.type === "ref") {
|
|
1207
|
+
const ref = { ...value };
|
|
1208
|
+
const refShape = def._shape;
|
|
1209
|
+
if (refShape && value) {
|
|
1210
|
+
for (const [childKey, childDef] of Object.entries(refShape)) {
|
|
1211
|
+
build(childDef, value[childKey], childKey, ref, { parentKey: key });
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
out[key] = ref;
|
|
1215
|
+
return;
|
|
1167
1216
|
}
|
|
1217
|
+
out[key] = value;
|
|
1218
|
+
};
|
|
1219
|
+
const result = {};
|
|
1220
|
+
for (const key in shape) {
|
|
1221
|
+
build(shape[key], input?.[key], key, result);
|
|
1168
1222
|
}
|
|
1169
1223
|
return result;
|
|
1170
1224
|
}
|
|
1171
1225
|
function prepareForRead(shape, stored, decryptFn) {
|
|
1226
|
+
const readValue = (def, key, container, ctx = {}) => {
|
|
1227
|
+
if (!def) return container?.[key];
|
|
1228
|
+
const action = def._pii?.action;
|
|
1229
|
+
if (action === "encrypt") {
|
|
1230
|
+
const enc = container?.[key + "Encrypted"] ?? container?.[`${ctx.parentKey ?? key}Encrypted`];
|
|
1231
|
+
return enc === void 0 ? void 0 : decryptFn(enc);
|
|
1232
|
+
}
|
|
1233
|
+
if (action === "hash") {
|
|
1234
|
+
const h = container?.[key + "Hash"] ?? container?.[`${ctx.parentKey ?? key}Hash`];
|
|
1235
|
+
return h === void 0 ? void 0 : h;
|
|
1236
|
+
}
|
|
1237
|
+
if (action === "clear")
|
|
1238
|
+
return container?.hasOwnProperty(key) ? null : void 0;
|
|
1239
|
+
if (def.type === "object" && def._shape) {
|
|
1240
|
+
const obj = {};
|
|
1241
|
+
const source = container && Object.prototype.hasOwnProperty.call(container, key) ? container[key] : container ?? {};
|
|
1242
|
+
for (const [childKey, childDef] of Object.entries(def._shape)) {
|
|
1243
|
+
obj[childKey] = readValue(childDef, childKey, source);
|
|
1244
|
+
}
|
|
1245
|
+
return obj;
|
|
1246
|
+
}
|
|
1247
|
+
if (def.type === "array" && def.itemType) {
|
|
1248
|
+
const arr = container?.[key];
|
|
1249
|
+
if (!Array.isArray(arr)) return arr;
|
|
1250
|
+
return arr.map(
|
|
1251
|
+
(item) => readValue(def.itemType, key, item, { parentKey: key, isArrayItem: true })
|
|
1252
|
+
);
|
|
1253
|
+
}
|
|
1254
|
+
if (def.type === "ref") {
|
|
1255
|
+
const ref = { ...container?.[key] ?? {} };
|
|
1256
|
+
const refShape = def._shape;
|
|
1257
|
+
if (refShape) {
|
|
1258
|
+
for (const [childKey, childDef] of Object.entries(refShape)) {
|
|
1259
|
+
ref[childKey] = readValue(childDef, childKey, ref);
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1262
|
+
return ref;
|
|
1263
|
+
}
|
|
1264
|
+
return container?.[key];
|
|
1265
|
+
};
|
|
1172
1266
|
const result = {};
|
|
1173
1267
|
for (const key in shape) {
|
|
1174
|
-
|
|
1175
|
-
if (!def) continue;
|
|
1176
|
-
if (def._pii?.action === "encrypt") {
|
|
1177
|
-
result[key] = decryptFn(stored[key + "Encrypted"]);
|
|
1178
|
-
} else {
|
|
1179
|
-
result[key] = stored[key];
|
|
1180
|
-
}
|
|
1268
|
+
result[key] = readValue(shape[key], key, stored);
|
|
1181
1269
|
}
|
|
1182
1270
|
return result;
|
|
1183
1271
|
}
|
|
1184
1272
|
function sanitizeForLog(shape, data, pseudonymFn) {
|
|
1185
|
-
const
|
|
1186
|
-
|
|
1187
|
-
const def = shape[key];
|
|
1188
|
-
if (!def) continue;
|
|
1189
|
-
const value = data[key];
|
|
1273
|
+
const visit = (def, value, ctx = {}) => {
|
|
1274
|
+
if (!def) return void 0;
|
|
1190
1275
|
const handling = def._pii?.logHandling;
|
|
1191
|
-
if (handling === "omit")
|
|
1192
|
-
if (handling === "redact")
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1276
|
+
if (handling === "omit") return void 0;
|
|
1277
|
+
if (handling === "redact") return "[REDACTED]";
|
|
1278
|
+
if (handling === "pseudonym") return pseudonymFn(value);
|
|
1279
|
+
if (def.type === "object" && def._shape) {
|
|
1280
|
+
const obj = {};
|
|
1281
|
+
const src = value ?? {};
|
|
1282
|
+
for (const [k, childDef] of Object.entries(def._shape)) {
|
|
1283
|
+
const child = visit(childDef, src[k], { parentKey: k });
|
|
1284
|
+
if (child !== void 0) obj[k] = child;
|
|
1285
|
+
}
|
|
1286
|
+
return obj;
|
|
1287
|
+
}
|
|
1288
|
+
if (def.type === "array" && def.itemType) {
|
|
1289
|
+
if (!Array.isArray(value)) return void 0;
|
|
1290
|
+
const arr = value.map((v) => visit(def.itemType, v, { parentKey: ctx.parentKey })).filter((v) => v !== void 0);
|
|
1291
|
+
return arr;
|
|
1292
|
+
}
|
|
1293
|
+
if (def.type === "ref") {
|
|
1294
|
+
const ref = value ? { type: value.type, id: value.id } : {};
|
|
1295
|
+
const refShape = def._shape;
|
|
1296
|
+
const src = value ?? {};
|
|
1297
|
+
if (refShape) {
|
|
1298
|
+
for (const [k, childDef] of Object.entries(refShape)) {
|
|
1299
|
+
const child = visit(childDef, src[k]);
|
|
1300
|
+
if (child !== void 0) ref[k] = child;
|
|
1301
|
+
}
|
|
1302
|
+
} else if (value) {
|
|
1303
|
+
ref.type = value.type;
|
|
1304
|
+
ref.id = value.id;
|
|
1305
|
+
}
|
|
1306
|
+
return ref;
|
|
1198
1307
|
}
|
|
1308
|
+
return value;
|
|
1309
|
+
};
|
|
1310
|
+
const output = {};
|
|
1311
|
+
for (const key in shape) {
|
|
1312
|
+
const child = visit(shape[key], data?.[key]);
|
|
1313
|
+
if (child !== void 0) output[key] = child;
|
|
1199
1314
|
}
|
|
1200
1315
|
return output;
|
|
1201
1316
|
}
|
|
@@ -1217,23 +1332,106 @@ function getPiiAudit(shape) {
|
|
|
1217
1332
|
return piiFields;
|
|
1218
1333
|
}
|
|
1219
1334
|
function scrubPiiForDelete(shape, stored) {
|
|
1220
|
-
const result = { ...stored };
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1335
|
+
const result = Array.isArray(stored) ? [...stored] : { ...stored };
|
|
1336
|
+
const setAtPath = (target, path, val) => {
|
|
1337
|
+
let cur = target;
|
|
1338
|
+
for (let i = 0; i < path.length - 1; i++) {
|
|
1339
|
+
const p = path[i];
|
|
1340
|
+
if (p === void 0) return;
|
|
1341
|
+
if (cur[p] === void 0) {
|
|
1342
|
+
const next = path[i + 1];
|
|
1343
|
+
cur[p] = typeof next === "number" ? [] : {};
|
|
1344
|
+
}
|
|
1345
|
+
cur = cur[p];
|
|
1346
|
+
}
|
|
1347
|
+
const last = path[path.length - 1];
|
|
1348
|
+
if (last === void 0) return;
|
|
1349
|
+
cur[last] = val;
|
|
1350
|
+
};
|
|
1351
|
+
const visit = (def, host, path, keyName) => {
|
|
1352
|
+
if (!def) return;
|
|
1353
|
+
const applyPath = (targetKey) => {
|
|
1354
|
+
const last = path[path.length - 1];
|
|
1355
|
+
if (last === void 0) return;
|
|
1356
|
+
if (typeof last === "number") {
|
|
1357
|
+
setAtPath(result, [...path, targetKey], null);
|
|
1358
|
+
} else {
|
|
1359
|
+
setAtPath(result, [...path.slice(0, -1), targetKey], null);
|
|
1360
|
+
}
|
|
1361
|
+
};
|
|
1224
1362
|
if (def._pii?.action === "encrypt") {
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1363
|
+
const targetKey = `${keyName}Encrypted`;
|
|
1364
|
+
if (host && Object.prototype.hasOwnProperty.call(host, targetKey)) {
|
|
1365
|
+
applyPath(targetKey);
|
|
1366
|
+
}
|
|
1367
|
+
return;
|
|
1230
1368
|
}
|
|
1369
|
+
if (def._pii?.action === "hash") {
|
|
1370
|
+
const targetKey = `${keyName}Hash`;
|
|
1371
|
+
if (host && Object.prototype.hasOwnProperty.call(host, targetKey)) {
|
|
1372
|
+
applyPath(targetKey);
|
|
1373
|
+
}
|
|
1374
|
+
return;
|
|
1375
|
+
}
|
|
1376
|
+
if (def._pii?.action === "clear") {
|
|
1377
|
+
if (host && Object.prototype.hasOwnProperty.call(host, keyName)) {
|
|
1378
|
+
setAtPath(result, path, null);
|
|
1379
|
+
}
|
|
1380
|
+
return;
|
|
1381
|
+
}
|
|
1382
|
+
if (def.type === "object" && def._shape) {
|
|
1383
|
+
const obj = host && Object.prototype.hasOwnProperty.call(host, keyName) ? host[keyName] : host;
|
|
1384
|
+
for (const [k, childDef] of Object.entries(def._shape)) {
|
|
1385
|
+
visit(childDef, obj, [...path, k], k);
|
|
1386
|
+
}
|
|
1387
|
+
return;
|
|
1388
|
+
}
|
|
1389
|
+
if (def.type === "array" && def.itemType) {
|
|
1390
|
+
const arr = host?.[keyName];
|
|
1391
|
+
if (Array.isArray(arr)) {
|
|
1392
|
+
arr.forEach(
|
|
1393
|
+
(item, idx) => visit(def.itemType, item, [...path, idx], keyName)
|
|
1394
|
+
);
|
|
1395
|
+
}
|
|
1396
|
+
return;
|
|
1397
|
+
}
|
|
1398
|
+
if (def.type === "ref") {
|
|
1399
|
+
const refShape = def._shape;
|
|
1400
|
+
const ref = host?.[keyName];
|
|
1401
|
+
if (refShape && ref) {
|
|
1402
|
+
for (const [k, childDef] of Object.entries(refShape)) {
|
|
1403
|
+
visit(childDef, ref, [...path, k], k);
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1407
|
+
};
|
|
1408
|
+
for (const key in shape) {
|
|
1409
|
+
visit(shape[key], stored, [key], key);
|
|
1231
1410
|
}
|
|
1232
1411
|
return result;
|
|
1233
1412
|
}
|
|
1234
1413
|
|
|
1235
1414
|
// src/schema.ts
|
|
1236
1415
|
var globalSchemaRegistry = /* @__PURE__ */ new Map();
|
|
1416
|
+
function deepClone(value) {
|
|
1417
|
+
const seen = /* @__PURE__ */ new WeakMap();
|
|
1418
|
+
const cloneAny = (val) => {
|
|
1419
|
+
if (val === null || typeof val !== "object") return val;
|
|
1420
|
+
if (seen.has(val)) throw new TypeError("Cannot clone circular structures");
|
|
1421
|
+
if (val instanceof Date) return new Date(val.getTime());
|
|
1422
|
+
if (Array.isArray(val)) {
|
|
1423
|
+
const arr = [];
|
|
1424
|
+
seen.set(val, arr);
|
|
1425
|
+
val.forEach((item) => arr.push(cloneAny(item)));
|
|
1426
|
+
return arr;
|
|
1427
|
+
}
|
|
1428
|
+
const out = {};
|
|
1429
|
+
seen.set(val, out);
|
|
1430
|
+
for (const [k, v] of Object.entries(val)) out[k] = cloneAny(v);
|
|
1431
|
+
return out;
|
|
1432
|
+
};
|
|
1433
|
+
return cloneAny(value);
|
|
1434
|
+
}
|
|
1237
1435
|
function cmpSemver(a, b) {
|
|
1238
1436
|
const pa = a.split(".").map((n) => parseInt(n, 10));
|
|
1239
1437
|
const pb = b.split(".").map((n) => parseInt(n, 10));
|
|
@@ -1292,8 +1490,17 @@ function getEnumValues(def) {
|
|
|
1292
1490
|
);
|
|
1293
1491
|
return ok ? src : void 0;
|
|
1294
1492
|
}
|
|
1493
|
+
function applyDefault(def, current) {
|
|
1494
|
+
if ((current === void 0 || current === null) && typeof def?.getDefault === "function") {
|
|
1495
|
+
const next = def.getDefault();
|
|
1496
|
+
if (next !== void 0) {
|
|
1497
|
+
return { value: next, applied: true };
|
|
1498
|
+
}
|
|
1499
|
+
}
|
|
1500
|
+
return { value: current, applied: false };
|
|
1501
|
+
}
|
|
1295
1502
|
function isOptional(def) {
|
|
1296
|
-
return
|
|
1503
|
+
return def?.isRequired === false;
|
|
1297
1504
|
}
|
|
1298
1505
|
function getValidator(def) {
|
|
1299
1506
|
return def?._validator ?? void 0;
|
|
@@ -1345,10 +1552,18 @@ function validateStringField(parentKey, key, value, def, errors) {
|
|
|
1345
1552
|
}
|
|
1346
1553
|
}
|
|
1347
1554
|
}
|
|
1348
|
-
function validateNumberField(parentKey, key, value,
|
|
1349
|
-
const
|
|
1555
|
+
function validateNumberField(parentKey, key, value, def, errors) {
|
|
1556
|
+
const path = parentKey ? `${parentKey}.${key}` : key;
|
|
1350
1557
|
if (typeof value !== "number") {
|
|
1351
|
-
errors.push(`Field ${
|
|
1558
|
+
errors.push(`Field ${path} must be number`);
|
|
1559
|
+
return;
|
|
1560
|
+
}
|
|
1561
|
+
const enumValues = getEnumValues(def);
|
|
1562
|
+
if (Array.isArray(enumValues)) {
|
|
1563
|
+
const enumError = validateEnum(path, value, enumValues);
|
|
1564
|
+
if (enumError) {
|
|
1565
|
+
errors.push(enumError);
|
|
1566
|
+
}
|
|
1352
1567
|
}
|
|
1353
1568
|
}
|
|
1354
1569
|
function validateBooleanField(parentKey, key, value, _def, errors) {
|
|
@@ -1357,9 +1572,15 @@ function validateBooleanField(parentKey, key, value, _def, errors) {
|
|
|
1357
1572
|
errors.push(`Field ${path} must be boolean`);
|
|
1358
1573
|
}
|
|
1359
1574
|
}
|
|
1360
|
-
function validateObjectChildren(parentKey, obj, shape, errors) {
|
|
1575
|
+
function validateObjectChildren(parentKey, obj, shape, errors, existing, piiEnforcement, logger) {
|
|
1361
1576
|
for (const [childKey, childDef] of Object.entries(shape)) {
|
|
1362
|
-
|
|
1577
|
+
let childValue = obj[childKey];
|
|
1578
|
+
const existingChild = existing && typeof existing === "object" ? existing[childKey] : void 0;
|
|
1579
|
+
const { value: withDefault, applied } = applyDefault(childDef, childValue);
|
|
1580
|
+
if (applied) {
|
|
1581
|
+
obj[childKey] = withDefault;
|
|
1582
|
+
childValue = withDefault;
|
|
1583
|
+
}
|
|
1363
1584
|
const { missing } = checkMissingRequired(
|
|
1364
1585
|
parentKey,
|
|
1365
1586
|
childKey,
|
|
@@ -1368,6 +1589,25 @@ function validateObjectChildren(parentKey, obj, shape, errors) {
|
|
|
1368
1589
|
errors
|
|
1369
1590
|
);
|
|
1370
1591
|
if (missing) continue;
|
|
1592
|
+
const { immutableViolation } = checkImmutable(
|
|
1593
|
+
parentKey,
|
|
1594
|
+
childKey,
|
|
1595
|
+
childValue,
|
|
1596
|
+
childDef,
|
|
1597
|
+
existing,
|
|
1598
|
+
errors
|
|
1599
|
+
);
|
|
1600
|
+
if (immutableViolation) continue;
|
|
1601
|
+
const { shortCircuit } = enforcePIIField(
|
|
1602
|
+
parentKey,
|
|
1603
|
+
childKey,
|
|
1604
|
+
childValue,
|
|
1605
|
+
childDef,
|
|
1606
|
+
piiEnforcement,
|
|
1607
|
+
errors,
|
|
1608
|
+
logger
|
|
1609
|
+
);
|
|
1610
|
+
if (shortCircuit) continue;
|
|
1371
1611
|
const { invalid } = runCustomValidator(
|
|
1372
1612
|
parentKey,
|
|
1373
1613
|
childKey,
|
|
@@ -1376,17 +1616,27 @@ function validateObjectChildren(parentKey, obj, shape, errors) {
|
|
|
1376
1616
|
errors
|
|
1377
1617
|
);
|
|
1378
1618
|
if (invalid) continue;
|
|
1379
|
-
validateByType(
|
|
1619
|
+
validateByType(
|
|
1620
|
+
parentKey,
|
|
1621
|
+
childKey,
|
|
1622
|
+
childValue,
|
|
1623
|
+
childDef,
|
|
1624
|
+
errors,
|
|
1625
|
+
existingChild,
|
|
1626
|
+
piiEnforcement,
|
|
1627
|
+
logger
|
|
1628
|
+
);
|
|
1380
1629
|
}
|
|
1381
1630
|
}
|
|
1382
|
-
function validateObjectField(parentKey, key, value, def, errors) {
|
|
1631
|
+
function validateObjectField(parentKey, key, value, def, errors, existing, piiEnforcement, logger) {
|
|
1383
1632
|
const path = parentKey ? `${parentKey}.${key}` : key;
|
|
1384
1633
|
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
1385
1634
|
errors.push(`Field ${path} must be object`);
|
|
1386
1635
|
return;
|
|
1387
1636
|
}
|
|
1388
1637
|
const objShape = getShape(def);
|
|
1389
|
-
if (objShape)
|
|
1638
|
+
if (objShape)
|
|
1639
|
+
validateObjectChildren(path, value, objShape, errors, existing, piiEnforcement, logger);
|
|
1390
1640
|
}
|
|
1391
1641
|
function validateArrayOfStrings(parentKey, key, arr, itemDef, errors) {
|
|
1392
1642
|
const path = parentKey ? `${parentKey}.${key}` : key;
|
|
@@ -1401,6 +1651,14 @@ function validateArrayOfStrings(parentKey, key, arr, itemDef, errors) {
|
|
|
1401
1651
|
errors.push(enumError);
|
|
1402
1652
|
}
|
|
1403
1653
|
}
|
|
1654
|
+
const validator = getValidator(itemDef);
|
|
1655
|
+
if (validator) {
|
|
1656
|
+
arr.forEach((v, idx) => {
|
|
1657
|
+
if (!validator(v)) {
|
|
1658
|
+
errors.push(`Invalid value for field: ${path}[${idx}]`);
|
|
1659
|
+
}
|
|
1660
|
+
});
|
|
1661
|
+
}
|
|
1404
1662
|
}
|
|
1405
1663
|
function validateArrayOfNumbers(parentKey, key, arr, itemDef, errors) {
|
|
1406
1664
|
const path = parentKey ? `${parentKey}.${key}` : key;
|
|
@@ -1414,14 +1672,30 @@ function validateArrayOfNumbers(parentKey, key, arr, itemDef, errors) {
|
|
|
1414
1672
|
errors.push(enumError);
|
|
1415
1673
|
}
|
|
1416
1674
|
}
|
|
1675
|
+
const validator = getValidator(itemDef);
|
|
1676
|
+
if (validator) {
|
|
1677
|
+
arr.forEach((v, idx) => {
|
|
1678
|
+
if (!validator(v)) {
|
|
1679
|
+
errors.push(`Invalid value for field: ${path}[${idx}]`);
|
|
1680
|
+
}
|
|
1681
|
+
});
|
|
1682
|
+
}
|
|
1417
1683
|
}
|
|
1418
1684
|
function validateArrayOfBooleans(parentKey, key, arr, _itemDef, errors) {
|
|
1419
1685
|
const path = parentKey ? `${parentKey}.${key}` : key;
|
|
1420
1686
|
if (!arr.every((v) => typeof v === "boolean")) {
|
|
1421
1687
|
errors.push(`Field ${path} must be boolean[]`);
|
|
1422
1688
|
}
|
|
1689
|
+
const validator = getValidator(_itemDef);
|
|
1690
|
+
if (validator) {
|
|
1691
|
+
arr.forEach((v, idx) => {
|
|
1692
|
+
if (!validator(v)) {
|
|
1693
|
+
errors.push(`Invalid value for field: ${path}[${idx}]`);
|
|
1694
|
+
}
|
|
1695
|
+
});
|
|
1696
|
+
}
|
|
1423
1697
|
}
|
|
1424
|
-
function validateArrayOfObjects(parentKey, key, arr, itemDef, errors) {
|
|
1698
|
+
function validateArrayOfObjects(parentKey, key, arr, itemDef, errors, existing, piiEnforcement, logger) {
|
|
1425
1699
|
const path = parentKey ? `${parentKey}.${key}` : key;
|
|
1426
1700
|
if (!Array.isArray(arr) || !arr.every((v) => typeof v === "object" && v !== null && !Array.isArray(v))) {
|
|
1427
1701
|
errors.push(`Field ${path} must be object[]`);
|
|
@@ -1431,8 +1705,18 @@ function validateArrayOfObjects(parentKey, key, arr, itemDef, errors) {
|
|
|
1431
1705
|
if (!itemShape) return;
|
|
1432
1706
|
arr.forEach((item, idx) => {
|
|
1433
1707
|
const itemParent = `${path}[${idx}]`;
|
|
1708
|
+
const existingItem = Array.isArray(existing) ? existing[idx] : void 0;
|
|
1434
1709
|
for (const [childKey, childDef] of Object.entries(itemShape)) {
|
|
1435
|
-
|
|
1710
|
+
let childValue = item[childKey];
|
|
1711
|
+
const existingChild = existingItem && typeof existingItem === "object" ? existingItem[childKey] : void 0;
|
|
1712
|
+
const { value: withDefault, applied } = applyDefault(
|
|
1713
|
+
childDef,
|
|
1714
|
+
childValue
|
|
1715
|
+
);
|
|
1716
|
+
if (applied) {
|
|
1717
|
+
item[childKey] = withDefault;
|
|
1718
|
+
childValue = withDefault;
|
|
1719
|
+
}
|
|
1436
1720
|
const { missing } = checkMissingRequired(
|
|
1437
1721
|
itemParent,
|
|
1438
1722
|
childKey,
|
|
@@ -1441,6 +1725,25 @@ function validateArrayOfObjects(parentKey, key, arr, itemDef, errors) {
|
|
|
1441
1725
|
errors
|
|
1442
1726
|
);
|
|
1443
1727
|
if (missing) continue;
|
|
1728
|
+
const { immutableViolation } = checkImmutable(
|
|
1729
|
+
itemParent,
|
|
1730
|
+
childKey,
|
|
1731
|
+
childValue,
|
|
1732
|
+
childDef,
|
|
1733
|
+
existingItem,
|
|
1734
|
+
errors
|
|
1735
|
+
);
|
|
1736
|
+
if (immutableViolation) continue;
|
|
1737
|
+
const { shortCircuit } = enforcePIIField(
|
|
1738
|
+
itemParent,
|
|
1739
|
+
childKey,
|
|
1740
|
+
childValue,
|
|
1741
|
+
childDef,
|
|
1742
|
+
piiEnforcement,
|
|
1743
|
+
errors,
|
|
1744
|
+
logger
|
|
1745
|
+
);
|
|
1746
|
+
if (shortCircuit) continue;
|
|
1444
1747
|
const { invalid } = runCustomValidator(
|
|
1445
1748
|
itemParent,
|
|
1446
1749
|
childKey,
|
|
@@ -1449,11 +1752,20 @@ function validateArrayOfObjects(parentKey, key, arr, itemDef, errors) {
|
|
|
1449
1752
|
errors
|
|
1450
1753
|
);
|
|
1451
1754
|
if (invalid) continue;
|
|
1452
|
-
validateByType(
|
|
1755
|
+
validateByType(
|
|
1756
|
+
itemParent,
|
|
1757
|
+
childKey,
|
|
1758
|
+
childValue,
|
|
1759
|
+
childDef,
|
|
1760
|
+
errors,
|
|
1761
|
+
existingChild,
|
|
1762
|
+
piiEnforcement,
|
|
1763
|
+
logger
|
|
1764
|
+
);
|
|
1453
1765
|
}
|
|
1454
1766
|
});
|
|
1455
1767
|
}
|
|
1456
|
-
function validateArrayField(parentKey, key, value, def, errors) {
|
|
1768
|
+
function validateArrayField(parentKey, key, value, def, errors, existing, piiEnforcement, logger) {
|
|
1457
1769
|
const path = parentKey ? `${parentKey}.${key}` : key;
|
|
1458
1770
|
if (!Array.isArray(value)) {
|
|
1459
1771
|
errors.push(`Field ${key} must be an array`);
|
|
@@ -1467,7 +1779,16 @@ function validateArrayField(parentKey, key, value, def, errors) {
|
|
|
1467
1779
|
if (itemType === "boolean")
|
|
1468
1780
|
return validateArrayOfBooleans(parentKey, key, value, def.itemType, errors);
|
|
1469
1781
|
if (itemType === "object")
|
|
1470
|
-
return validateArrayOfObjects(
|
|
1782
|
+
return validateArrayOfObjects(
|
|
1783
|
+
parentKey,
|
|
1784
|
+
key,
|
|
1785
|
+
value,
|
|
1786
|
+
def.itemType,
|
|
1787
|
+
errors,
|
|
1788
|
+
existing,
|
|
1789
|
+
piiEnforcement,
|
|
1790
|
+
logger
|
|
1791
|
+
);
|
|
1471
1792
|
if (itemType === "ref") {
|
|
1472
1793
|
const expectedType = def.itemType.refType;
|
|
1473
1794
|
value.forEach((ref, idx) => {
|
|
@@ -1479,24 +1800,63 @@ function validateArrayField(parentKey, key, value, def, errors) {
|
|
|
1479
1800
|
});
|
|
1480
1801
|
const refShape = getShape(def.itemType);
|
|
1481
1802
|
if (refShape) {
|
|
1803
|
+
const existingRefs = Array.isArray(existing) ? existing : [];
|
|
1482
1804
|
value.forEach((ref, idx) => {
|
|
1483
1805
|
if (ref && typeof ref === "object" && ref !== null) {
|
|
1806
|
+
const existingRef = existingRefs[idx];
|
|
1484
1807
|
for (const [childKey, childDef] of Object.entries(refShape)) {
|
|
1485
|
-
const
|
|
1808
|
+
const childPath = `${path}[${idx}].${childKey}`;
|
|
1809
|
+
let childValue = ref[childKey];
|
|
1810
|
+
const existingChild = existingRef && typeof existingRef === "object" ? existingRef[childKey] : void 0;
|
|
1811
|
+
const { value: withDefault, applied } = applyDefault(
|
|
1812
|
+
childDef,
|
|
1813
|
+
childValue
|
|
1814
|
+
);
|
|
1815
|
+
if (applied) {
|
|
1816
|
+
ref[childKey] = withDefault;
|
|
1817
|
+
childValue = withDefault;
|
|
1818
|
+
}
|
|
1486
1819
|
if ((childValue === void 0 || childValue === null) && !isOptional(childDef)) {
|
|
1487
|
-
errors.push(
|
|
1488
|
-
`Missing required field: ${path}[${idx}].${childKey}`
|
|
1489
|
-
);
|
|
1820
|
+
errors.push(`Missing required field: ${childPath}`);
|
|
1490
1821
|
continue;
|
|
1491
1822
|
}
|
|
1823
|
+
const { immutableViolation } = checkImmutable(
|
|
1824
|
+
`${path}[${idx}]`,
|
|
1825
|
+
childKey,
|
|
1826
|
+
childValue,
|
|
1827
|
+
childDef,
|
|
1828
|
+
existingRef,
|
|
1829
|
+
errors
|
|
1830
|
+
);
|
|
1831
|
+
if (immutableViolation) continue;
|
|
1832
|
+
const { shortCircuit } = enforcePIIField(
|
|
1833
|
+
`${path}[${idx}]`,
|
|
1834
|
+
childKey,
|
|
1835
|
+
childValue,
|
|
1836
|
+
childDef,
|
|
1837
|
+
piiEnforcement,
|
|
1838
|
+
errors,
|
|
1839
|
+
logger
|
|
1840
|
+
);
|
|
1841
|
+
if (shortCircuit) continue;
|
|
1492
1842
|
const childValidator = getValidator(childDef);
|
|
1493
1843
|
if (childValidator && childValue !== void 0 && childValue !== null) {
|
|
1494
1844
|
const valid = childValidator(childValue);
|
|
1495
|
-
if (!valid)
|
|
1496
|
-
errors.push(
|
|
1497
|
-
|
|
1498
|
-
|
|
1845
|
+
if (!valid) {
|
|
1846
|
+
errors.push(`Invalid value for field: ${childPath}`);
|
|
1847
|
+
continue;
|
|
1848
|
+
}
|
|
1499
1849
|
}
|
|
1850
|
+
validateByType(
|
|
1851
|
+
`${path}[${idx}]`,
|
|
1852
|
+
childKey,
|
|
1853
|
+
childValue,
|
|
1854
|
+
childDef,
|
|
1855
|
+
errors,
|
|
1856
|
+
existingChild,
|
|
1857
|
+
piiEnforcement,
|
|
1858
|
+
logger
|
|
1859
|
+
);
|
|
1500
1860
|
}
|
|
1501
1861
|
}
|
|
1502
1862
|
});
|
|
@@ -1505,13 +1865,20 @@ function validateArrayField(parentKey, key, value, def, errors) {
|
|
|
1505
1865
|
}
|
|
1506
1866
|
errors.push(`Field ${path} has unsupported array item type`);
|
|
1507
1867
|
}
|
|
1508
|
-
function validateRefField(parentKey, key, value,
|
|
1868
|
+
function validateRefField(parentKey, key, value, def, errors, _existing, _piiEnforcement, _logger) {
|
|
1869
|
+
const path = parentKey ? `${parentKey}.${key}` : key;
|
|
1509
1870
|
if (typeof value !== "object" || value === null || typeof value.type !== "string" || typeof value.id !== "string") {
|
|
1510
|
-
const path = parentKey ? `${parentKey}.${key}` : key;
|
|
1511
1871
|
errors.push(`Field ${path} must be { type: string; id: string }`);
|
|
1872
|
+
return;
|
|
1873
|
+
}
|
|
1874
|
+
const expectedType = def.refType;
|
|
1875
|
+
if (expectedType && value.type !== expectedType) {
|
|
1876
|
+
errors.push(
|
|
1877
|
+
`Field ${path} must reference type: ${expectedType} (got ${value.type})`
|
|
1878
|
+
);
|
|
1512
1879
|
}
|
|
1513
1880
|
}
|
|
1514
|
-
function validateByType(parentKey, key, value, def, errors) {
|
|
1881
|
+
function validateByType(parentKey, key, value, def, errors, existing, piiEnforcement, logger) {
|
|
1515
1882
|
const path = parentKey ? `${parentKey}.${key}` : key;
|
|
1516
1883
|
switch (def.type) {
|
|
1517
1884
|
case "string":
|
|
@@ -1521,11 +1888,29 @@ function validateByType(parentKey, key, value, def, errors) {
|
|
|
1521
1888
|
case "boolean":
|
|
1522
1889
|
return validateBooleanField(parentKey, key, value, def, errors);
|
|
1523
1890
|
case "object":
|
|
1524
|
-
return validateObjectField(
|
|
1891
|
+
return validateObjectField(
|
|
1892
|
+
parentKey,
|
|
1893
|
+
key,
|
|
1894
|
+
value,
|
|
1895
|
+
def,
|
|
1896
|
+
errors,
|
|
1897
|
+
existing,
|
|
1898
|
+
piiEnforcement,
|
|
1899
|
+
logger
|
|
1900
|
+
);
|
|
1525
1901
|
case "array":
|
|
1526
|
-
return validateArrayField(
|
|
1902
|
+
return validateArrayField(
|
|
1903
|
+
parentKey,
|
|
1904
|
+
key,
|
|
1905
|
+
value,
|
|
1906
|
+
def,
|
|
1907
|
+
errors,
|
|
1908
|
+
existing,
|
|
1909
|
+
piiEnforcement,
|
|
1910
|
+
logger
|
|
1911
|
+
);
|
|
1527
1912
|
case "ref":
|
|
1528
|
-
return validateRefField(parentKey, key, value, def, errors);
|
|
1913
|
+
return validateRefField(parentKey, key, value, def, errors, existing, piiEnforcement, logger);
|
|
1529
1914
|
default:
|
|
1530
1915
|
errors.push(`Unknown type for field ${path}: ${def.type}`);
|
|
1531
1916
|
}
|
|
@@ -1556,10 +1941,11 @@ function createSchema(_shape, entityType, options = {
|
|
|
1556
1941
|
validate(input, existing) {
|
|
1557
1942
|
const errors = [];
|
|
1558
1943
|
const result = {};
|
|
1944
|
+
const piiMode = options.piiEnforcement ?? "none";
|
|
1559
1945
|
if (typeof input !== "object" || input === null) {
|
|
1560
1946
|
return { valid: false, errors: ["Input must be an object"] };
|
|
1561
1947
|
}
|
|
1562
|
-
const working = { ...input };
|
|
1948
|
+
const working = typeof input === "object" && input !== null ? deepClone(input) : { ...input };
|
|
1563
1949
|
if (working.type == null) working.type = entityType;
|
|
1564
1950
|
if (working.version == null) working.version = version;
|
|
1565
1951
|
const fromVersion = String(working.version ?? "0.0.0");
|
|
@@ -1583,11 +1969,17 @@ function createSchema(_shape, entityType, options = {
|
|
|
1583
1969
|
}
|
|
1584
1970
|
for (const key in schema._shape) {
|
|
1585
1971
|
const def = schema._shape[key];
|
|
1586
|
-
|
|
1972
|
+
let value = working[key];
|
|
1973
|
+
const existingField = existing && typeof existing === "object" ? existing[key] : void 0;
|
|
1587
1974
|
if (!def) {
|
|
1588
1975
|
errors.push(`Field definition missing for: ${key}`);
|
|
1589
1976
|
continue;
|
|
1590
1977
|
}
|
|
1978
|
+
const { value: withDefault, applied } = applyDefault(def, value);
|
|
1979
|
+
if (applied) {
|
|
1980
|
+
working[key] = withDefault;
|
|
1981
|
+
value = withDefault;
|
|
1982
|
+
}
|
|
1591
1983
|
const { missing } = checkMissingRequired("", key, value, def, errors);
|
|
1592
1984
|
if (missing) continue;
|
|
1593
1985
|
const { immutableViolation } = checkImmutable(
|
|
@@ -1604,7 +1996,7 @@ function createSchema(_shape, entityType, options = {
|
|
|
1604
1996
|
key,
|
|
1605
1997
|
value,
|
|
1606
1998
|
def,
|
|
1607
|
-
|
|
1999
|
+
piiMode,
|
|
1608
2000
|
errors,
|
|
1609
2001
|
console
|
|
1610
2002
|
);
|
|
@@ -1619,7 +2011,7 @@ function createSchema(_shape, entityType, options = {
|
|
|
1619
2011
|
localErrors
|
|
1620
2012
|
);
|
|
1621
2013
|
if (!invalid) {
|
|
1622
|
-
validateByType("", key, val, def, localErrors);
|
|
2014
|
+
validateByType("", key, val, def, localErrors, existingField, piiMode, console);
|
|
1623
2015
|
}
|
|
1624
2016
|
return localErrors;
|
|
1625
2017
|
};
|
|
@@ -1741,13 +2133,20 @@ function createSchema(_shape, entityType, options = {
|
|
|
1741
2133
|
log?.(`Skipping field ${key} (not in onlyFields)`);
|
|
1742
2134
|
continue;
|
|
1743
2135
|
}
|
|
1744
|
-
const refType = def.refType;
|
|
1745
2136
|
const autoValidate = def.autoValidate !== false;
|
|
1746
2137
|
const refPolicy = def.refPolicy ?? "eager";
|
|
1747
2138
|
const value = entity[key];
|
|
1748
2139
|
if (!value) continue;
|
|
1749
2140
|
if (def.type === "ref") {
|
|
2141
|
+
const refType = def.refType;
|
|
2142
|
+
if (!refType)
|
|
2143
|
+
throw new Error(`Missing refType for reference field ${key}`);
|
|
1750
2144
|
const ref = value;
|
|
2145
|
+
if (ref.type && ref.type !== refType) {
|
|
2146
|
+
throw new Error(
|
|
2147
|
+
`Reference type mismatch for field ${key}: expected ${refType}, got ${ref.type}`
|
|
2148
|
+
);
|
|
2149
|
+
}
|
|
1751
2150
|
const target = await options2.resolveEntity(refType, ref.id);
|
|
1752
2151
|
if (!target)
|
|
1753
2152
|
throw new Error(
|
|
@@ -1764,8 +2163,16 @@ function createSchema(_shape, entityType, options = {
|
|
|
1764
2163
|
}
|
|
1765
2164
|
}
|
|
1766
2165
|
} else if (def.type === "array" && def.itemType?.type === "ref") {
|
|
2166
|
+
const refType = def.itemType.refType;
|
|
2167
|
+
if (!refType)
|
|
2168
|
+
throw new Error(`Missing refType for reference array field ${key}`);
|
|
1767
2169
|
const refs = value;
|
|
1768
2170
|
for (const ref of refs) {
|
|
2171
|
+
if (ref.type && ref.type !== refType) {
|
|
2172
|
+
throw new Error(
|
|
2173
|
+
`Reference type mismatch for field ${key}: expected ${refType}, got ${ref.type}`
|
|
2174
|
+
);
|
|
2175
|
+
}
|
|
1769
2176
|
const target = await options2.resolveEntity(refType, ref.id);
|
|
1770
2177
|
if (!target)
|
|
1771
2178
|
throw new Error(
|
|
@@ -1856,12 +2263,16 @@ function createSchema(_shape, entityType, options = {
|
|
|
1856
2263
|
for (const [key, def] of Object.entries(schema._shape)) {
|
|
1857
2264
|
description[key] = {
|
|
1858
2265
|
type: def.type,
|
|
1859
|
-
optional:
|
|
2266
|
+
optional: isOptional(def),
|
|
2267
|
+
immutable: !!def.isImmutable,
|
|
2268
|
+
system: !!def.isSystem,
|
|
1860
2269
|
description: def._description ?? "",
|
|
1861
2270
|
version: def._version ?? "",
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
2271
|
+
deprecated: def.deprecated ?? false,
|
|
2272
|
+
deprecatedVersion: def.deprecatedVersion === void 0 ? null : def.deprecatedVersion,
|
|
2273
|
+
enum: getEnumValues(def) ?? null,
|
|
2274
|
+
refType: def.refType ?? null,
|
|
2275
|
+
pii: !def._pii || def._pii.classification === "none" ? null : def._pii
|
|
1865
2276
|
};
|
|
1866
2277
|
}
|
|
1867
2278
|
return {
|
|
@@ -1881,6 +2292,20 @@ function getSchemaForType(type) {
|
|
|
1881
2292
|
function getAllSchemas() {
|
|
1882
2293
|
return Array.from(globalSchemaRegistry.values());
|
|
1883
2294
|
}
|
|
2295
|
+
function renderSchemaDescription(schema) {
|
|
2296
|
+
const meta = schema.describe();
|
|
2297
|
+
return {
|
|
2298
|
+
title: `${meta.entityType} (v${meta.version})`,
|
|
2299
|
+
fields: Object.entries(meta.shape).map(([name, def]) => ({
|
|
2300
|
+
name,
|
|
2301
|
+
type: def.type,
|
|
2302
|
+
optional: def.optional,
|
|
2303
|
+
description: def.description,
|
|
2304
|
+
deprecated: def.deprecated,
|
|
2305
|
+
pii: def.pii ? def.pii.classification : void 0
|
|
2306
|
+
}))
|
|
2307
|
+
};
|
|
2308
|
+
}
|
|
1884
2309
|
|
|
1885
2310
|
// src/components.ts
|
|
1886
2311
|
var componentSchemaRegistry = /* @__PURE__ */ new Map();
|
|
@@ -1906,6 +2331,7 @@ function getAllComponentSchemas() {
|
|
|
1906
2331
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1907
2332
|
0 && (module.exports = {
|
|
1908
2333
|
FieldBuilder,
|
|
2334
|
+
IsoLanguageCode,
|
|
1909
2335
|
createComponentSchema,
|
|
1910
2336
|
createSchema,
|
|
1911
2337
|
field,
|
|
@@ -1913,13 +2339,23 @@ function getAllComponentSchemas() {
|
|
|
1913
2339
|
getAllSchemas,
|
|
1914
2340
|
getComponentSchema,
|
|
1915
2341
|
getSchemaForType,
|
|
2342
|
+
isExtensionSingleton,
|
|
2343
|
+
isExtensionSubtag,
|
|
2344
|
+
isIsoLanguageCode,
|
|
2345
|
+
isPrivateUseSingleton,
|
|
2346
|
+
isPrivateUseSubtag,
|
|
2347
|
+
isRegionSubtag,
|
|
2348
|
+
isScriptSubtag,
|
|
2349
|
+
isVariantSubtag,
|
|
1916
2350
|
isoCountryCodes,
|
|
1917
2351
|
isoCurrencyCodes,
|
|
1918
2352
|
registerComponentSchema,
|
|
2353
|
+
renderSchemaDescription,
|
|
1919
2354
|
validateCountryCode,
|
|
1920
2355
|
validateCurrencyCode,
|
|
1921
2356
|
validateDateTimeISO,
|
|
1922
2357
|
validateEmail,
|
|
2358
|
+
validateLanguage,
|
|
1923
2359
|
validateName,
|
|
1924
2360
|
validatePercentage,
|
|
1925
2361
|
validatePhone,
|