@tinacms/schema-tools 0.0.0-e0ddb8c-20241004065742 → 0.0.0-e5c0e91-20250421003142
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.d.ts +1 -6
- package/dist/index.js +191 -156
- package/dist/index.mjs +191 -156
- package/dist/schema/TinaSchema.d.ts +21 -1
- package/dist/schema/addNamespaceToSchema.d.ts +8 -4
- package/dist/types/index.d.ts +13 -5
- package/dist/validate/fields.d.ts +0 -3
- package/dist/validate/schema.d.ts +0 -3
- package/dist/validate/util.d.ts +3 -0
- package/package.json +6 -6
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -20,42 +20,26 @@
|
|
|
20
20
|
}
|
|
21
21
|
const yup__namespace = /* @__PURE__ */ _interopNamespaceDefault(yup);
|
|
22
22
|
function addNamespaceToSchema(maybeNode, namespace = []) {
|
|
23
|
-
if (typeof maybeNode
|
|
23
|
+
if (typeof maybeNode !== "object" || maybeNode === null) {
|
|
24
24
|
return maybeNode;
|
|
25
25
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const keys = Object.keys(maybeNode);
|
|
34
|
-
Object.values(maybeNode).map((m, index) => {
|
|
35
|
-
const key = keys[index];
|
|
36
|
-
if (Array.isArray(m)) {
|
|
37
|
-
newNode[key] = m.map((element) => {
|
|
38
|
-
if (!element) {
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
if (!element.hasOwnProperty("name")) {
|
|
42
|
-
return element;
|
|
26
|
+
const newNode = { ...maybeNode, namespace: [...namespace] };
|
|
27
|
+
Object.entries(maybeNode).forEach(([key, value]) => {
|
|
28
|
+
if (Array.isArray(value)) {
|
|
29
|
+
newNode[key] = value.map((element) => {
|
|
30
|
+
if (element && typeof element === "object" && "name" in element) {
|
|
31
|
+
const valueName = element.name || element.value;
|
|
32
|
+
return addNamespaceToSchema(element, [...namespace, valueName]);
|
|
43
33
|
}
|
|
44
|
-
|
|
45
|
-
return addNamespaceToSchema(element, [...namespace, value]);
|
|
34
|
+
return element;
|
|
46
35
|
});
|
|
36
|
+
} else if (value && typeof value === "object" && "name" in value) {
|
|
37
|
+
newNode[key] = addNamespaceToSchema(value, [...namespace, value.name]);
|
|
47
38
|
} else {
|
|
48
|
-
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
if (!m.hasOwnProperty("name")) {
|
|
52
|
-
newNode[key] = m;
|
|
53
|
-
} else {
|
|
54
|
-
newNode[key] = addNamespaceToSchema(m, [...namespace, m.name]);
|
|
55
|
-
}
|
|
39
|
+
newNode[key] = value;
|
|
56
40
|
}
|
|
57
41
|
});
|
|
58
|
-
return
|
|
42
|
+
return newNode;
|
|
59
43
|
}
|
|
60
44
|
function getDefaultExportFromCjs(x) {
|
|
61
45
|
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
|
|
@@ -1961,7 +1945,7 @@
|
|
|
1961
1945
|
}
|
|
1962
1946
|
}
|
|
1963
1947
|
};
|
|
1964
|
-
this.
|
|
1948
|
+
this.legacyWalkFields = (cb) => {
|
|
1965
1949
|
const walk = (collectionOrObject, collection, path) => {
|
|
1966
1950
|
if (collectionOrObject.templates) {
|
|
1967
1951
|
collectionOrObject.templates.forEach((template) => {
|
|
@@ -1983,7 +1967,7 @@
|
|
|
1983
1967
|
collections.forEach((collection) => walk(collection, collection, []));
|
|
1984
1968
|
};
|
|
1985
1969
|
this.schema = config;
|
|
1986
|
-
this.
|
|
1970
|
+
this.legacyWalkFields(({ field, collection }) => {
|
|
1987
1971
|
if (!("searchable" in field)) {
|
|
1988
1972
|
if (field.type === "image") {
|
|
1989
1973
|
field.searchable = false;
|
|
@@ -2004,6 +1988,67 @@
|
|
|
2004
1988
|
field.uid = field.uid || false;
|
|
2005
1989
|
});
|
|
2006
1990
|
}
|
|
1991
|
+
findReferencesFromCollection(name2) {
|
|
1992
|
+
const result = {};
|
|
1993
|
+
this.walkFields(({ field, collection: c, path }) => {
|
|
1994
|
+
if (c.name !== name2) {
|
|
1995
|
+
return;
|
|
1996
|
+
}
|
|
1997
|
+
if (field.type === "reference") {
|
|
1998
|
+
field.collections.forEach((name22) => {
|
|
1999
|
+
if (result[name22] === void 0) {
|
|
2000
|
+
result[name22] = [];
|
|
2001
|
+
}
|
|
2002
|
+
result[name22].push(path);
|
|
2003
|
+
});
|
|
2004
|
+
}
|
|
2005
|
+
});
|
|
2006
|
+
return result;
|
|
2007
|
+
}
|
|
2008
|
+
/**
|
|
2009
|
+
* Walk all fields in tina schema
|
|
2010
|
+
*
|
|
2011
|
+
* @param cb callback function invoked for each field
|
|
2012
|
+
*/
|
|
2013
|
+
walkFields(cb) {
|
|
2014
|
+
const walk = (collectionOrObject, collection, path = "$") => {
|
|
2015
|
+
if (collectionOrObject.templates) {
|
|
2016
|
+
collectionOrObject.templates.forEach((template) => {
|
|
2017
|
+
const templatePath = `${path}.${template.name}`;
|
|
2018
|
+
template.fields.forEach((field) => {
|
|
2019
|
+
const fieldPath = field.list ? `${templatePath}[*].${field.name}` : `${templatePath}.${field.name}`;
|
|
2020
|
+
cb({ field, collection, path: fieldPath });
|
|
2021
|
+
if (field.type === "object") {
|
|
2022
|
+
walk(field, collection, fieldPath);
|
|
2023
|
+
}
|
|
2024
|
+
});
|
|
2025
|
+
});
|
|
2026
|
+
}
|
|
2027
|
+
if (collectionOrObject.fields) {
|
|
2028
|
+
collectionOrObject.fields.forEach((field) => {
|
|
2029
|
+
const fieldPath = field.list ? `${path}.${field.name}[*]` : `${path}.${field.name}`;
|
|
2030
|
+
cb({ field, collection, path: fieldPath });
|
|
2031
|
+
if (field.type === "object" && field.fields) {
|
|
2032
|
+
walk(field, collection, fieldPath);
|
|
2033
|
+
} else if (field.templates) {
|
|
2034
|
+
field.templates.forEach((template) => {
|
|
2035
|
+
const templatePath = `${fieldPath}.${template.name}`;
|
|
2036
|
+
template.fields.forEach((field2) => {
|
|
2037
|
+
const fieldPath2 = field2.list ? `${templatePath}[*].${field2.name}` : `${templatePath}.${field2.name}`;
|
|
2038
|
+
cb({ field: field2, collection, path: fieldPath2 });
|
|
2039
|
+
if (field2.type === "object") {
|
|
2040
|
+
walk(field2, collection, fieldPath2);
|
|
2041
|
+
}
|
|
2042
|
+
});
|
|
2043
|
+
});
|
|
2044
|
+
}
|
|
2045
|
+
});
|
|
2046
|
+
}
|
|
2047
|
+
};
|
|
2048
|
+
this.getCollections().forEach((collection) => {
|
|
2049
|
+
walk(collection, collection);
|
|
2050
|
+
});
|
|
2051
|
+
}
|
|
2007
2052
|
/**
|
|
2008
2053
|
* This function returns an array of glob matches for a given collection.
|
|
2009
2054
|
*
|
|
@@ -2226,9 +2271,12 @@
|
|
|
2226
2271
|
moreInfo.push(parseZodError({ zodError: unionError }));
|
|
2227
2272
|
});
|
|
2228
2273
|
}
|
|
2229
|
-
const errorMessage =
|
|
2274
|
+
const errorMessage = `${issue == null ? void 0 : issue.message}
|
|
2275
|
+
Additional information:
|
|
2276
|
+
- Error found at path ${issue.path.join(
|
|
2230
2277
|
"."
|
|
2231
|
-
)}
|
|
2278
|
+
)}
|
|
2279
|
+
`;
|
|
2232
2280
|
const errorMessages = [errorMessage, ...moreInfo];
|
|
2233
2281
|
return {
|
|
2234
2282
|
errors: errorMessages
|
|
@@ -2263,6 +2311,9 @@ If you need to use this value in your content you can use the \`nameOverride\` p
|
|
|
2263
2311
|
});
|
|
2264
2312
|
}
|
|
2265
2313
|
});
|
|
2314
|
+
const duplicateFieldErrorMessage = (fields) => `Fields must have unique names. Found duplicate field names: [${fields}]`;
|
|
2315
|
+
const duplicateTemplateErrorMessage = (templates) => `Templates must have unique names. Found duplicate template names: [${templates}]`;
|
|
2316
|
+
const duplicateCollectionErrorMessage = (collection) => `Collections must have unique names. Found duplicate collection names: [${collection}]`;
|
|
2266
2317
|
const TypeName = [
|
|
2267
2318
|
"string",
|
|
2268
2319
|
"boolean",
|
|
@@ -2273,10 +2324,11 @@ If you need to use this value in your content you can use the \`nameOverride\` p
|
|
|
2273
2324
|
"reference",
|
|
2274
2325
|
"rich-text"
|
|
2275
2326
|
];
|
|
2276
|
-
const
|
|
2277
|
-
const
|
|
2278
|
-
|
|
2279
|
-
|
|
2327
|
+
const formattedTypes = ` - ${TypeName.join("\n - ")}`;
|
|
2328
|
+
const typeTypeError = `Invalid \`type\` property. \`type\` expected to be one of the following values:
|
|
2329
|
+
${formattedTypes}`;
|
|
2330
|
+
const typeRequiredError = `Missing \`type\` property. Please add a \`type\` property with one of the following:
|
|
2331
|
+
${formattedTypes}`;
|
|
2280
2332
|
const Option = z.z.union(
|
|
2281
2333
|
[
|
|
2282
2334
|
z.z.string(),
|
|
@@ -2362,7 +2414,7 @@ If you need to use this value in your content you can use the \`nameOverride\` p
|
|
|
2362
2414
|
if (dups) {
|
|
2363
2415
|
ctx.addIssue({
|
|
2364
2416
|
code: z.z.ZodIssueCode.custom,
|
|
2365
|
-
message:
|
|
2417
|
+
message: duplicateFieldErrorMessage(dups)
|
|
2366
2418
|
});
|
|
2367
2419
|
}
|
|
2368
2420
|
});
|
|
@@ -2372,21 +2424,21 @@ If you need to use this value in your content you can use the \`nameOverride\` p
|
|
|
2372
2424
|
invalid_type_error: typeTypeError,
|
|
2373
2425
|
required_error: typeRequiredError
|
|
2374
2426
|
}),
|
|
2375
|
-
fields: z.z.array(TinaFieldZod).min(1).optional().superRefine((val, ctx) => {
|
|
2427
|
+
fields: z.z.array(TinaFieldZod).min(1, "Property `fields` cannot be empty.").optional().superRefine((val, ctx) => {
|
|
2376
2428
|
const dups = findDuplicates(val == null ? void 0 : val.map((x) => x.name));
|
|
2377
2429
|
if (dups) {
|
|
2378
2430
|
ctx.addIssue({
|
|
2379
2431
|
code: z.z.ZodIssueCode.custom,
|
|
2380
|
-
message:
|
|
2432
|
+
message: duplicateFieldErrorMessage(dups)
|
|
2381
2433
|
});
|
|
2382
2434
|
}
|
|
2383
2435
|
}),
|
|
2384
|
-
templates: z.z.array(TemplateTemp).min(1).optional().superRefine((val, ctx) => {
|
|
2436
|
+
templates: z.z.array(TemplateTemp).min(1, "Property `templates` cannot be empty.").optional().superRefine((val, ctx) => {
|
|
2385
2437
|
const dups = findDuplicates(val == null ? void 0 : val.map((x) => x.name));
|
|
2386
2438
|
if (dups) {
|
|
2387
2439
|
ctx.addIssue({
|
|
2388
2440
|
code: z.z.ZodIssueCode.custom,
|
|
2389
|
-
message:
|
|
2441
|
+
message: duplicateTemplateErrorMessage(dups)
|
|
2390
2442
|
});
|
|
2391
2443
|
}
|
|
2392
2444
|
})
|
|
@@ -2401,7 +2453,7 @@ If you need to use this value in your content you can use the \`nameOverride\` p
|
|
|
2401
2453
|
if (dups) {
|
|
2402
2454
|
ctx.addIssue({
|
|
2403
2455
|
code: z.z.ZodIssueCode.custom,
|
|
2404
|
-
message:
|
|
2456
|
+
message: duplicateTemplateErrorMessage(dups)
|
|
2405
2457
|
});
|
|
2406
2458
|
}
|
|
2407
2459
|
})
|
|
@@ -2421,10 +2473,17 @@ If you need to use this value in your content you can use the \`nameOverride\` p
|
|
|
2421
2473
|
],
|
|
2422
2474
|
{
|
|
2423
2475
|
errorMap: (issue, ctx) => {
|
|
2424
|
-
var _a;
|
|
2476
|
+
var _a, _b;
|
|
2425
2477
|
if (issue.code === "invalid_union_discriminator") {
|
|
2478
|
+
if (!((_a = ctx.data) == null ? void 0 : _a.type)) {
|
|
2479
|
+
return {
|
|
2480
|
+
message: `Missing \`type\` property in field \`${ctx.data.name}\`. Please add a \`type\` property with one of the following:
|
|
2481
|
+
${formattedTypes}`
|
|
2482
|
+
};
|
|
2483
|
+
}
|
|
2426
2484
|
return {
|
|
2427
|
-
message: `Invalid \`type\` property. In the schema is 'type: ${(
|
|
2485
|
+
message: `Invalid \`type\` property in field \`${ctx.data.name}\`. In the schema is 'type: ${(_b = ctx.data) == null ? void 0 : _b.type}' but expected one of the following:
|
|
2486
|
+
${formattedTypes}`
|
|
2428
2487
|
};
|
|
2429
2488
|
}
|
|
2430
2489
|
return {
|
|
@@ -2434,77 +2493,52 @@ If you need to use this value in your content you can use the \`nameOverride\` p
|
|
|
2434
2493
|
}
|
|
2435
2494
|
).superRefine((val, ctx) => {
|
|
2436
2495
|
if (val.type === "string") {
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
${
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
ctx.addIssue({
|
|
2452
|
-
code: z.z.ZodIssueCode.custom,
|
|
2453
|
-
message: `Must have { required: true } when using \`isTitle\` Error in value
|
|
2454
|
-
${JSON.stringify(
|
|
2455
|
-
val,
|
|
2456
|
-
null,
|
|
2457
|
-
2
|
|
2458
|
-
)}
|
|
2459
|
-
`
|
|
2460
|
-
});
|
|
2461
|
-
}
|
|
2496
|
+
const stringifiedField = JSON.stringify(val, null, 2);
|
|
2497
|
+
if (val.isTitle && val.list) {
|
|
2498
|
+
ctx.addIssue({
|
|
2499
|
+
code: z.z.ZodIssueCode.custom,
|
|
2500
|
+
message: `\`list: true\` is not allowed when using \`isTitle\` for fields of \`type: string\`. Error found in field:
|
|
2501
|
+
${stringifiedField}`
|
|
2502
|
+
});
|
|
2503
|
+
}
|
|
2504
|
+
if (val.isTitle && !val.required) {
|
|
2505
|
+
ctx.addIssue({
|
|
2506
|
+
code: z.z.ZodIssueCode.custom,
|
|
2507
|
+
message: `Property \`required: true\` is required when using \`isTitle\` for fields of \`type: string\`. Error found in field:
|
|
2508
|
+
${stringifiedField}`
|
|
2509
|
+
});
|
|
2462
2510
|
}
|
|
2463
|
-
if (val.uid) {
|
|
2511
|
+
if (val.uid && val.list) {
|
|
2464
2512
|
if (val.list) {
|
|
2465
2513
|
ctx.addIssue({
|
|
2466
2514
|
code: z.z.ZodIssueCode.custom,
|
|
2467
|
-
message:
|
|
2468
|
-
${
|
|
2469
|
-
val,
|
|
2470
|
-
null,
|
|
2471
|
-
2
|
|
2472
|
-
)}
|
|
2473
|
-
`
|
|
2474
|
-
});
|
|
2475
|
-
}
|
|
2476
|
-
if (!val.required) {
|
|
2477
|
-
ctx.addIssue({
|
|
2478
|
-
code: z.z.ZodIssueCode.custom,
|
|
2479
|
-
message: `Must have { required: true } when using \`uid\` Error in value
|
|
2480
|
-
${JSON.stringify(
|
|
2481
|
-
val,
|
|
2482
|
-
null,
|
|
2483
|
-
2
|
|
2484
|
-
)}
|
|
2485
|
-
`
|
|
2515
|
+
message: `\`list: true\` is not allowed when using \`uid\` for fields of \`type: string\`. Error found in field:
|
|
2516
|
+
${stringifiedField}`
|
|
2486
2517
|
});
|
|
2487
2518
|
}
|
|
2488
2519
|
}
|
|
2520
|
+
if (val.uid && !val.required) {
|
|
2521
|
+
ctx.addIssue({
|
|
2522
|
+
code: z.z.ZodIssueCode.custom,
|
|
2523
|
+
message: `Property \`required: true\` is required when using \`uid\` for fields of \`type: string\`. Error found in field:
|
|
2524
|
+
${stringifiedField}`
|
|
2525
|
+
});
|
|
2526
|
+
}
|
|
2489
2527
|
}
|
|
2490
2528
|
if (val.type === "object") {
|
|
2491
|
-
|
|
2492
|
-
let isValid = Boolean(val == null ? void 0 : val.templates) || Boolean(val == null ? void 0 : val.fields);
|
|
2493
|
-
if (!isValid) {
|
|
2529
|
+
if (!(val == null ? void 0 : val.templates) && !(val == null ? void 0 : val.fields)) {
|
|
2494
2530
|
ctx.addIssue({
|
|
2495
2531
|
code: z.z.ZodIssueCode.custom,
|
|
2496
|
-
message
|
|
2532
|
+
message: "Fields of `type: object` must have either `templates` or `fields` property."
|
|
2533
|
+
});
|
|
2534
|
+
return false;
|
|
2535
|
+
}
|
|
2536
|
+
if ((val == null ? void 0 : val.templates) && (val == null ? void 0 : val.fields)) {
|
|
2537
|
+
ctx.addIssue({
|
|
2538
|
+
code: z.z.ZodIssueCode.custom,
|
|
2539
|
+
message: "Fields of `type: object` must have either `templates` or `fields` property, not both."
|
|
2497
2540
|
});
|
|
2498
2541
|
return false;
|
|
2499
|
-
} else {
|
|
2500
|
-
isValid = !((val == null ? void 0 : val.templates) && (val == null ? void 0 : val.fields));
|
|
2501
|
-
if (!isValid) {
|
|
2502
|
-
ctx.addIssue({
|
|
2503
|
-
code: z.z.ZodIssueCode.custom,
|
|
2504
|
-
message
|
|
2505
|
-
});
|
|
2506
|
-
}
|
|
2507
|
-
return isValid;
|
|
2508
2542
|
}
|
|
2509
2543
|
}
|
|
2510
2544
|
return true;
|
|
@@ -2548,8 +2582,8 @@ ${JSON.stringify(
|
|
|
2548
2582
|
];
|
|
2549
2583
|
const Template = z.z.object({
|
|
2550
2584
|
label: z.z.string({
|
|
2551
|
-
invalid_type_error: "label
|
|
2552
|
-
required_error: "label
|
|
2585
|
+
invalid_type_error: "Invalid data type for property `label`. Must be of type `string`",
|
|
2586
|
+
required_error: "Missing `label` property. Property `label` is required."
|
|
2553
2587
|
}),
|
|
2554
2588
|
name,
|
|
2555
2589
|
fields: z.z.array(TinaFieldZod)
|
|
@@ -2559,7 +2593,7 @@ ${JSON.stringify(
|
|
|
2559
2593
|
if (dups) {
|
|
2560
2594
|
ctx.addIssue({
|
|
2561
2595
|
code: z.z.ZodIssueCode.custom,
|
|
2562
|
-
message:
|
|
2596
|
+
message: duplicateFieldErrorMessage(dups)
|
|
2563
2597
|
});
|
|
2564
2598
|
}
|
|
2565
2599
|
});
|
|
@@ -2569,7 +2603,7 @@ ${JSON.stringify(
|
|
|
2569
2603
|
if (val === "relativePath") {
|
|
2570
2604
|
ctx.addIssue({
|
|
2571
2605
|
code: z.z.ZodIssueCode.custom,
|
|
2572
|
-
message: `name cannot be 'relativePath'
|
|
2606
|
+
message: "Invalid `name` property. `name` cannot be 'relativePath' as it is a reserved field name."
|
|
2573
2607
|
});
|
|
2574
2608
|
}
|
|
2575
2609
|
}),
|
|
@@ -2577,7 +2611,7 @@ ${JSON.stringify(
|
|
|
2577
2611
|
if (val === ".") {
|
|
2578
2612
|
ctx.addIssue({
|
|
2579
2613
|
code: z.z.ZodIssueCode.custom,
|
|
2580
|
-
message: `path cannot be '.'. Please use '/' or '' instead.
|
|
2614
|
+
message: "Invalid `path` property. `path` cannot be '.'. Please use '/' or '' instead."
|
|
2581
2615
|
});
|
|
2582
2616
|
}
|
|
2583
2617
|
}),
|
|
@@ -2586,63 +2620,64 @@ ${JSON.stringify(
|
|
|
2586
2620
|
isDetached: z.z.boolean().optional()
|
|
2587
2621
|
});
|
|
2588
2622
|
const TinaCloudCollection = CollectionBaseSchema.extend({
|
|
2589
|
-
fields: z.z.array(TinaFieldZod).min(1).optional().superRefine((val, ctx) => {
|
|
2623
|
+
fields: z.z.array(TinaFieldZod).min(1, "Property `fields` cannot be empty.").optional().superRefine((val, ctx) => {
|
|
2590
2624
|
const dups = findDuplicates(val == null ? void 0 : val.map((x) => x.name));
|
|
2591
2625
|
if (dups) {
|
|
2592
2626
|
ctx.addIssue({
|
|
2593
2627
|
code: z.z.ZodIssueCode.custom,
|
|
2594
|
-
message:
|
|
2628
|
+
message: duplicateFieldErrorMessage(dups)
|
|
2595
2629
|
});
|
|
2596
2630
|
}
|
|
2597
|
-
}).
|
|
2598
|
-
|
|
2599
|
-
(
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
{
|
|
2613
|
-
message: "Fields can only have one use of `uid`"
|
|
2614
|
-
}
|
|
2615
|
-
).refine(
|
|
2616
|
-
// It is valid if it is 0 or 1
|
|
2617
|
-
(val) => {
|
|
2618
|
-
const arr = (val == null ? void 0 : val.filter((x) => x.type === "password")) || [];
|
|
2619
|
-
return arr.length < 2;
|
|
2620
|
-
},
|
|
2621
|
-
{
|
|
2622
|
-
message: "Fields can only have one use of `password` type"
|
|
2631
|
+
}).superRefine((val, ctx) => {
|
|
2632
|
+
const arr = (val == null ? void 0 : val.filter((x) => x.type === "string" && x.isTitle)) || [];
|
|
2633
|
+
if (arr.length > 1) {
|
|
2634
|
+
ctx.addIssue({
|
|
2635
|
+
code: z.z.ZodIssueCode.custom,
|
|
2636
|
+
message: `The following fields have the property \`isTitle\`: [${arr.map((field) => field.name).join(", ")}]. Only one can contain the property \`isTitle\`.`
|
|
2637
|
+
});
|
|
2638
|
+
}
|
|
2639
|
+
}).superRefine((val, ctx) => {
|
|
2640
|
+
const arr = (val == null ? void 0 : val.filter((x) => x.uid)) || [];
|
|
2641
|
+
if (arr.length > 2) {
|
|
2642
|
+
ctx.addIssue({
|
|
2643
|
+
code: z.z.ZodIssueCode.custom,
|
|
2644
|
+
message: `The following fields have the property \`uid\`: [${arr.map((field) => field.name).join(", ")}]. Only one can contain the property \`uid\`.`
|
|
2645
|
+
});
|
|
2623
2646
|
}
|
|
2624
|
-
),
|
|
2625
|
-
|
|
2647
|
+
}).superRefine((val, ctx) => {
|
|
2648
|
+
const arr = (val == null ? void 0 : val.filter((x) => x.type === "password")) || [];
|
|
2649
|
+
if (arr.length > 2) {
|
|
2650
|
+
ctx.addIssue({
|
|
2651
|
+
code: z.z.ZodIssueCode.custom,
|
|
2652
|
+
message: `The following fields have \`type: password\`: [${arr.map((field) => field.name).join(", ")}]. Only one can be of \`type: password\`.`
|
|
2653
|
+
});
|
|
2654
|
+
}
|
|
2655
|
+
}),
|
|
2656
|
+
templates: z.z.array(Template).min(1, "Property `templates` cannot be empty.").optional().superRefine((val, ctx) => {
|
|
2626
2657
|
const dups = findDuplicates(val == null ? void 0 : val.map((x) => x.name));
|
|
2627
2658
|
if (dups) {
|
|
2628
2659
|
ctx.addIssue({
|
|
2629
2660
|
code: z.z.ZodIssueCode.custom,
|
|
2630
|
-
message:
|
|
2661
|
+
message: duplicateFieldErrorMessage(dups)
|
|
2631
2662
|
});
|
|
2632
2663
|
}
|
|
2633
2664
|
})
|
|
2634
|
-
}).
|
|
2635
|
-
(val)
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
}
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2665
|
+
}).superRefine((val, ctx) => {
|
|
2666
|
+
if (!(val == null ? void 0 : val.templates) && !(val == null ? void 0 : val.fields)) {
|
|
2667
|
+
ctx.addIssue({
|
|
2668
|
+
code: z.z.ZodIssueCode.custom,
|
|
2669
|
+
message: "Fields of `type: object` must have either `templates` or `fields` property."
|
|
2670
|
+
});
|
|
2671
|
+
return false;
|
|
2672
|
+
}
|
|
2673
|
+
if ((val == null ? void 0 : val.templates) && (val == null ? void 0 : val.fields)) {
|
|
2674
|
+
ctx.addIssue({
|
|
2675
|
+
code: z.z.ZodIssueCode.custom,
|
|
2676
|
+
message: "Fields of `type: object` must have either `templates` or `fields` property, not both."
|
|
2677
|
+
});
|
|
2678
|
+
return false;
|
|
2679
|
+
}
|
|
2680
|
+
});
|
|
2646
2681
|
const TinaCloudSchemaZod = z.z.object({
|
|
2647
2682
|
collections: z.z.array(TinaCloudCollection),
|
|
2648
2683
|
config: tinaConfigZod.optional()
|
|
@@ -2652,14 +2687,14 @@ ${JSON.stringify(
|
|
|
2652
2687
|
if (dups) {
|
|
2653
2688
|
ctx.addIssue({
|
|
2654
2689
|
code: z.z.ZodIssueCode.custom,
|
|
2655
|
-
message:
|
|
2690
|
+
message: duplicateCollectionErrorMessage(dups),
|
|
2656
2691
|
fatal: true
|
|
2657
2692
|
});
|
|
2658
2693
|
}
|
|
2659
2694
|
if (((_b = val.collections) == null ? void 0 : _b.filter((x) => x.isAuthCollection).length) > 1) {
|
|
2660
2695
|
ctx.addIssue({
|
|
2661
2696
|
code: z.z.ZodIssueCode.custom,
|
|
2662
|
-
message:
|
|
2697
|
+
message: "Only one collection can be marked as `isAuthCollection`.",
|
|
2663
2698
|
fatal: true
|
|
2664
2699
|
});
|
|
2665
2700
|
}
|
|
@@ -2667,7 +2702,7 @@ ${JSON.stringify(
|
|
|
2667
2702
|
if (media && media.tina && media.loadCustomStore) {
|
|
2668
2703
|
ctx.addIssue({
|
|
2669
2704
|
code: z.z.ZodIssueCode.custom,
|
|
2670
|
-
message: "
|
|
2705
|
+
message: "Cannot have both `loadCustomStore` and `tina`. Must use one or the other.",
|
|
2671
2706
|
fatal: true,
|
|
2672
2707
|
path: ["config", "media"]
|
|
2673
2708
|
});
|
|
@@ -2676,7 +2711,7 @@ ${JSON.stringify(
|
|
|
2676
2711
|
if (search && search.tina && search.searchClient) {
|
|
2677
2712
|
ctx.addIssue({
|
|
2678
2713
|
code: z.z.ZodIssueCode.custom,
|
|
2679
|
-
message: "
|
|
2714
|
+
message: "Cannot have both `searchClient` and `tina`. Must use one or the other.",
|
|
2680
2715
|
fatal: true,
|
|
2681
2716
|
path: ["config", "search"]
|
|
2682
2717
|
});
|
|
@@ -2694,7 +2729,7 @@ ${JSON.stringify(
|
|
|
2694
2729
|
} catch (e) {
|
|
2695
2730
|
if (e instanceof z.ZodError) {
|
|
2696
2731
|
const errors = parseZodError({ zodError: e });
|
|
2697
|
-
throw new TinaSchemaValidationError(errors.join("
|
|
2732
|
+
throw new TinaSchemaValidationError(errors.join("\n"));
|
|
2698
2733
|
}
|
|
2699
2734
|
throw new Error(e);
|
|
2700
2735
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -2,42 +2,26 @@ import * as yup from "yup";
|
|
|
2
2
|
import UrlPattern from "url-pattern";
|
|
3
3
|
import z$1, { z, ZodError } from "zod";
|
|
4
4
|
function addNamespaceToSchema(maybeNode, namespace = []) {
|
|
5
|
-
if (typeof maybeNode
|
|
5
|
+
if (typeof maybeNode !== "object" || maybeNode === null) {
|
|
6
6
|
return maybeNode;
|
|
7
7
|
}
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const keys = Object.keys(maybeNode);
|
|
16
|
-
Object.values(maybeNode).map((m, index) => {
|
|
17
|
-
const key = keys[index];
|
|
18
|
-
if (Array.isArray(m)) {
|
|
19
|
-
newNode[key] = m.map((element) => {
|
|
20
|
-
if (!element) {
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
if (!element.hasOwnProperty("name")) {
|
|
24
|
-
return element;
|
|
8
|
+
const newNode = { ...maybeNode, namespace: [...namespace] };
|
|
9
|
+
Object.entries(maybeNode).forEach(([key, value]) => {
|
|
10
|
+
if (Array.isArray(value)) {
|
|
11
|
+
newNode[key] = value.map((element) => {
|
|
12
|
+
if (element && typeof element === "object" && "name" in element) {
|
|
13
|
+
const valueName = element.name || element.value;
|
|
14
|
+
return addNamespaceToSchema(element, [...namespace, valueName]);
|
|
25
15
|
}
|
|
26
|
-
|
|
27
|
-
return addNamespaceToSchema(element, [...namespace, value]);
|
|
16
|
+
return element;
|
|
28
17
|
});
|
|
18
|
+
} else if (value && typeof value === "object" && "name" in value) {
|
|
19
|
+
newNode[key] = addNamespaceToSchema(value, [...namespace, value.name]);
|
|
29
20
|
} else {
|
|
30
|
-
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
if (!m.hasOwnProperty("name")) {
|
|
34
|
-
newNode[key] = m;
|
|
35
|
-
} else {
|
|
36
|
-
newNode[key] = addNamespaceToSchema(m, [...namespace, m.name]);
|
|
37
|
-
}
|
|
21
|
+
newNode[key] = value;
|
|
38
22
|
}
|
|
39
23
|
});
|
|
40
|
-
return
|
|
24
|
+
return newNode;
|
|
41
25
|
}
|
|
42
26
|
function getDefaultExportFromCjs(x) {
|
|
43
27
|
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
|
|
@@ -1943,7 +1927,7 @@ class TinaSchema {
|
|
|
1943
1927
|
}
|
|
1944
1928
|
}
|
|
1945
1929
|
};
|
|
1946
|
-
this.
|
|
1930
|
+
this.legacyWalkFields = (cb) => {
|
|
1947
1931
|
const walk = (collectionOrObject, collection, path) => {
|
|
1948
1932
|
if (collectionOrObject.templates) {
|
|
1949
1933
|
collectionOrObject.templates.forEach((template) => {
|
|
@@ -1965,7 +1949,7 @@ class TinaSchema {
|
|
|
1965
1949
|
collections.forEach((collection) => walk(collection, collection, []));
|
|
1966
1950
|
};
|
|
1967
1951
|
this.schema = config;
|
|
1968
|
-
this.
|
|
1952
|
+
this.legacyWalkFields(({ field, collection }) => {
|
|
1969
1953
|
if (!("searchable" in field)) {
|
|
1970
1954
|
if (field.type === "image") {
|
|
1971
1955
|
field.searchable = false;
|
|
@@ -1986,6 +1970,67 @@ class TinaSchema {
|
|
|
1986
1970
|
field.uid = field.uid || false;
|
|
1987
1971
|
});
|
|
1988
1972
|
}
|
|
1973
|
+
findReferencesFromCollection(name2) {
|
|
1974
|
+
const result = {};
|
|
1975
|
+
this.walkFields(({ field, collection: c, path }) => {
|
|
1976
|
+
if (c.name !== name2) {
|
|
1977
|
+
return;
|
|
1978
|
+
}
|
|
1979
|
+
if (field.type === "reference") {
|
|
1980
|
+
field.collections.forEach((name22) => {
|
|
1981
|
+
if (result[name22] === void 0) {
|
|
1982
|
+
result[name22] = [];
|
|
1983
|
+
}
|
|
1984
|
+
result[name22].push(path);
|
|
1985
|
+
});
|
|
1986
|
+
}
|
|
1987
|
+
});
|
|
1988
|
+
return result;
|
|
1989
|
+
}
|
|
1990
|
+
/**
|
|
1991
|
+
* Walk all fields in tina schema
|
|
1992
|
+
*
|
|
1993
|
+
* @param cb callback function invoked for each field
|
|
1994
|
+
*/
|
|
1995
|
+
walkFields(cb) {
|
|
1996
|
+
const walk = (collectionOrObject, collection, path = "$") => {
|
|
1997
|
+
if (collectionOrObject.templates) {
|
|
1998
|
+
collectionOrObject.templates.forEach((template) => {
|
|
1999
|
+
const templatePath = `${path}.${template.name}`;
|
|
2000
|
+
template.fields.forEach((field) => {
|
|
2001
|
+
const fieldPath = field.list ? `${templatePath}[*].${field.name}` : `${templatePath}.${field.name}`;
|
|
2002
|
+
cb({ field, collection, path: fieldPath });
|
|
2003
|
+
if (field.type === "object") {
|
|
2004
|
+
walk(field, collection, fieldPath);
|
|
2005
|
+
}
|
|
2006
|
+
});
|
|
2007
|
+
});
|
|
2008
|
+
}
|
|
2009
|
+
if (collectionOrObject.fields) {
|
|
2010
|
+
collectionOrObject.fields.forEach((field) => {
|
|
2011
|
+
const fieldPath = field.list ? `${path}.${field.name}[*]` : `${path}.${field.name}`;
|
|
2012
|
+
cb({ field, collection, path: fieldPath });
|
|
2013
|
+
if (field.type === "object" && field.fields) {
|
|
2014
|
+
walk(field, collection, fieldPath);
|
|
2015
|
+
} else if (field.templates) {
|
|
2016
|
+
field.templates.forEach((template) => {
|
|
2017
|
+
const templatePath = `${fieldPath}.${template.name}`;
|
|
2018
|
+
template.fields.forEach((field2) => {
|
|
2019
|
+
const fieldPath2 = field2.list ? `${templatePath}[*].${field2.name}` : `${templatePath}.${field2.name}`;
|
|
2020
|
+
cb({ field: field2, collection, path: fieldPath2 });
|
|
2021
|
+
if (field2.type === "object") {
|
|
2022
|
+
walk(field2, collection, fieldPath2);
|
|
2023
|
+
}
|
|
2024
|
+
});
|
|
2025
|
+
});
|
|
2026
|
+
}
|
|
2027
|
+
});
|
|
2028
|
+
}
|
|
2029
|
+
};
|
|
2030
|
+
this.getCollections().forEach((collection) => {
|
|
2031
|
+
walk(collection, collection);
|
|
2032
|
+
});
|
|
2033
|
+
}
|
|
1989
2034
|
/**
|
|
1990
2035
|
* This function returns an array of glob matches for a given collection.
|
|
1991
2036
|
*
|
|
@@ -2208,9 +2253,12 @@ const parseZodError = ({ zodError }) => {
|
|
|
2208
2253
|
moreInfo.push(parseZodError({ zodError: unionError }));
|
|
2209
2254
|
});
|
|
2210
2255
|
}
|
|
2211
|
-
const errorMessage =
|
|
2256
|
+
const errorMessage = `${issue == null ? void 0 : issue.message}
|
|
2257
|
+
Additional information:
|
|
2258
|
+
- Error found at path ${issue.path.join(
|
|
2212
2259
|
"."
|
|
2213
|
-
)}
|
|
2260
|
+
)}
|
|
2261
|
+
`;
|
|
2214
2262
|
const errorMessages = [errorMessage, ...moreInfo];
|
|
2215
2263
|
return {
|
|
2216
2264
|
errors: errorMessages
|
|
@@ -2245,6 +2293,9 @@ If you need to use this value in your content you can use the \`nameOverride\` p
|
|
|
2245
2293
|
});
|
|
2246
2294
|
}
|
|
2247
2295
|
});
|
|
2296
|
+
const duplicateFieldErrorMessage = (fields) => `Fields must have unique names. Found duplicate field names: [${fields}]`;
|
|
2297
|
+
const duplicateTemplateErrorMessage = (templates) => `Templates must have unique names. Found duplicate template names: [${templates}]`;
|
|
2298
|
+
const duplicateCollectionErrorMessage = (collection) => `Collections must have unique names. Found duplicate collection names: [${collection}]`;
|
|
2248
2299
|
const TypeName = [
|
|
2249
2300
|
"string",
|
|
2250
2301
|
"boolean",
|
|
@@ -2255,10 +2306,11 @@ const TypeName = [
|
|
|
2255
2306
|
"reference",
|
|
2256
2307
|
"rich-text"
|
|
2257
2308
|
];
|
|
2258
|
-
const
|
|
2259
|
-
const
|
|
2260
|
-
|
|
2261
|
-
|
|
2309
|
+
const formattedTypes = ` - ${TypeName.join("\n - ")}`;
|
|
2310
|
+
const typeTypeError = `Invalid \`type\` property. \`type\` expected to be one of the following values:
|
|
2311
|
+
${formattedTypes}`;
|
|
2312
|
+
const typeRequiredError = `Missing \`type\` property. Please add a \`type\` property with one of the following:
|
|
2313
|
+
${formattedTypes}`;
|
|
2262
2314
|
const Option = z.union(
|
|
2263
2315
|
[
|
|
2264
2316
|
z.string(),
|
|
@@ -2344,7 +2396,7 @@ const TinaFieldZod = z.lazy(() => {
|
|
|
2344
2396
|
if (dups) {
|
|
2345
2397
|
ctx.addIssue({
|
|
2346
2398
|
code: z.ZodIssueCode.custom,
|
|
2347
|
-
message:
|
|
2399
|
+
message: duplicateFieldErrorMessage(dups)
|
|
2348
2400
|
});
|
|
2349
2401
|
}
|
|
2350
2402
|
});
|
|
@@ -2354,21 +2406,21 @@ const TinaFieldZod = z.lazy(() => {
|
|
|
2354
2406
|
invalid_type_error: typeTypeError,
|
|
2355
2407
|
required_error: typeRequiredError
|
|
2356
2408
|
}),
|
|
2357
|
-
fields: z.array(TinaFieldZod).min(1).optional().superRefine((val, ctx) => {
|
|
2409
|
+
fields: z.array(TinaFieldZod).min(1, "Property `fields` cannot be empty.").optional().superRefine((val, ctx) => {
|
|
2358
2410
|
const dups = findDuplicates(val == null ? void 0 : val.map((x) => x.name));
|
|
2359
2411
|
if (dups) {
|
|
2360
2412
|
ctx.addIssue({
|
|
2361
2413
|
code: z.ZodIssueCode.custom,
|
|
2362
|
-
message:
|
|
2414
|
+
message: duplicateFieldErrorMessage(dups)
|
|
2363
2415
|
});
|
|
2364
2416
|
}
|
|
2365
2417
|
}),
|
|
2366
|
-
templates: z.array(TemplateTemp).min(1).optional().superRefine((val, ctx) => {
|
|
2418
|
+
templates: z.array(TemplateTemp).min(1, "Property `templates` cannot be empty.").optional().superRefine((val, ctx) => {
|
|
2367
2419
|
const dups = findDuplicates(val == null ? void 0 : val.map((x) => x.name));
|
|
2368
2420
|
if (dups) {
|
|
2369
2421
|
ctx.addIssue({
|
|
2370
2422
|
code: z.ZodIssueCode.custom,
|
|
2371
|
-
message:
|
|
2423
|
+
message: duplicateTemplateErrorMessage(dups)
|
|
2372
2424
|
});
|
|
2373
2425
|
}
|
|
2374
2426
|
})
|
|
@@ -2383,7 +2435,7 @@ const TinaFieldZod = z.lazy(() => {
|
|
|
2383
2435
|
if (dups) {
|
|
2384
2436
|
ctx.addIssue({
|
|
2385
2437
|
code: z.ZodIssueCode.custom,
|
|
2386
|
-
message:
|
|
2438
|
+
message: duplicateTemplateErrorMessage(dups)
|
|
2387
2439
|
});
|
|
2388
2440
|
}
|
|
2389
2441
|
})
|
|
@@ -2403,10 +2455,17 @@ const TinaFieldZod = z.lazy(() => {
|
|
|
2403
2455
|
],
|
|
2404
2456
|
{
|
|
2405
2457
|
errorMap: (issue, ctx) => {
|
|
2406
|
-
var _a;
|
|
2458
|
+
var _a, _b;
|
|
2407
2459
|
if (issue.code === "invalid_union_discriminator") {
|
|
2460
|
+
if (!((_a = ctx.data) == null ? void 0 : _a.type)) {
|
|
2461
|
+
return {
|
|
2462
|
+
message: `Missing \`type\` property in field \`${ctx.data.name}\`. Please add a \`type\` property with one of the following:
|
|
2463
|
+
${formattedTypes}`
|
|
2464
|
+
};
|
|
2465
|
+
}
|
|
2408
2466
|
return {
|
|
2409
|
-
message: `Invalid \`type\` property. In the schema is 'type: ${(
|
|
2467
|
+
message: `Invalid \`type\` property in field \`${ctx.data.name}\`. In the schema is 'type: ${(_b = ctx.data) == null ? void 0 : _b.type}' but expected one of the following:
|
|
2468
|
+
${formattedTypes}`
|
|
2410
2469
|
};
|
|
2411
2470
|
}
|
|
2412
2471
|
return {
|
|
@@ -2416,77 +2475,52 @@ const TinaFieldZod = z.lazy(() => {
|
|
|
2416
2475
|
}
|
|
2417
2476
|
).superRefine((val, ctx) => {
|
|
2418
2477
|
if (val.type === "string") {
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
${
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
ctx.addIssue({
|
|
2434
|
-
code: z.ZodIssueCode.custom,
|
|
2435
|
-
message: `Must have { required: true } when using \`isTitle\` Error in value
|
|
2436
|
-
${JSON.stringify(
|
|
2437
|
-
val,
|
|
2438
|
-
null,
|
|
2439
|
-
2
|
|
2440
|
-
)}
|
|
2441
|
-
`
|
|
2442
|
-
});
|
|
2443
|
-
}
|
|
2478
|
+
const stringifiedField = JSON.stringify(val, null, 2);
|
|
2479
|
+
if (val.isTitle && val.list) {
|
|
2480
|
+
ctx.addIssue({
|
|
2481
|
+
code: z.ZodIssueCode.custom,
|
|
2482
|
+
message: `\`list: true\` is not allowed when using \`isTitle\` for fields of \`type: string\`. Error found in field:
|
|
2483
|
+
${stringifiedField}`
|
|
2484
|
+
});
|
|
2485
|
+
}
|
|
2486
|
+
if (val.isTitle && !val.required) {
|
|
2487
|
+
ctx.addIssue({
|
|
2488
|
+
code: z.ZodIssueCode.custom,
|
|
2489
|
+
message: `Property \`required: true\` is required when using \`isTitle\` for fields of \`type: string\`. Error found in field:
|
|
2490
|
+
${stringifiedField}`
|
|
2491
|
+
});
|
|
2444
2492
|
}
|
|
2445
|
-
if (val.uid) {
|
|
2493
|
+
if (val.uid && val.list) {
|
|
2446
2494
|
if (val.list) {
|
|
2447
2495
|
ctx.addIssue({
|
|
2448
2496
|
code: z.ZodIssueCode.custom,
|
|
2449
|
-
message:
|
|
2450
|
-
${
|
|
2451
|
-
val,
|
|
2452
|
-
null,
|
|
2453
|
-
2
|
|
2454
|
-
)}
|
|
2455
|
-
`
|
|
2456
|
-
});
|
|
2457
|
-
}
|
|
2458
|
-
if (!val.required) {
|
|
2459
|
-
ctx.addIssue({
|
|
2460
|
-
code: z.ZodIssueCode.custom,
|
|
2461
|
-
message: `Must have { required: true } when using \`uid\` Error in value
|
|
2462
|
-
${JSON.stringify(
|
|
2463
|
-
val,
|
|
2464
|
-
null,
|
|
2465
|
-
2
|
|
2466
|
-
)}
|
|
2467
|
-
`
|
|
2497
|
+
message: `\`list: true\` is not allowed when using \`uid\` for fields of \`type: string\`. Error found in field:
|
|
2498
|
+
${stringifiedField}`
|
|
2468
2499
|
});
|
|
2469
2500
|
}
|
|
2470
2501
|
}
|
|
2502
|
+
if (val.uid && !val.required) {
|
|
2503
|
+
ctx.addIssue({
|
|
2504
|
+
code: z.ZodIssueCode.custom,
|
|
2505
|
+
message: `Property \`required: true\` is required when using \`uid\` for fields of \`type: string\`. Error found in field:
|
|
2506
|
+
${stringifiedField}`
|
|
2507
|
+
});
|
|
2508
|
+
}
|
|
2471
2509
|
}
|
|
2472
2510
|
if (val.type === "object") {
|
|
2473
|
-
|
|
2474
|
-
let isValid = Boolean(val == null ? void 0 : val.templates) || Boolean(val == null ? void 0 : val.fields);
|
|
2475
|
-
if (!isValid) {
|
|
2511
|
+
if (!(val == null ? void 0 : val.templates) && !(val == null ? void 0 : val.fields)) {
|
|
2476
2512
|
ctx.addIssue({
|
|
2477
2513
|
code: z.ZodIssueCode.custom,
|
|
2478
|
-
message
|
|
2514
|
+
message: "Fields of `type: object` must have either `templates` or `fields` property."
|
|
2515
|
+
});
|
|
2516
|
+
return false;
|
|
2517
|
+
}
|
|
2518
|
+
if ((val == null ? void 0 : val.templates) && (val == null ? void 0 : val.fields)) {
|
|
2519
|
+
ctx.addIssue({
|
|
2520
|
+
code: z.ZodIssueCode.custom,
|
|
2521
|
+
message: "Fields of `type: object` must have either `templates` or `fields` property, not both."
|
|
2479
2522
|
});
|
|
2480
2523
|
return false;
|
|
2481
|
-
} else {
|
|
2482
|
-
isValid = !((val == null ? void 0 : val.templates) && (val == null ? void 0 : val.fields));
|
|
2483
|
-
if (!isValid) {
|
|
2484
|
-
ctx.addIssue({
|
|
2485
|
-
code: z.ZodIssueCode.custom,
|
|
2486
|
-
message
|
|
2487
|
-
});
|
|
2488
|
-
}
|
|
2489
|
-
return isValid;
|
|
2490
2524
|
}
|
|
2491
2525
|
}
|
|
2492
2526
|
return true;
|
|
@@ -2530,8 +2564,8 @@ const FORMATS = [
|
|
|
2530
2564
|
];
|
|
2531
2565
|
const Template = z.object({
|
|
2532
2566
|
label: z.string({
|
|
2533
|
-
invalid_type_error: "label
|
|
2534
|
-
required_error: "label
|
|
2567
|
+
invalid_type_error: "Invalid data type for property `label`. Must be of type `string`",
|
|
2568
|
+
required_error: "Missing `label` property. Property `label` is required."
|
|
2535
2569
|
}),
|
|
2536
2570
|
name,
|
|
2537
2571
|
fields: z.array(TinaFieldZod)
|
|
@@ -2541,7 +2575,7 @@ const Template = z.object({
|
|
|
2541
2575
|
if (dups) {
|
|
2542
2576
|
ctx.addIssue({
|
|
2543
2577
|
code: z.ZodIssueCode.custom,
|
|
2544
|
-
message:
|
|
2578
|
+
message: duplicateFieldErrorMessage(dups)
|
|
2545
2579
|
});
|
|
2546
2580
|
}
|
|
2547
2581
|
});
|
|
@@ -2551,7 +2585,7 @@ const CollectionBaseSchema = z.object({
|
|
|
2551
2585
|
if (val === "relativePath") {
|
|
2552
2586
|
ctx.addIssue({
|
|
2553
2587
|
code: z.ZodIssueCode.custom,
|
|
2554
|
-
message: `name cannot be 'relativePath'
|
|
2588
|
+
message: "Invalid `name` property. `name` cannot be 'relativePath' as it is a reserved field name."
|
|
2555
2589
|
});
|
|
2556
2590
|
}
|
|
2557
2591
|
}),
|
|
@@ -2559,7 +2593,7 @@ const CollectionBaseSchema = z.object({
|
|
|
2559
2593
|
if (val === ".") {
|
|
2560
2594
|
ctx.addIssue({
|
|
2561
2595
|
code: z.ZodIssueCode.custom,
|
|
2562
|
-
message: `path cannot be '.'. Please use '/' or '' instead.
|
|
2596
|
+
message: "Invalid `path` property. `path` cannot be '.'. Please use '/' or '' instead."
|
|
2563
2597
|
});
|
|
2564
2598
|
}
|
|
2565
2599
|
}),
|
|
@@ -2568,63 +2602,64 @@ const CollectionBaseSchema = z.object({
|
|
|
2568
2602
|
isDetached: z.boolean().optional()
|
|
2569
2603
|
});
|
|
2570
2604
|
const TinaCloudCollection = CollectionBaseSchema.extend({
|
|
2571
|
-
fields: z.array(TinaFieldZod).min(1).optional().superRefine((val, ctx) => {
|
|
2605
|
+
fields: z.array(TinaFieldZod).min(1, "Property `fields` cannot be empty.").optional().superRefine((val, ctx) => {
|
|
2572
2606
|
const dups = findDuplicates(val == null ? void 0 : val.map((x) => x.name));
|
|
2573
2607
|
if (dups) {
|
|
2574
2608
|
ctx.addIssue({
|
|
2575
2609
|
code: z.ZodIssueCode.custom,
|
|
2576
|
-
message:
|
|
2610
|
+
message: duplicateFieldErrorMessage(dups)
|
|
2577
2611
|
});
|
|
2578
2612
|
}
|
|
2579
|
-
}).
|
|
2580
|
-
|
|
2581
|
-
(
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
{
|
|
2595
|
-
message: "Fields can only have one use of `uid`"
|
|
2596
|
-
}
|
|
2597
|
-
).refine(
|
|
2598
|
-
// It is valid if it is 0 or 1
|
|
2599
|
-
(val) => {
|
|
2600
|
-
const arr = (val == null ? void 0 : val.filter((x) => x.type === "password")) || [];
|
|
2601
|
-
return arr.length < 2;
|
|
2602
|
-
},
|
|
2603
|
-
{
|
|
2604
|
-
message: "Fields can only have one use of `password` type"
|
|
2613
|
+
}).superRefine((val, ctx) => {
|
|
2614
|
+
const arr = (val == null ? void 0 : val.filter((x) => x.type === "string" && x.isTitle)) || [];
|
|
2615
|
+
if (arr.length > 1) {
|
|
2616
|
+
ctx.addIssue({
|
|
2617
|
+
code: z.ZodIssueCode.custom,
|
|
2618
|
+
message: `The following fields have the property \`isTitle\`: [${arr.map((field) => field.name).join(", ")}]. Only one can contain the property \`isTitle\`.`
|
|
2619
|
+
});
|
|
2620
|
+
}
|
|
2621
|
+
}).superRefine((val, ctx) => {
|
|
2622
|
+
const arr = (val == null ? void 0 : val.filter((x) => x.uid)) || [];
|
|
2623
|
+
if (arr.length > 2) {
|
|
2624
|
+
ctx.addIssue({
|
|
2625
|
+
code: z.ZodIssueCode.custom,
|
|
2626
|
+
message: `The following fields have the property \`uid\`: [${arr.map((field) => field.name).join(", ")}]. Only one can contain the property \`uid\`.`
|
|
2627
|
+
});
|
|
2605
2628
|
}
|
|
2606
|
-
),
|
|
2607
|
-
|
|
2629
|
+
}).superRefine((val, ctx) => {
|
|
2630
|
+
const arr = (val == null ? void 0 : val.filter((x) => x.type === "password")) || [];
|
|
2631
|
+
if (arr.length > 2) {
|
|
2632
|
+
ctx.addIssue({
|
|
2633
|
+
code: z.ZodIssueCode.custom,
|
|
2634
|
+
message: `The following fields have \`type: password\`: [${arr.map((field) => field.name).join(", ")}]. Only one can be of \`type: password\`.`
|
|
2635
|
+
});
|
|
2636
|
+
}
|
|
2637
|
+
}),
|
|
2638
|
+
templates: z.array(Template).min(1, "Property `templates` cannot be empty.").optional().superRefine((val, ctx) => {
|
|
2608
2639
|
const dups = findDuplicates(val == null ? void 0 : val.map((x) => x.name));
|
|
2609
2640
|
if (dups) {
|
|
2610
2641
|
ctx.addIssue({
|
|
2611
2642
|
code: z.ZodIssueCode.custom,
|
|
2612
|
-
message:
|
|
2643
|
+
message: duplicateFieldErrorMessage(dups)
|
|
2613
2644
|
});
|
|
2614
2645
|
}
|
|
2615
2646
|
})
|
|
2616
|
-
}).
|
|
2617
|
-
(val)
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
}
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2647
|
+
}).superRefine((val, ctx) => {
|
|
2648
|
+
if (!(val == null ? void 0 : val.templates) && !(val == null ? void 0 : val.fields)) {
|
|
2649
|
+
ctx.addIssue({
|
|
2650
|
+
code: z.ZodIssueCode.custom,
|
|
2651
|
+
message: "Fields of `type: object` must have either `templates` or `fields` property."
|
|
2652
|
+
});
|
|
2653
|
+
return false;
|
|
2654
|
+
}
|
|
2655
|
+
if ((val == null ? void 0 : val.templates) && (val == null ? void 0 : val.fields)) {
|
|
2656
|
+
ctx.addIssue({
|
|
2657
|
+
code: z.ZodIssueCode.custom,
|
|
2658
|
+
message: "Fields of `type: object` must have either `templates` or `fields` property, not both."
|
|
2659
|
+
});
|
|
2660
|
+
return false;
|
|
2661
|
+
}
|
|
2662
|
+
});
|
|
2628
2663
|
const TinaCloudSchemaZod = z.object({
|
|
2629
2664
|
collections: z.array(TinaCloudCollection),
|
|
2630
2665
|
config: tinaConfigZod.optional()
|
|
@@ -2634,14 +2669,14 @@ const TinaCloudSchemaZod = z.object({
|
|
|
2634
2669
|
if (dups) {
|
|
2635
2670
|
ctx.addIssue({
|
|
2636
2671
|
code: z.ZodIssueCode.custom,
|
|
2637
|
-
message:
|
|
2672
|
+
message: duplicateCollectionErrorMessage(dups),
|
|
2638
2673
|
fatal: true
|
|
2639
2674
|
});
|
|
2640
2675
|
}
|
|
2641
2676
|
if (((_b = val.collections) == null ? void 0 : _b.filter((x) => x.isAuthCollection).length) > 1) {
|
|
2642
2677
|
ctx.addIssue({
|
|
2643
2678
|
code: z.ZodIssueCode.custom,
|
|
2644
|
-
message:
|
|
2679
|
+
message: "Only one collection can be marked as `isAuthCollection`.",
|
|
2645
2680
|
fatal: true
|
|
2646
2681
|
});
|
|
2647
2682
|
}
|
|
@@ -2649,7 +2684,7 @@ const TinaCloudSchemaZod = z.object({
|
|
|
2649
2684
|
if (media && media.tina && media.loadCustomStore) {
|
|
2650
2685
|
ctx.addIssue({
|
|
2651
2686
|
code: z.ZodIssueCode.custom,
|
|
2652
|
-
message: "
|
|
2687
|
+
message: "Cannot have both `loadCustomStore` and `tina`. Must use one or the other.",
|
|
2653
2688
|
fatal: true,
|
|
2654
2689
|
path: ["config", "media"]
|
|
2655
2690
|
});
|
|
@@ -2658,7 +2693,7 @@ const TinaCloudSchemaZod = z.object({
|
|
|
2658
2693
|
if (search && search.tina && search.searchClient) {
|
|
2659
2694
|
ctx.addIssue({
|
|
2660
2695
|
code: z.ZodIssueCode.custom,
|
|
2661
|
-
message: "
|
|
2696
|
+
message: "Cannot have both `searchClient` and `tina`. Must use one or the other.",
|
|
2662
2697
|
fatal: true,
|
|
2663
2698
|
path: ["config", "search"]
|
|
2664
2699
|
});
|
|
@@ -2676,7 +2711,7 @@ const validateSchema = ({ schema }) => {
|
|
|
2676
2711
|
} catch (e) {
|
|
2677
2712
|
if (e instanceof ZodError) {
|
|
2678
2713
|
const errors = parseZodError({ zodError: e });
|
|
2679
|
-
throw new TinaSchemaValidationError(errors.join("
|
|
2714
|
+
throw new TinaSchemaValidationError(errors.join("\n"));
|
|
2680
2715
|
}
|
|
2681
2716
|
throw new Error(e);
|
|
2682
2717
|
}
|
|
@@ -28,6 +28,7 @@ export declare class TinaSchema {
|
|
|
28
28
|
} & Schema);
|
|
29
29
|
getIsTitleFieldName: (collection: string) => string;
|
|
30
30
|
getCollectionsByName: (collectionNames: string[]) => Collection<true>[];
|
|
31
|
+
findReferencesFromCollection(name: string): Record<string, string[]>;
|
|
31
32
|
getCollection: (collectionName: string) => Collection<true>;
|
|
32
33
|
getCollections: () => Collection<true>[];
|
|
33
34
|
getCollectionByFullPath: (filepath: string) => Collection<true>;
|
|
@@ -59,7 +60,26 @@ export declare class TinaSchema {
|
|
|
59
60
|
*
|
|
60
61
|
*/
|
|
61
62
|
getTemplatesForCollectable: (collection: Collectable) => CollectionTemplateable;
|
|
62
|
-
|
|
63
|
+
/**
|
|
64
|
+
* Walk all fields in tina schema
|
|
65
|
+
*
|
|
66
|
+
* @param cb callback function invoked for each field
|
|
67
|
+
*/
|
|
68
|
+
walkFields(cb: (args: {
|
|
69
|
+
field: any;
|
|
70
|
+
collection: any;
|
|
71
|
+
path: string;
|
|
72
|
+
isListItem?: boolean;
|
|
73
|
+
}) => void): void;
|
|
74
|
+
/**
|
|
75
|
+
* Walk all fields in Tina Schema
|
|
76
|
+
*
|
|
77
|
+
* This is a legacy version to preserve backwards compatibility for the tina generated schema. It does not
|
|
78
|
+
* traverse fields in object lists in rich-text templates.
|
|
79
|
+
*
|
|
80
|
+
* @param cb callback function invoked for each field
|
|
81
|
+
*/
|
|
82
|
+
legacyWalkFields: (cb: (args: {
|
|
63
83
|
field: TinaField;
|
|
64
84
|
collection: Collection;
|
|
65
85
|
path: string[];
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
type Node = {
|
|
2
|
+
name?: string;
|
|
3
|
+
value?: string;
|
|
4
|
+
namespace?: string[];
|
|
5
|
+
[key: string]: any;
|
|
6
|
+
};
|
|
7
|
+
export declare function addNamespaceToSchema<T extends Node | string>(maybeNode: T, namespace?: string[]): T;
|
|
8
|
+
export {};
|
package/dist/types/index.d.ts
CHANGED
|
@@ -185,7 +185,7 @@ export type ReferenceField = (FieldGeneric<string, undefined, ReferenceFieldOpti
|
|
|
185
185
|
export type PasswordField = (FieldGeneric<string, undefined> | FieldGeneric<string, false>) & BaseField & {
|
|
186
186
|
type: 'password';
|
|
187
187
|
};
|
|
188
|
-
type
|
|
188
|
+
type ToolbarOverrideType = 'heading' | 'link' | 'image' | 'quote' | 'ul' | 'ol' | 'code' | 'codeBlock' | 'bold' | 'italic' | 'raw' | 'embed' | 'mermaid' | 'table';
|
|
189
189
|
type RichTextAst = {
|
|
190
190
|
type: 'root';
|
|
191
191
|
children: Record<string, unknown>[];
|
|
@@ -198,8 +198,14 @@ export type RichTextField<WithNamespace extends boolean = false> = (FieldGeneric
|
|
|
198
198
|
* will be stored as frontmatter
|
|
199
199
|
*/
|
|
200
200
|
isBody?: boolean;
|
|
201
|
-
|
|
201
|
+
/**@deprecated use overrides.toolbar */
|
|
202
|
+
toolbarOverride?: ToolbarOverrideType[];
|
|
202
203
|
templates?: RichTextTemplate<WithNamespace>[];
|
|
204
|
+
overrides?: {
|
|
205
|
+
toolbar?: ToolbarOverrideType[];
|
|
206
|
+
/**Default set to true */
|
|
207
|
+
showFloatingToolbar?: boolean;
|
|
208
|
+
};
|
|
203
209
|
/**
|
|
204
210
|
* By default, Tina parses markdown with MDX, this is a more strict parser
|
|
205
211
|
* that allows you to use structured content inside markdown (via `templates`).
|
|
@@ -357,6 +363,7 @@ interface AuthHooks {
|
|
|
357
363
|
type AuthOptions = AuthHooks & AuthProvider;
|
|
358
364
|
export interface Config<CMSCallback = undefined, FormifyCallback = undefined, DocumentCreatorCallback = undefined, Store = undefined, SearchClient = undefined> {
|
|
359
365
|
contentApiUrlOverride?: string;
|
|
366
|
+
oauth2?: boolean;
|
|
360
367
|
authProvider?: AuthProvider;
|
|
361
368
|
admin?: {
|
|
362
369
|
/**
|
|
@@ -394,7 +401,7 @@ export interface Config<CMSCallback = undefined, FormifyCallback = undefined, Do
|
|
|
394
401
|
token?: string | null;
|
|
395
402
|
ui?: {
|
|
396
403
|
/**
|
|
397
|
-
* When using
|
|
404
|
+
* When using TinaCloud's branching feature, provide the URL for your given branch
|
|
398
405
|
*
|
|
399
406
|
* Eg. If you're deplying to Vercel, and your repo name is 'my-app',
|
|
400
407
|
* Vercel's preview URL would be based on the branch:
|
|
@@ -521,7 +528,7 @@ export interface Config<CMSCallback = undefined, FormifyCallback = undefined, Do
|
|
|
521
528
|
} | {
|
|
522
529
|
searchClient?: never;
|
|
523
530
|
/**
|
|
524
|
-
* Use the
|
|
531
|
+
* Use the TinaCloud search index
|
|
525
532
|
*/
|
|
526
533
|
tina: {
|
|
527
534
|
/**
|
|
@@ -548,7 +555,7 @@ export interface Config<CMSCallback = undefined, FormifyCallback = undefined, Do
|
|
|
548
555
|
maxSearchIndexFieldLength?: number;
|
|
549
556
|
};
|
|
550
557
|
/**
|
|
551
|
-
* Used to override the default
|
|
558
|
+
* Used to override the default TinaCloud API URL
|
|
552
559
|
*
|
|
553
560
|
* [mostly for internal use only]
|
|
554
561
|
*/
|
|
@@ -630,6 +637,7 @@ type Document = {
|
|
|
630
637
|
relativePath: string;
|
|
631
638
|
filename: string;
|
|
632
639
|
extension: string;
|
|
640
|
+
hasReferences?: boolean;
|
|
633
641
|
};
|
|
634
642
|
};
|
|
635
643
|
export interface UICollection<Form = any, CMS = any, TinaForm = any> {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tinacms/schema-tools",
|
|
3
|
-
"version": "0.0.0-
|
|
3
|
+
"version": "0.0.0-e5c0e91-20250421003142",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"module": "./dist/index.mjs",
|
|
6
6
|
"exports": {
|
|
@@ -23,16 +23,16 @@
|
|
|
23
23
|
]
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
|
-
"@types/jest": "^29.5.
|
|
26
|
+
"@types/jest": "^29.5.14",
|
|
27
27
|
"@types/micromatch": "^4.0.9",
|
|
28
|
-
"@types/react": "^18.3.
|
|
28
|
+
"@types/react": "^18.3.18",
|
|
29
29
|
"@types/yup": "^0.29.14",
|
|
30
30
|
"jest": "^29.7.0",
|
|
31
31
|
"react": "^18.3.1",
|
|
32
32
|
"ts-jest": "^29.2.5",
|
|
33
|
-
"typescript": "^5.
|
|
33
|
+
"typescript": "^5.7.3",
|
|
34
34
|
"yup": "^0.32.11",
|
|
35
|
-
"@tinacms/scripts": "1.
|
|
35
|
+
"@tinacms/scripts": "1.3.4"
|
|
36
36
|
},
|
|
37
37
|
"peerDependencies": {
|
|
38
38
|
"react": ">=16.14.0",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"dependencies": {
|
|
49
49
|
"picomatch-browser": "2.2.6",
|
|
50
50
|
"url-pattern": "^1.0.3",
|
|
51
|
-
"zod": "^3.
|
|
51
|
+
"zod": "^3.24.2"
|
|
52
52
|
},
|
|
53
53
|
"scripts": {
|
|
54
54
|
"build": "tinacms-scripts build",
|