@tinacms/schema-tools 0.0.0-e70425b-20241028042614 → 0.0.0-e999254-20250610011143

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.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 === "string") {
23
+ if (typeof maybeNode !== "object" || maybeNode === null) {
24
24
  return maybeNode;
25
25
  }
26
- if (typeof maybeNode === "boolean") {
27
- return maybeNode;
28
- }
29
- if (typeof maybeNode === "function") {
30
- return maybeNode;
31
- }
32
- const newNode = { ...maybeNode };
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
- const value = element.name || element.value;
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
- if (!m) {
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 { ...newNode, namespace };
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;
@@ -1680,6 +1664,9 @@
1680
1664
  };
1681
1665
  };
1682
1666
  const normalizePath = (filepath) => filepath.replace(/\\/g, "/");
1667
+ const canonicalPath = (filepath) => {
1668
+ return normalizePath(filepath).split("/").filter((name2) => name2 !== "").join("/");
1669
+ };
1683
1670
  class TinaSchema {
1684
1671
  /**
1685
1672
  * Create a schema class from a user defined schema object
@@ -1729,21 +1716,21 @@
1729
1716
  };
1730
1717
  this.getCollectionByFullPath = (filepath) => {
1731
1718
  const fileExtension = filepath.split(".").pop();
1732
- const normalizedPath = filepath.replace(/\\/g, "/");
1719
+ const canonicalFilepath = canonicalPath(filepath);
1733
1720
  const possibleCollections = this.getCollections().filter((collection) => {
1734
1721
  var _a, _b;
1735
- if (!normalizedPath.endsWith(`.gitkeep.${collection.format || "md"}`) && fileExtension !== (collection.format || "md")) {
1722
+ if (!canonicalFilepath.endsWith(`.gitkeep.${collection.format || "md"}`) && fileExtension !== (collection.format || "md")) {
1736
1723
  return false;
1737
1724
  }
1738
1725
  if (((_a = collection == null ? void 0 : collection.match) == null ? void 0 : _a.include) || ((_b = collection == null ? void 0 : collection.match) == null ? void 0 : _b.exclude)) {
1739
1726
  const matches = this.getMatches({ collection });
1740
- const match = picomatch$1.isMatch(normalizedPath, matches);
1727
+ const match = picomatch$1.isMatch(canonicalFilepath, matches);
1741
1728
  if (!match) {
1742
1729
  return false;
1743
1730
  }
1744
1731
  }
1745
- const path = collection.path ? collection.path.replace(/\/?$/, "/") : "";
1746
- return normalizedPath.startsWith(path);
1732
+ const collectionPath = canonicalPath(collection.path);
1733
+ return collectionPath === "" || canonicalFilepath.startsWith(`${collectionPath}/`);
1747
1734
  });
1748
1735
  if (possibleCollections.length === 0) {
1749
1736
  throw new Error(`Unable to find collection for file at ${filepath}`);
@@ -1961,7 +1948,7 @@
1961
1948
  }
1962
1949
  }
1963
1950
  };
1964
- this.walkFields = (cb) => {
1951
+ this.legacyWalkFields = (cb) => {
1965
1952
  const walk = (collectionOrObject, collection, path) => {
1966
1953
  if (collectionOrObject.templates) {
1967
1954
  collectionOrObject.templates.forEach((template) => {
@@ -1983,7 +1970,7 @@
1983
1970
  collections.forEach((collection) => walk(collection, collection, []));
1984
1971
  };
1985
1972
  this.schema = config;
1986
- this.walkFields(({ field, collection, path }) => {
1973
+ this.legacyWalkFields(({ field, collection }) => {
1987
1974
  if (!("searchable" in field)) {
1988
1975
  if (field.type === "image") {
1989
1976
  field.searchable = false;
@@ -2004,6 +1991,67 @@
2004
1991
  field.uid = field.uid || false;
2005
1992
  });
2006
1993
  }
1994
+ findReferencesFromCollection(name2) {
1995
+ const result = {};
1996
+ this.walkFields(({ field, collection: c, path }) => {
1997
+ if (c.name !== name2) {
1998
+ return;
1999
+ }
2000
+ if (field.type === "reference") {
2001
+ field.collections.forEach((name22) => {
2002
+ if (result[name22] === void 0) {
2003
+ result[name22] = [];
2004
+ }
2005
+ result[name22].push(path);
2006
+ });
2007
+ }
2008
+ });
2009
+ return result;
2010
+ }
2011
+ /**
2012
+ * Walk all fields in tina schema
2013
+ *
2014
+ * @param cb callback function invoked for each field
2015
+ */
2016
+ walkFields(cb) {
2017
+ const walk = (collectionOrObject, collection, path = "$") => {
2018
+ if (collectionOrObject.templates) {
2019
+ collectionOrObject.templates.forEach((template) => {
2020
+ const templatePath = `${path}.${template.name}`;
2021
+ template.fields.forEach((field) => {
2022
+ const fieldPath = field.list ? `${templatePath}[*].${field.name}` : `${templatePath}.${field.name}`;
2023
+ cb({ field, collection, path: fieldPath });
2024
+ if (field.type === "object") {
2025
+ walk(field, collection, fieldPath);
2026
+ }
2027
+ });
2028
+ });
2029
+ }
2030
+ if (collectionOrObject.fields) {
2031
+ collectionOrObject.fields.forEach((field) => {
2032
+ const fieldPath = field.list ? `${path}.${field.name}[*]` : `${path}.${field.name}`;
2033
+ cb({ field, collection, path: fieldPath });
2034
+ if (field.type === "object" && field.fields) {
2035
+ walk(field, collection, fieldPath);
2036
+ } else if (field.templates) {
2037
+ field.templates.forEach((template) => {
2038
+ const templatePath = `${fieldPath}.${template.name}`;
2039
+ template.fields.forEach((field2) => {
2040
+ const fieldPath2 = field2.list ? `${templatePath}[*].${field2.name}` : `${templatePath}.${field2.name}`;
2041
+ cb({ field: field2, collection, path: fieldPath2 });
2042
+ if (field2.type === "object") {
2043
+ walk(field2, collection, fieldPath2);
2044
+ }
2045
+ });
2046
+ });
2047
+ }
2048
+ });
2049
+ }
2050
+ };
2051
+ this.getCollections().forEach((collection) => {
2052
+ walk(collection, collection);
2053
+ });
2054
+ }
2007
2055
  /**
2008
2056
  * This function returns an array of glob matches for a given collection.
2009
2057
  *
@@ -2015,16 +2063,16 @@
2015
2063
  }) {
2016
2064
  var _a, _b;
2017
2065
  const collection = typeof collectionOrString === "string" ? this.getCollection(collectionOrString) : collectionOrString;
2018
- const normalPath = normalizePath(collection.path);
2019
- const pathSuffix = normalPath ? "/" : "";
2066
+ const collectionPath = canonicalPath(collection.path);
2067
+ const pathSuffix = collectionPath ? "/" : "";
2020
2068
  const format = collection.format || "md";
2021
2069
  const matches = [];
2022
2070
  if ((_a = collection == null ? void 0 : collection.match) == null ? void 0 : _a.include) {
2023
- const match = `${normalPath}${pathSuffix}${collection.match.include}.${format}`;
2071
+ const match = `${collectionPath}${pathSuffix}${collection.match.include}.${format}`;
2024
2072
  matches.push(match);
2025
2073
  }
2026
2074
  if ((_b = collection == null ? void 0 : collection.match) == null ? void 0 : _b.exclude) {
2027
- const exclude = `!(${normalPath}${pathSuffix}${collection.match.exclude}.${format})`;
2075
+ const exclude = `!(${collectionPath}${pathSuffix}${collection.match.exclude}.${format})`;
2028
2076
  matches.push(exclude);
2029
2077
  }
2030
2078
  return matches;
@@ -2217,6 +2265,15 @@
2217
2265
  })
2218
2266
  };
2219
2267
  };
2268
+ const CONTENT_FORMATS = [
2269
+ "mdx",
2270
+ "md",
2271
+ "markdown",
2272
+ "json",
2273
+ "yaml",
2274
+ "yml",
2275
+ "toml"
2276
+ ];
2220
2277
  const parseZodError = ({ zodError }) => {
2221
2278
  var _a, _b, _c, _d;
2222
2279
  const errors = zodError.flatten((issue) => {
@@ -2226,9 +2283,12 @@
2226
2283
  moreInfo.push(parseZodError({ zodError: unionError }));
2227
2284
  });
2228
2285
  }
2229
- const errorMessage = `Error ${issue == null ? void 0 : issue.message} at path ${issue.path.join(
2286
+ const errorMessage = `${issue == null ? void 0 : issue.message}
2287
+ Additional information:
2288
+ - Error found at path ${issue.path.join(
2230
2289
  "."
2231
- )}`;
2290
+ )}
2291
+ `;
2232
2292
  const errorMessages = [errorMessage, ...moreInfo];
2233
2293
  return {
2234
2294
  errors: errorMessages
@@ -2263,6 +2323,9 @@ If you need to use this value in your content you can use the \`nameOverride\` p
2263
2323
  });
2264
2324
  }
2265
2325
  });
2326
+ const duplicateFieldErrorMessage = (fields) => `Fields must have unique names. Found duplicate field names: [${fields}]`;
2327
+ const duplicateTemplateErrorMessage = (templates) => `Templates must have unique names. Found duplicate template names: [${templates}]`;
2328
+ const duplicateCollectionErrorMessage = (collection) => `Collections must have unique names. Found duplicate collection names: [${collection}]`;
2266
2329
  const TypeName = [
2267
2330
  "string",
2268
2331
  "boolean",
@@ -2273,10 +2336,11 @@ If you need to use this value in your content you can use the \`nameOverride\` p
2273
2336
  "reference",
2274
2337
  "rich-text"
2275
2338
  ];
2276
- const typeTypeError = `type must be one of ${TypeName.join(", ")}`;
2277
- const typeRequiredError = `type is required and must be one of ${TypeName.join(
2278
- ", "
2279
- )}`;
2339
+ const formattedTypes = ` - ${TypeName.join("\n - ")}`;
2340
+ const typeTypeError = `Invalid \`type\` property. \`type\` expected to be one of the following values:
2341
+ ${formattedTypes}`;
2342
+ const typeRequiredError = `Missing \`type\` property. Please add a \`type\` property with one of the following:
2343
+ ${formattedTypes}`;
2280
2344
  const Option = z.z.union(
2281
2345
  [
2282
2346
  z.z.string(),
@@ -2362,7 +2426,7 @@ If you need to use this value in your content you can use the \`nameOverride\` p
2362
2426
  if (dups) {
2363
2427
  ctx.addIssue({
2364
2428
  code: z.z.ZodIssueCode.custom,
2365
- message: `Fields must have a unique name, duplicate field names: ${dups}`
2429
+ message: duplicateFieldErrorMessage(dups)
2366
2430
  });
2367
2431
  }
2368
2432
  });
@@ -2372,21 +2436,21 @@ If you need to use this value in your content you can use the \`nameOverride\` p
2372
2436
  invalid_type_error: typeTypeError,
2373
2437
  required_error: typeRequiredError
2374
2438
  }),
2375
- fields: z.z.array(TinaFieldZod).min(1).optional().superRefine((val, ctx) => {
2439
+ fields: z.z.array(TinaFieldZod).min(1, "Property `fields` cannot be empty.").optional().superRefine((val, ctx) => {
2376
2440
  const dups = findDuplicates(val == null ? void 0 : val.map((x) => x.name));
2377
2441
  if (dups) {
2378
2442
  ctx.addIssue({
2379
2443
  code: z.z.ZodIssueCode.custom,
2380
- message: `Fields must have a unique name, duplicate field names: ${dups}`
2444
+ message: duplicateFieldErrorMessage(dups)
2381
2445
  });
2382
2446
  }
2383
2447
  }),
2384
- templates: z.z.array(TemplateTemp).min(1).optional().superRefine((val, ctx) => {
2448
+ templates: z.z.array(TemplateTemp).min(1, "Property `templates` cannot be empty.").optional().superRefine((val, ctx) => {
2385
2449
  const dups = findDuplicates(val == null ? void 0 : val.map((x) => x.name));
2386
2450
  if (dups) {
2387
2451
  ctx.addIssue({
2388
2452
  code: z.z.ZodIssueCode.custom,
2389
- message: `Templates must have a unique name, duplicate template names: ${dups}`
2453
+ message: duplicateTemplateErrorMessage(dups)
2390
2454
  });
2391
2455
  }
2392
2456
  })
@@ -2401,7 +2465,7 @@ If you need to use this value in your content you can use the \`nameOverride\` p
2401
2465
  if (dups) {
2402
2466
  ctx.addIssue({
2403
2467
  code: z.z.ZodIssueCode.custom,
2404
- message: `Templates must have a unique name, duplicate template names: ${dups}`
2468
+ message: duplicateTemplateErrorMessage(dups)
2405
2469
  });
2406
2470
  }
2407
2471
  })
@@ -2421,10 +2485,17 @@ If you need to use this value in your content you can use the \`nameOverride\` p
2421
2485
  ],
2422
2486
  {
2423
2487
  errorMap: (issue, ctx) => {
2424
- var _a;
2488
+ var _a, _b;
2425
2489
  if (issue.code === "invalid_union_discriminator") {
2490
+ if (!((_a = ctx.data) == null ? void 0 : _a.type)) {
2491
+ return {
2492
+ message: `Missing \`type\` property in field \`${ctx.data.name}\`. Please add a \`type\` property with one of the following:
2493
+ ${formattedTypes}`
2494
+ };
2495
+ }
2426
2496
  return {
2427
- message: `Invalid \`type\` property. In the schema is 'type: ${(_a = ctx.data) == null ? void 0 : _a.type}' and expected one of ${TypeName.join(", ")}`
2497
+ 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:
2498
+ ${formattedTypes}`
2428
2499
  };
2429
2500
  }
2430
2501
  return {
@@ -2434,77 +2505,52 @@ If you need to use this value in your content you can use the \`nameOverride\` p
2434
2505
  }
2435
2506
  ).superRefine((val, ctx) => {
2436
2507
  if (val.type === "string") {
2437
- if (val.isTitle) {
2438
- if (val.list) {
2439
- ctx.addIssue({
2440
- code: z.z.ZodIssueCode.custom,
2441
- message: `Can not have \`list: true\` when using \`isTitle\`. Error in value
2442
- ${JSON.stringify(
2443
- val,
2444
- null,
2445
- 2
2446
- )}
2447
- `
2448
- });
2449
- }
2450
- if (!val.required) {
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
- }
2508
+ const stringifiedField = JSON.stringify(val, null, 2);
2509
+ if (val.isTitle && val.list) {
2510
+ ctx.addIssue({
2511
+ code: z.z.ZodIssueCode.custom,
2512
+ message: `\`list: true\` is not allowed when using \`isTitle\` for fields of \`type: string\`. Error found in field:
2513
+ ${stringifiedField}`
2514
+ });
2515
+ }
2516
+ if (val.isTitle && !val.required) {
2517
+ ctx.addIssue({
2518
+ code: z.z.ZodIssueCode.custom,
2519
+ message: `Property \`required: true\` is required when using \`isTitle\` for fields of \`type: string\`. Error found in field:
2520
+ ${stringifiedField}`
2521
+ });
2462
2522
  }
2463
- if (val.uid) {
2523
+ if (val.uid && val.list) {
2464
2524
  if (val.list) {
2465
2525
  ctx.addIssue({
2466
2526
  code: z.z.ZodIssueCode.custom,
2467
- message: `Can not have \`list: true\` when using \`uid\`. Error in value
2468
- ${JSON.stringify(
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
- `
2527
+ message: `\`list: true\` is not allowed when using \`uid\` for fields of \`type: string\`. Error found in field:
2528
+ ${stringifiedField}`
2486
2529
  });
2487
2530
  }
2488
2531
  }
2532
+ if (val.uid && !val.required) {
2533
+ ctx.addIssue({
2534
+ code: z.z.ZodIssueCode.custom,
2535
+ message: `Property \`required: true\` is required when using \`uid\` for fields of \`type: string\`. Error found in field:
2536
+ ${stringifiedField}`
2537
+ });
2538
+ }
2489
2539
  }
2490
2540
  if (val.type === "object") {
2491
- const message = "Must provide one of templates or fields in your collection";
2492
- let isValid = Boolean(val == null ? void 0 : val.templates) || Boolean(val == null ? void 0 : val.fields);
2493
- if (!isValid) {
2541
+ if (!(val == null ? void 0 : val.templates) && !(val == null ? void 0 : val.fields)) {
2494
2542
  ctx.addIssue({
2495
2543
  code: z.z.ZodIssueCode.custom,
2496
- message
2544
+ message: "Fields of `type: object` must have either `templates` or `fields` property."
2545
+ });
2546
+ return false;
2547
+ }
2548
+ if ((val == null ? void 0 : val.templates) && (val == null ? void 0 : val.fields)) {
2549
+ ctx.addIssue({
2550
+ code: z.z.ZodIssueCode.custom,
2551
+ message: "Fields of `type: object` must have either `templates` or `fields` property, not both."
2497
2552
  });
2498
2553
  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
2554
  }
2509
2555
  }
2510
2556
  return true;
@@ -2537,19 +2583,10 @@ ${JSON.stringify(
2537
2583
  const newConfig = tinaConfigZod.parse(config);
2538
2584
  return newConfig;
2539
2585
  };
2540
- const FORMATS = [
2541
- "json",
2542
- "md",
2543
- "markdown",
2544
- "mdx",
2545
- "toml",
2546
- "yaml",
2547
- "yml"
2548
- ];
2549
2586
  const Template = z.z.object({
2550
2587
  label: z.z.string({
2551
- invalid_type_error: "label must be a string",
2552
- required_error: "label was not provided but is required"
2588
+ invalid_type_error: "Invalid data type for property `label`. Must be of type `string`",
2589
+ required_error: "Missing `label` property. Property `label` is required."
2553
2590
  }),
2554
2591
  name,
2555
2592
  fields: z.z.array(TinaFieldZod)
@@ -2559,7 +2596,7 @@ ${JSON.stringify(
2559
2596
  if (dups) {
2560
2597
  ctx.addIssue({
2561
2598
  code: z.z.ZodIssueCode.custom,
2562
- message: `Fields must have a unique name, duplicate field names: ${dups}`
2599
+ message: duplicateFieldErrorMessage(dups)
2563
2600
  });
2564
2601
  }
2565
2602
  });
@@ -2569,7 +2606,7 @@ ${JSON.stringify(
2569
2606
  if (val === "relativePath") {
2570
2607
  ctx.addIssue({
2571
2608
  code: z.z.ZodIssueCode.custom,
2572
- message: `name cannot be 'relativePath'. 'relativePath' is a reserved field name.`
2609
+ message: "Invalid `name` property. `name` cannot be 'relativePath' as it is a reserved field name."
2573
2610
  });
2574
2611
  }
2575
2612
  }),
@@ -2577,72 +2614,73 @@ ${JSON.stringify(
2577
2614
  if (val === ".") {
2578
2615
  ctx.addIssue({
2579
2616
  code: z.z.ZodIssueCode.custom,
2580
- message: `path cannot be '.'. Please use '/' or '' instead. `
2617
+ message: "Invalid `path` property. `path` cannot be '.'. Please use '/' or '' instead."
2581
2618
  });
2582
2619
  }
2583
2620
  }),
2584
- format: z.z.enum(FORMATS).optional(),
2621
+ format: z.z.enum(CONTENT_FORMATS).optional(),
2585
2622
  isAuthCollection: z.z.boolean().optional(),
2586
2623
  isDetached: z.z.boolean().optional()
2587
2624
  });
2588
2625
  const TinaCloudCollection = CollectionBaseSchema.extend({
2589
- fields: z.z.array(TinaFieldZod).min(1).optional().superRefine((val, ctx) => {
2626
+ fields: z.z.array(TinaFieldZod).min(1, "Property `fields` cannot be empty.").optional().superRefine((val, ctx) => {
2590
2627
  const dups = findDuplicates(val == null ? void 0 : val.map((x) => x.name));
2591
2628
  if (dups) {
2592
2629
  ctx.addIssue({
2593
2630
  code: z.z.ZodIssueCode.custom,
2594
- message: `Fields must have a unique name, duplicate field names: ${dups}`
2631
+ message: duplicateFieldErrorMessage(dups)
2595
2632
  });
2596
2633
  }
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 === "string" && x.isTitle)) || [];
2601
- return arr.length < 2;
2602
- },
2603
- {
2604
- message: "Fields can only have one use of `isTitle`"
2605
- }
2606
- ).refine(
2607
- // It is valid if it is 0 or 1
2608
- (val) => {
2609
- const arr = (val == null ? void 0 : val.filter((x) => x.uid)) || [];
2610
- return arr.length < 2;
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"
2634
+ }).superRefine((val, ctx) => {
2635
+ const arr = (val == null ? void 0 : val.filter((x) => x.type === "string" && x.isTitle)) || [];
2636
+ if (arr.length > 1) {
2637
+ ctx.addIssue({
2638
+ code: z.z.ZodIssueCode.custom,
2639
+ message: `The following fields have the property \`isTitle\`: [${arr.map((field) => field.name).join(", ")}]. Only one can contain the property \`isTitle\`.`
2640
+ });
2641
+ }
2642
+ }).superRefine((val, ctx) => {
2643
+ const arr = (val == null ? void 0 : val.filter((x) => x.uid)) || [];
2644
+ if (arr.length > 2) {
2645
+ ctx.addIssue({
2646
+ code: z.z.ZodIssueCode.custom,
2647
+ message: `The following fields have the property \`uid\`: [${arr.map((field) => field.name).join(", ")}]. Only one can contain the property \`uid\`.`
2648
+ });
2623
2649
  }
2624
- ),
2625
- templates: z.z.array(Template).min(1).optional().superRefine((val, ctx) => {
2650
+ }).superRefine((val, ctx) => {
2651
+ const arr = (val == null ? void 0 : val.filter((x) => x.type === "password")) || [];
2652
+ if (arr.length > 2) {
2653
+ ctx.addIssue({
2654
+ code: z.z.ZodIssueCode.custom,
2655
+ message: `The following fields have \`type: password\`: [${arr.map((field) => field.name).join(", ")}]. Only one can be of \`type: password\`.`
2656
+ });
2657
+ }
2658
+ }),
2659
+ templates: z.z.array(Template).min(1, "Property `templates` cannot be empty.").optional().superRefine((val, ctx) => {
2626
2660
  const dups = findDuplicates(val == null ? void 0 : val.map((x) => x.name));
2627
2661
  if (dups) {
2628
2662
  ctx.addIssue({
2629
2663
  code: z.z.ZodIssueCode.custom,
2630
- message: `Templates must have a unique name, duplicate template names: ${dups}`
2664
+ message: duplicateFieldErrorMessage(dups)
2631
2665
  });
2632
2666
  }
2633
2667
  })
2634
- }).refine(
2635
- (val) => {
2636
- let isValid = Boolean(val == null ? void 0 : val.templates) || Boolean(val == null ? void 0 : val.fields);
2637
- if (!isValid) {
2638
- return false;
2639
- } else {
2640
- isValid = !((val == null ? void 0 : val.templates) && (val == null ? void 0 : val.fields));
2641
- return isValid;
2642
- }
2643
- },
2644
- { message: "Must provide one of templates or fields in your collection" }
2645
- );
2668
+ }).superRefine((val, ctx) => {
2669
+ if (!(val == null ? void 0 : val.templates) && !(val == null ? void 0 : val.fields)) {
2670
+ ctx.addIssue({
2671
+ code: z.z.ZodIssueCode.custom,
2672
+ message: "Fields of `type: object` must have either `templates` or `fields` property."
2673
+ });
2674
+ return false;
2675
+ }
2676
+ if ((val == null ? void 0 : val.templates) && (val == null ? void 0 : val.fields)) {
2677
+ ctx.addIssue({
2678
+ code: z.z.ZodIssueCode.custom,
2679
+ message: "Fields of `type: object` must have either `templates` or `fields` property, not both."
2680
+ });
2681
+ return false;
2682
+ }
2683
+ });
2646
2684
  const TinaCloudSchemaZod = z.z.object({
2647
2685
  collections: z.z.array(TinaCloudCollection),
2648
2686
  config: tinaConfigZod.optional()
@@ -2652,14 +2690,14 @@ ${JSON.stringify(
2652
2690
  if (dups) {
2653
2691
  ctx.addIssue({
2654
2692
  code: z.z.ZodIssueCode.custom,
2655
- message: `${dups} are duplicate names in your collections. Collection names must be unique.`,
2693
+ message: duplicateCollectionErrorMessage(dups),
2656
2694
  fatal: true
2657
2695
  });
2658
2696
  }
2659
2697
  if (((_b = val.collections) == null ? void 0 : _b.filter((x) => x.isAuthCollection).length) > 1) {
2660
2698
  ctx.addIssue({
2661
2699
  code: z.z.ZodIssueCode.custom,
2662
- message: `Only one collection can be marked as isAuthCollection`,
2700
+ message: "Only one collection can be marked as `isAuthCollection`.",
2663
2701
  fatal: true
2664
2702
  });
2665
2703
  }
@@ -2667,7 +2705,7 @@ ${JSON.stringify(
2667
2705
  if (media && media.tina && media.loadCustomStore) {
2668
2706
  ctx.addIssue({
2669
2707
  code: z.z.ZodIssueCode.custom,
2670
- message: "can not have both loadCustomStore and tina. Must use one or the other",
2708
+ message: "Cannot have both `loadCustomStore` and `tina`. Must use one or the other.",
2671
2709
  fatal: true,
2672
2710
  path: ["config", "media"]
2673
2711
  });
@@ -2676,7 +2714,7 @@ ${JSON.stringify(
2676
2714
  if (search && search.tina && search.searchClient) {
2677
2715
  ctx.addIssue({
2678
2716
  code: z.z.ZodIssueCode.custom,
2679
- message: "can not have both searchClient and tina. Must use one or the other",
2717
+ message: "Cannot have both `searchClient` and `tina`. Must use one or the other.",
2680
2718
  fatal: true,
2681
2719
  path: ["config", "search"]
2682
2720
  });
@@ -2694,16 +2732,18 @@ ${JSON.stringify(
2694
2732
  } catch (e) {
2695
2733
  if (e instanceof z.ZodError) {
2696
2734
  const errors = parseZodError({ zodError: e });
2697
- throw new TinaSchemaValidationError(errors.join(", \n"));
2735
+ throw new TinaSchemaValidationError(errors.join("\n"));
2698
2736
  }
2699
2737
  throw new Error(e);
2700
2738
  }
2701
2739
  };
2740
+ exports2.CONTENT_FORMATS = CONTENT_FORMATS;
2702
2741
  exports2.NAMER = NAMER;
2703
2742
  exports2.TINA_HOST = TINA_HOST;
2704
2743
  exports2.TinaSchema = TinaSchema;
2705
2744
  exports2.TinaSchemaValidationError = TinaSchemaValidationError;
2706
2745
  exports2.addNamespaceToSchema = addNamespaceToSchema;
2746
+ exports2.canonicalPath = canonicalPath;
2707
2747
  exports2.normalizePath = normalizePath;
2708
2748
  exports2.parseURL = parseURL;
2709
2749
  exports2.resolveField = resolveField;