@tinacms/schema-tools 0.0.0-f3aa146-20241112221138 → 0.0.0-f471982-20250804064407

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,20 +1991,67 @@
2004
1991
  field.uid = field.uid || false;
2005
1992
  });
2006
1993
  }
2007
- findReferences(name2) {
1994
+ findReferencesFromCollection(name2) {
2008
1995
  const result = {};
2009
1996
  this.walkFields(({ field, collection: c, path }) => {
1997
+ if (c.name !== name2) {
1998
+ return;
1999
+ }
2010
2000
  if (field.type === "reference") {
2011
- if (field.collections.includes(name2)) {
2012
- if (result[c.name] === void 0) {
2013
- result[c.name] = [];
2001
+ field.collections.forEach((name22) => {
2002
+ if (result[name22] === void 0) {
2003
+ result[name22] = [];
2014
2004
  }
2015
- result[c.name].push({ path, field });
2016
- }
2005
+ result[name22].push(path);
2006
+ });
2017
2007
  }
2018
2008
  });
2019
2009
  return result;
2020
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
+ }
2021
2055
  /**
2022
2056
  * This function returns an array of glob matches for a given collection.
2023
2057
  *
@@ -2029,16 +2063,16 @@
2029
2063
  }) {
2030
2064
  var _a, _b;
2031
2065
  const collection = typeof collectionOrString === "string" ? this.getCollection(collectionOrString) : collectionOrString;
2032
- const normalPath = normalizePath(collection.path);
2033
- const pathSuffix = normalPath ? "/" : "";
2066
+ const collectionPath = canonicalPath(collection.path);
2067
+ const pathSuffix = collectionPath ? "/" : "";
2034
2068
  const format = collection.format || "md";
2035
2069
  const matches = [];
2036
2070
  if ((_a = collection == null ? void 0 : collection.match) == null ? void 0 : _a.include) {
2037
- const match = `${normalPath}${pathSuffix}${collection.match.include}.${format}`;
2071
+ const match = `${collectionPath}${pathSuffix}${collection.match.include}.${format}`;
2038
2072
  matches.push(match);
2039
2073
  }
2040
2074
  if ((_b = collection == null ? void 0 : collection.match) == null ? void 0 : _b.exclude) {
2041
- const exclude = `!(${normalPath}${pathSuffix}${collection.match.exclude}.${format})`;
2075
+ const exclude = `!(${collectionPath}${pathSuffix}${collection.match.exclude}.${format})`;
2042
2076
  matches.push(exclude);
2043
2077
  }
2044
2078
  return matches;
@@ -2231,6 +2265,15 @@
2231
2265
  })
2232
2266
  };
2233
2267
  };
2268
+ const CONTENT_FORMATS = [
2269
+ "mdx",
2270
+ "md",
2271
+ "markdown",
2272
+ "json",
2273
+ "yaml",
2274
+ "yml",
2275
+ "toml"
2276
+ ];
2234
2277
  const parseZodError = ({ zodError }) => {
2235
2278
  var _a, _b, _c, _d;
2236
2279
  const errors = zodError.flatten((issue) => {
@@ -2240,9 +2283,12 @@
2240
2283
  moreInfo.push(parseZodError({ zodError: unionError }));
2241
2284
  });
2242
2285
  }
2243
- 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(
2244
2289
  "."
2245
- )}`;
2290
+ )}
2291
+ `;
2246
2292
  const errorMessages = [errorMessage, ...moreInfo];
2247
2293
  return {
2248
2294
  errors: errorMessages
@@ -2277,6 +2323,9 @@ If you need to use this value in your content you can use the \`nameOverride\` p
2277
2323
  });
2278
2324
  }
2279
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}]`;
2280
2329
  const TypeName = [
2281
2330
  "string",
2282
2331
  "boolean",
@@ -2287,10 +2336,11 @@ If you need to use this value in your content you can use the \`nameOverride\` p
2287
2336
  "reference",
2288
2337
  "rich-text"
2289
2338
  ];
2290
- const typeTypeError = `type must be one of ${TypeName.join(", ")}`;
2291
- const typeRequiredError = `type is required and must be one of ${TypeName.join(
2292
- ", "
2293
- )}`;
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}`;
2294
2344
  const Option = z.z.union(
2295
2345
  [
2296
2346
  z.z.string(),
@@ -2376,7 +2426,7 @@ If you need to use this value in your content you can use the \`nameOverride\` p
2376
2426
  if (dups) {
2377
2427
  ctx.addIssue({
2378
2428
  code: z.z.ZodIssueCode.custom,
2379
- message: `Fields must have a unique name, duplicate field names: ${dups}`
2429
+ message: duplicateFieldErrorMessage(dups)
2380
2430
  });
2381
2431
  }
2382
2432
  });
@@ -2386,21 +2436,21 @@ If you need to use this value in your content you can use the \`nameOverride\` p
2386
2436
  invalid_type_error: typeTypeError,
2387
2437
  required_error: typeRequiredError
2388
2438
  }),
2389
- 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) => {
2390
2440
  const dups = findDuplicates(val == null ? void 0 : val.map((x) => x.name));
2391
2441
  if (dups) {
2392
2442
  ctx.addIssue({
2393
2443
  code: z.z.ZodIssueCode.custom,
2394
- message: `Fields must have a unique name, duplicate field names: ${dups}`
2444
+ message: duplicateFieldErrorMessage(dups)
2395
2445
  });
2396
2446
  }
2397
2447
  }),
2398
- 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) => {
2399
2449
  const dups = findDuplicates(val == null ? void 0 : val.map((x) => x.name));
2400
2450
  if (dups) {
2401
2451
  ctx.addIssue({
2402
2452
  code: z.z.ZodIssueCode.custom,
2403
- message: `Templates must have a unique name, duplicate template names: ${dups}`
2453
+ message: duplicateTemplateErrorMessage(dups)
2404
2454
  });
2405
2455
  }
2406
2456
  })
@@ -2415,7 +2465,7 @@ If you need to use this value in your content you can use the \`nameOverride\` p
2415
2465
  if (dups) {
2416
2466
  ctx.addIssue({
2417
2467
  code: z.z.ZodIssueCode.custom,
2418
- message: `Templates must have a unique name, duplicate template names: ${dups}`
2468
+ message: duplicateTemplateErrorMessage(dups)
2419
2469
  });
2420
2470
  }
2421
2471
  })
@@ -2435,10 +2485,17 @@ If you need to use this value in your content you can use the \`nameOverride\` p
2435
2485
  ],
2436
2486
  {
2437
2487
  errorMap: (issue, ctx) => {
2438
- var _a;
2488
+ var _a, _b;
2439
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
+ }
2440
2496
  return {
2441
- 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}`
2442
2499
  };
2443
2500
  }
2444
2501
  return {
@@ -2448,77 +2505,52 @@ If you need to use this value in your content you can use the \`nameOverride\` p
2448
2505
  }
2449
2506
  ).superRefine((val, ctx) => {
2450
2507
  if (val.type === "string") {
2451
- if (val.isTitle) {
2452
- if (val.list) {
2453
- ctx.addIssue({
2454
- code: z.z.ZodIssueCode.custom,
2455
- message: `Can not have \`list: true\` when using \`isTitle\`. Error in value
2456
- ${JSON.stringify(
2457
- val,
2458
- null,
2459
- 2
2460
- )}
2461
- `
2462
- });
2463
- }
2464
- if (!val.required) {
2465
- ctx.addIssue({
2466
- code: z.z.ZodIssueCode.custom,
2467
- message: `Must have { required: true } when using \`isTitle\` Error in value
2468
- ${JSON.stringify(
2469
- val,
2470
- null,
2471
- 2
2472
- )}
2473
- `
2474
- });
2475
- }
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
+ });
2476
2515
  }
2477
- if (val.uid) {
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
+ });
2522
+ }
2523
+ if (val.uid && val.list) {
2478
2524
  if (val.list) {
2479
2525
  ctx.addIssue({
2480
2526
  code: z.z.ZodIssueCode.custom,
2481
- message: `Can not have \`list: true\` when using \`uid\`. Error in value
2482
- ${JSON.stringify(
2483
- val,
2484
- null,
2485
- 2
2486
- )}
2487
- `
2488
- });
2489
- }
2490
- if (!val.required) {
2491
- ctx.addIssue({
2492
- code: z.z.ZodIssueCode.custom,
2493
- message: `Must have { required: true } when using \`uid\` Error in value
2494
- ${JSON.stringify(
2495
- val,
2496
- null,
2497
- 2
2498
- )}
2499
- `
2527
+ message: `\`list: true\` is not allowed when using \`uid\` for fields of \`type: string\`. Error found in field:
2528
+ ${stringifiedField}`
2500
2529
  });
2501
2530
  }
2502
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
+ }
2503
2539
  }
2504
2540
  if (val.type === "object") {
2505
- const message = "Must provide one of templates or fields in your collection";
2506
- let isValid = Boolean(val == null ? void 0 : val.templates) || Boolean(val == null ? void 0 : val.fields);
2507
- if (!isValid) {
2541
+ if (!(val == null ? void 0 : val.templates) && !(val == null ? void 0 : val.fields)) {
2508
2542
  ctx.addIssue({
2509
2543
  code: z.z.ZodIssueCode.custom,
2510
- 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."
2511
2552
  });
2512
2553
  return false;
2513
- } else {
2514
- isValid = !((val == null ? void 0 : val.templates) && (val == null ? void 0 : val.fields));
2515
- if (!isValid) {
2516
- ctx.addIssue({
2517
- code: z.z.ZodIssueCode.custom,
2518
- message
2519
- });
2520
- }
2521
- return isValid;
2522
2554
  }
2523
2555
  }
2524
2556
  return true;
@@ -2551,19 +2583,10 @@ ${JSON.stringify(
2551
2583
  const newConfig = tinaConfigZod.parse(config);
2552
2584
  return newConfig;
2553
2585
  };
2554
- const FORMATS = [
2555
- "json",
2556
- "md",
2557
- "markdown",
2558
- "mdx",
2559
- "toml",
2560
- "yaml",
2561
- "yml"
2562
- ];
2563
2586
  const Template = z.z.object({
2564
2587
  label: z.z.string({
2565
- invalid_type_error: "label must be a string",
2566
- 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."
2567
2590
  }),
2568
2591
  name,
2569
2592
  fields: z.z.array(TinaFieldZod)
@@ -2573,7 +2596,7 @@ ${JSON.stringify(
2573
2596
  if (dups) {
2574
2597
  ctx.addIssue({
2575
2598
  code: z.z.ZodIssueCode.custom,
2576
- message: `Fields must have a unique name, duplicate field names: ${dups}`
2599
+ message: duplicateFieldErrorMessage(dups)
2577
2600
  });
2578
2601
  }
2579
2602
  });
@@ -2583,7 +2606,7 @@ ${JSON.stringify(
2583
2606
  if (val === "relativePath") {
2584
2607
  ctx.addIssue({
2585
2608
  code: z.z.ZodIssueCode.custom,
2586
- 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."
2587
2610
  });
2588
2611
  }
2589
2612
  }),
@@ -2591,72 +2614,73 @@ ${JSON.stringify(
2591
2614
  if (val === ".") {
2592
2615
  ctx.addIssue({
2593
2616
  code: z.z.ZodIssueCode.custom,
2594
- message: `path cannot be '.'. Please use '/' or '' instead. `
2617
+ message: "Invalid `path` property. `path` cannot be '.'. Please use '/' or '' instead."
2595
2618
  });
2596
2619
  }
2597
2620
  }),
2598
- format: z.z.enum(FORMATS).optional(),
2621
+ format: z.z.enum(CONTENT_FORMATS).optional(),
2599
2622
  isAuthCollection: z.z.boolean().optional(),
2600
2623
  isDetached: z.z.boolean().optional()
2601
2624
  });
2602
2625
  const TinaCloudCollection = CollectionBaseSchema.extend({
2603
- 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) => {
2604
2627
  const dups = findDuplicates(val == null ? void 0 : val.map((x) => x.name));
2605
2628
  if (dups) {
2606
2629
  ctx.addIssue({
2607
2630
  code: z.z.ZodIssueCode.custom,
2608
- message: `Fields must have a unique name, duplicate field names: ${dups}`
2631
+ message: duplicateFieldErrorMessage(dups)
2609
2632
  });
2610
2633
  }
2611
- }).refine(
2612
- // It is valid if it is 0 or 1
2613
- (val) => {
2614
- const arr = (val == null ? void 0 : val.filter((x) => x.type === "string" && x.isTitle)) || [];
2615
- return arr.length < 2;
2616
- },
2617
- {
2618
- message: "Fields can only have one use of `isTitle`"
2619
- }
2620
- ).refine(
2621
- // It is valid if it is 0 or 1
2622
- (val) => {
2623
- const arr = (val == null ? void 0 : val.filter((x) => x.uid)) || [];
2624
- return arr.length < 2;
2625
- },
2626
- {
2627
- message: "Fields can only have one use of `uid`"
2628
- }
2629
- ).refine(
2630
- // It is valid if it is 0 or 1
2631
- (val) => {
2632
- const arr = (val == null ? void 0 : val.filter((x) => x.type === "password")) || [];
2633
- return arr.length < 2;
2634
- },
2635
- {
2636
- 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
+ });
2637
2641
  }
2638
- ),
2639
- templates: z.z.array(Template).min(1).optional().superRefine((val, ctx) => {
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
+ });
2649
+ }
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) => {
2640
2660
  const dups = findDuplicates(val == null ? void 0 : val.map((x) => x.name));
2641
2661
  if (dups) {
2642
2662
  ctx.addIssue({
2643
2663
  code: z.z.ZodIssueCode.custom,
2644
- message: `Templates must have a unique name, duplicate template names: ${dups}`
2664
+ message: duplicateFieldErrorMessage(dups)
2645
2665
  });
2646
2666
  }
2647
2667
  })
2648
- }).refine(
2649
- (val) => {
2650
- let isValid = Boolean(val == null ? void 0 : val.templates) || Boolean(val == null ? void 0 : val.fields);
2651
- if (!isValid) {
2652
- return false;
2653
- } else {
2654
- isValid = !((val == null ? void 0 : val.templates) && (val == null ? void 0 : val.fields));
2655
- return isValid;
2656
- }
2657
- },
2658
- { message: "Must provide one of templates or fields in your collection" }
2659
- );
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
+ });
2660
2684
  const TinaCloudSchemaZod = z.z.object({
2661
2685
  collections: z.z.array(TinaCloudCollection),
2662
2686
  config: tinaConfigZod.optional()
@@ -2666,14 +2690,14 @@ ${JSON.stringify(
2666
2690
  if (dups) {
2667
2691
  ctx.addIssue({
2668
2692
  code: z.z.ZodIssueCode.custom,
2669
- message: `${dups} are duplicate names in your collections. Collection names must be unique.`,
2693
+ message: duplicateCollectionErrorMessage(dups),
2670
2694
  fatal: true
2671
2695
  });
2672
2696
  }
2673
2697
  if (((_b = val.collections) == null ? void 0 : _b.filter((x) => x.isAuthCollection).length) > 1) {
2674
2698
  ctx.addIssue({
2675
2699
  code: z.z.ZodIssueCode.custom,
2676
- message: `Only one collection can be marked as isAuthCollection`,
2700
+ message: "Only one collection can be marked as `isAuthCollection`.",
2677
2701
  fatal: true
2678
2702
  });
2679
2703
  }
@@ -2681,7 +2705,7 @@ ${JSON.stringify(
2681
2705
  if (media && media.tina && media.loadCustomStore) {
2682
2706
  ctx.addIssue({
2683
2707
  code: z.z.ZodIssueCode.custom,
2684
- 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.",
2685
2709
  fatal: true,
2686
2710
  path: ["config", "media"]
2687
2711
  });
@@ -2690,7 +2714,7 @@ ${JSON.stringify(
2690
2714
  if (search && search.tina && search.searchClient) {
2691
2715
  ctx.addIssue({
2692
2716
  code: z.z.ZodIssueCode.custom,
2693
- 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.",
2694
2718
  fatal: true,
2695
2719
  path: ["config", "search"]
2696
2720
  });
@@ -2708,16 +2732,18 @@ ${JSON.stringify(
2708
2732
  } catch (e) {
2709
2733
  if (e instanceof z.ZodError) {
2710
2734
  const errors = parseZodError({ zodError: e });
2711
- throw new TinaSchemaValidationError(errors.join(", \n"));
2735
+ throw new TinaSchemaValidationError(errors.join("\n"));
2712
2736
  }
2713
2737
  throw new Error(e);
2714
2738
  }
2715
2739
  };
2740
+ exports2.CONTENT_FORMATS = CONTENT_FORMATS;
2716
2741
  exports2.NAMER = NAMER;
2717
2742
  exports2.TINA_HOST = TINA_HOST;
2718
2743
  exports2.TinaSchema = TinaSchema;
2719
2744
  exports2.TinaSchemaValidationError = TinaSchemaValidationError;
2720
2745
  exports2.addNamespaceToSchema = addNamespaceToSchema;
2746
+ exports2.canonicalPath = canonicalPath;
2721
2747
  exports2.normalizePath = normalizePath;
2722
2748
  exports2.parseURL = parseURL;
2723
2749
  exports2.resolveField = resolveField;