@tinacms/schema-tools 0.0.0-d69e892-20241003042309 → 0.0.0-d9672bc-20250218033222

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;
@@ -1961,29 +1945,8 @@
1961
1945
  }
1962
1946
  }
1963
1947
  };
1964
- this.walkFields = (cb) => {
1965
- const walk = (collectionOrObject, collection, path) => {
1966
- if (collectionOrObject.templates) {
1967
- collectionOrObject.templates.forEach((template) => {
1968
- template.fields.forEach((field) => {
1969
- cb({ field, collection, path: [...path, template.name] });
1970
- });
1971
- });
1972
- }
1973
- if (collectionOrObject.fields) {
1974
- collectionOrObject.fields.forEach((field) => {
1975
- cb({ field, collection, path: [...path, field.name] });
1976
- if (field.type === "rich-text" || field.type === "object") {
1977
- walk(field, collection, [...path, field.name]);
1978
- }
1979
- });
1980
- }
1981
- };
1982
- const collections = this.getCollections();
1983
- collections.forEach((collection) => walk(collection, collection, []));
1984
- };
1985
1948
  this.schema = config;
1986
- this.walkFields(({ field, collection, path }) => {
1949
+ this.walkFields(({ field, collection }) => {
1987
1950
  if (!("searchable" in field)) {
1988
1951
  if (field.type === "image") {
1989
1952
  field.searchable = false;
@@ -2004,6 +1967,51 @@
2004
1967
  field.uid = field.uid || false;
2005
1968
  });
2006
1969
  }
1970
+ findReferencesFromCollection(name2) {
1971
+ const result = {};
1972
+ this.walkFields(({ field, collection: c, path }) => {
1973
+ if (c.name !== name2) {
1974
+ return;
1975
+ }
1976
+ if (field.type === "reference") {
1977
+ field.collections.forEach((name22) => {
1978
+ if (result[name22] === void 0) {
1979
+ result[name22] = [];
1980
+ }
1981
+ result[name22].push(path);
1982
+ });
1983
+ }
1984
+ });
1985
+ return result;
1986
+ }
1987
+ walkFields(cb) {
1988
+ const walk = (collectionOrObject, collection, path = "$") => {
1989
+ if (collectionOrObject.templates) {
1990
+ collectionOrObject.templates.forEach((template) => {
1991
+ const templatePath = `${path}.${template.name}`;
1992
+ template.fields.forEach((field) => {
1993
+ const fieldPath = field.list ? `${templatePath}[*].${field.name}` : `${templatePath}.${field.name}`;
1994
+ cb({ field, collection, path: fieldPath });
1995
+ if (field.type === "object") {
1996
+ walk(field, collection, fieldPath);
1997
+ }
1998
+ });
1999
+ });
2000
+ }
2001
+ if (collectionOrObject.fields) {
2002
+ collectionOrObject.fields.forEach((field) => {
2003
+ const fieldPath = field.list ? `${path}.${field.name}[*]` : `${path}.${field.name}`;
2004
+ cb({ field, collection, path: fieldPath });
2005
+ if (field.type === "object" && field.fields) {
2006
+ walk(field, collection, fieldPath);
2007
+ }
2008
+ });
2009
+ }
2010
+ };
2011
+ this.getCollections().forEach((collection) => {
2012
+ walk(collection, collection);
2013
+ });
2014
+ }
2007
2015
  /**
2008
2016
  * This function returns an array of glob matches for a given collection.
2009
2017
  *
@@ -2226,9 +2234,12 @@
2226
2234
  moreInfo.push(parseZodError({ zodError: unionError }));
2227
2235
  });
2228
2236
  }
2229
- const errorMessage = `Error ${issue == null ? void 0 : issue.message} at path ${issue.path.join(
2237
+ const errorMessage = `${issue == null ? void 0 : issue.message}
2238
+ Additional information:
2239
+ - Error found at path ${issue.path.join(
2230
2240
  "."
2231
- )}`;
2241
+ )}
2242
+ `;
2232
2243
  const errorMessages = [errorMessage, ...moreInfo];
2233
2244
  return {
2234
2245
  errors: errorMessages
@@ -2263,6 +2274,9 @@ If you need to use this value in your content you can use the \`nameOverride\` p
2263
2274
  });
2264
2275
  }
2265
2276
  });
2277
+ const duplicateFieldErrorMessage = (fields) => `Fields must have unique names. Found duplicate field names: [${fields}]`;
2278
+ const duplicateTemplateErrorMessage = (templates) => `Templates must have unique names. Found duplicate template names: [${templates}]`;
2279
+ const duplicateCollectionErrorMessage = (collection) => `Collections must have unique names. Found duplicate collection names: [${collection}]`;
2266
2280
  const TypeName = [
2267
2281
  "string",
2268
2282
  "boolean",
@@ -2273,10 +2287,11 @@ If you need to use this value in your content you can use the \`nameOverride\` p
2273
2287
  "reference",
2274
2288
  "rich-text"
2275
2289
  ];
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
- )}`;
2290
+ const formattedTypes = ` - ${TypeName.join("\n - ")}`;
2291
+ const typeTypeError = `Invalid \`type\` property. \`type\` expected to be one of the following values:
2292
+ ${formattedTypes}`;
2293
+ const typeRequiredError = `Missing \`type\` property. Please add a \`type\` property with one of the following:
2294
+ ${formattedTypes}`;
2280
2295
  const Option = z.z.union(
2281
2296
  [
2282
2297
  z.z.string(),
@@ -2362,7 +2377,7 @@ If you need to use this value in your content you can use the \`nameOverride\` p
2362
2377
  if (dups) {
2363
2378
  ctx.addIssue({
2364
2379
  code: z.z.ZodIssueCode.custom,
2365
- message: `Fields must have a unique name, duplicate field names: ${dups}`
2380
+ message: duplicateFieldErrorMessage(dups)
2366
2381
  });
2367
2382
  }
2368
2383
  });
@@ -2372,21 +2387,21 @@ If you need to use this value in your content you can use the \`nameOverride\` p
2372
2387
  invalid_type_error: typeTypeError,
2373
2388
  required_error: typeRequiredError
2374
2389
  }),
2375
- fields: z.z.array(TinaFieldZod).min(1).optional().superRefine((val, ctx) => {
2390
+ fields: z.z.array(TinaFieldZod).min(1, "Property `fields` cannot be empty.").optional().superRefine((val, ctx) => {
2376
2391
  const dups = findDuplicates(val == null ? void 0 : val.map((x) => x.name));
2377
2392
  if (dups) {
2378
2393
  ctx.addIssue({
2379
2394
  code: z.z.ZodIssueCode.custom,
2380
- message: `Fields must have a unique name, duplicate field names: ${dups}`
2395
+ message: duplicateFieldErrorMessage(dups)
2381
2396
  });
2382
2397
  }
2383
2398
  }),
2384
- templates: z.z.array(TemplateTemp).min(1).optional().superRefine((val, ctx) => {
2399
+ templates: z.z.array(TemplateTemp).min(1, "Property `templates` cannot be empty.").optional().superRefine((val, ctx) => {
2385
2400
  const dups = findDuplicates(val == null ? void 0 : val.map((x) => x.name));
2386
2401
  if (dups) {
2387
2402
  ctx.addIssue({
2388
2403
  code: z.z.ZodIssueCode.custom,
2389
- message: `Templates must have a unique name, duplicate template names: ${dups}`
2404
+ message: duplicateTemplateErrorMessage(dups)
2390
2405
  });
2391
2406
  }
2392
2407
  })
@@ -2401,7 +2416,7 @@ If you need to use this value in your content you can use the \`nameOverride\` p
2401
2416
  if (dups) {
2402
2417
  ctx.addIssue({
2403
2418
  code: z.z.ZodIssueCode.custom,
2404
- message: `Templates must have a unique name, duplicate template names: ${dups}`
2419
+ message: duplicateTemplateErrorMessage(dups)
2405
2420
  });
2406
2421
  }
2407
2422
  })
@@ -2421,10 +2436,17 @@ If you need to use this value in your content you can use the \`nameOverride\` p
2421
2436
  ],
2422
2437
  {
2423
2438
  errorMap: (issue, ctx) => {
2424
- var _a;
2439
+ var _a, _b;
2425
2440
  if (issue.code === "invalid_union_discriminator") {
2441
+ if (!((_a = ctx.data) == null ? void 0 : _a.type)) {
2442
+ return {
2443
+ message: `Missing \`type\` property in field \`${ctx.data.name}\`. Please add a \`type\` property with one of the following:
2444
+ ${formattedTypes}`
2445
+ };
2446
+ }
2426
2447
  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(", ")}`
2448
+ 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:
2449
+ ${formattedTypes}`
2428
2450
  };
2429
2451
  }
2430
2452
  return {
@@ -2434,77 +2456,52 @@ If you need to use this value in your content you can use the \`nameOverride\` p
2434
2456
  }
2435
2457
  ).superRefine((val, ctx) => {
2436
2458
  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
- }
2459
+ const stringifiedField = JSON.stringify(val, null, 2);
2460
+ if (val.isTitle && val.list) {
2461
+ ctx.addIssue({
2462
+ code: z.z.ZodIssueCode.custom,
2463
+ message: `\`list: true\` is not allowed when using \`isTitle\` for fields of \`type: string\`. Error found in field:
2464
+ ${stringifiedField}`
2465
+ });
2466
+ }
2467
+ if (val.isTitle && !val.required) {
2468
+ ctx.addIssue({
2469
+ code: z.z.ZodIssueCode.custom,
2470
+ message: `Property \`required: true\` is required when using \`isTitle\` for fields of \`type: string\`. Error found in field:
2471
+ ${stringifiedField}`
2472
+ });
2462
2473
  }
2463
- if (val.uid) {
2474
+ if (val.uid && val.list) {
2464
2475
  if (val.list) {
2465
2476
  ctx.addIssue({
2466
2477
  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
- `
2478
+ message: `\`list: true\` is not allowed when using \`uid\` for fields of \`type: string\`. Error found in field:
2479
+ ${stringifiedField}`
2486
2480
  });
2487
2481
  }
2488
2482
  }
2483
+ if (val.uid && !val.required) {
2484
+ ctx.addIssue({
2485
+ code: z.z.ZodIssueCode.custom,
2486
+ message: `Property \`required: true\` is required when using \`uid\` for fields of \`type: string\`. Error found in field:
2487
+ ${stringifiedField}`
2488
+ });
2489
+ }
2489
2490
  }
2490
2491
  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) {
2492
+ if (!(val == null ? void 0 : val.templates) && !(val == null ? void 0 : val.fields)) {
2494
2493
  ctx.addIssue({
2495
2494
  code: z.z.ZodIssueCode.custom,
2496
- message
2495
+ message: "Fields of `type: object` must have either `templates` or `fields` property."
2496
+ });
2497
+ return false;
2498
+ }
2499
+ if ((val == null ? void 0 : val.templates) && (val == null ? void 0 : val.fields)) {
2500
+ ctx.addIssue({
2501
+ code: z.z.ZodIssueCode.custom,
2502
+ message: "Fields of `type: object` must have either `templates` or `fields` property, not both."
2497
2503
  });
2498
2504
  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
2505
  }
2509
2506
  }
2510
2507
  return true;
@@ -2548,8 +2545,8 @@ ${JSON.stringify(
2548
2545
  ];
2549
2546
  const Template = z.z.object({
2550
2547
  label: z.z.string({
2551
- invalid_type_error: "label must be a string",
2552
- required_error: "label was not provided but is required"
2548
+ invalid_type_error: "Invalid data type for property `label`. Must be of type `string`",
2549
+ required_error: "Missing `label` property. Property `label` is required."
2553
2550
  }),
2554
2551
  name,
2555
2552
  fields: z.z.array(TinaFieldZod)
@@ -2559,7 +2556,7 @@ ${JSON.stringify(
2559
2556
  if (dups) {
2560
2557
  ctx.addIssue({
2561
2558
  code: z.z.ZodIssueCode.custom,
2562
- message: `Fields must have a unique name, duplicate field names: ${dups}`
2559
+ message: duplicateFieldErrorMessage(dups)
2563
2560
  });
2564
2561
  }
2565
2562
  });
@@ -2569,7 +2566,7 @@ ${JSON.stringify(
2569
2566
  if (val === "relativePath") {
2570
2567
  ctx.addIssue({
2571
2568
  code: z.z.ZodIssueCode.custom,
2572
- message: `name cannot be 'relativePath'. 'relativePath' is a reserved field name.`
2569
+ message: "Invalid `name` property. `name` cannot be 'relativePath' as it is a reserved field name."
2573
2570
  });
2574
2571
  }
2575
2572
  }),
@@ -2577,7 +2574,7 @@ ${JSON.stringify(
2577
2574
  if (val === ".") {
2578
2575
  ctx.addIssue({
2579
2576
  code: z.z.ZodIssueCode.custom,
2580
- message: `path cannot be '.'. Please use '/' or '' instead. `
2577
+ message: "Invalid `path` property. `path` cannot be '.'. Please use '/' or '' instead."
2581
2578
  });
2582
2579
  }
2583
2580
  }),
@@ -2586,63 +2583,64 @@ ${JSON.stringify(
2586
2583
  isDetached: z.z.boolean().optional()
2587
2584
  });
2588
2585
  const TinaCloudCollection = CollectionBaseSchema.extend({
2589
- fields: z.z.array(TinaFieldZod).min(1).optional().superRefine((val, ctx) => {
2586
+ fields: z.z.array(TinaFieldZod).min(1, "Property `fields` cannot be empty.").optional().superRefine((val, ctx) => {
2590
2587
  const dups = findDuplicates(val == null ? void 0 : val.map((x) => x.name));
2591
2588
  if (dups) {
2592
2589
  ctx.addIssue({
2593
2590
  code: z.z.ZodIssueCode.custom,
2594
- message: `Fields must have a unique name, duplicate field names: ${dups}`
2591
+ message: duplicateFieldErrorMessage(dups)
2595
2592
  });
2596
2593
  }
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"
2594
+ }).superRefine((val, ctx) => {
2595
+ const arr = (val == null ? void 0 : val.filter((x) => x.type === "string" && x.isTitle)) || [];
2596
+ if (arr.length > 1) {
2597
+ ctx.addIssue({
2598
+ code: z.z.ZodIssueCode.custom,
2599
+ message: `The following fields have the property \`isTitle\`: [${arr.map((field) => field.name).join(", ")}]. Only one can contain the property \`isTitle\`.`
2600
+ });
2623
2601
  }
2624
- ),
2625
- templates: z.z.array(Template).min(1).optional().superRefine((val, ctx) => {
2602
+ }).superRefine((val, ctx) => {
2603
+ const arr = (val == null ? void 0 : val.filter((x) => x.uid)) || [];
2604
+ if (arr.length > 2) {
2605
+ ctx.addIssue({
2606
+ code: z.z.ZodIssueCode.custom,
2607
+ message: `The following fields have the property \`uid\`: [${arr.map((field) => field.name).join(", ")}]. Only one can contain the property \`uid\`.`
2608
+ });
2609
+ }
2610
+ }).superRefine((val, ctx) => {
2611
+ const arr = (val == null ? void 0 : val.filter((x) => x.type === "password")) || [];
2612
+ if (arr.length > 2) {
2613
+ ctx.addIssue({
2614
+ code: z.z.ZodIssueCode.custom,
2615
+ message: `The following fields have \`type: password\`: [${arr.map((field) => field.name).join(", ")}]. Only one can be of \`type: password\`.`
2616
+ });
2617
+ }
2618
+ }),
2619
+ templates: z.z.array(Template).min(1, "Property `templates` cannot be empty.").optional().superRefine((val, ctx) => {
2626
2620
  const dups = findDuplicates(val == null ? void 0 : val.map((x) => x.name));
2627
2621
  if (dups) {
2628
2622
  ctx.addIssue({
2629
2623
  code: z.z.ZodIssueCode.custom,
2630
- message: `Templates must have a unique name, duplicate template names: ${dups}`
2624
+ message: duplicateFieldErrorMessage(dups)
2631
2625
  });
2632
2626
  }
2633
2627
  })
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
- );
2628
+ }).superRefine((val, ctx) => {
2629
+ if (!(val == null ? void 0 : val.templates) && !(val == null ? void 0 : val.fields)) {
2630
+ ctx.addIssue({
2631
+ code: z.z.ZodIssueCode.custom,
2632
+ message: "Fields of `type: object` must have either `templates` or `fields` property."
2633
+ });
2634
+ return false;
2635
+ }
2636
+ if ((val == null ? void 0 : val.templates) && (val == null ? void 0 : val.fields)) {
2637
+ ctx.addIssue({
2638
+ code: z.z.ZodIssueCode.custom,
2639
+ message: "Fields of `type: object` must have either `templates` or `fields` property, not both."
2640
+ });
2641
+ return false;
2642
+ }
2643
+ });
2646
2644
  const TinaCloudSchemaZod = z.z.object({
2647
2645
  collections: z.z.array(TinaCloudCollection),
2648
2646
  config: tinaConfigZod.optional()
@@ -2652,14 +2650,14 @@ ${JSON.stringify(
2652
2650
  if (dups) {
2653
2651
  ctx.addIssue({
2654
2652
  code: z.z.ZodIssueCode.custom,
2655
- message: `${dups} are duplicate names in your collections. Collection names must be unique.`,
2653
+ message: duplicateCollectionErrorMessage(dups),
2656
2654
  fatal: true
2657
2655
  });
2658
2656
  }
2659
2657
  if (((_b = val.collections) == null ? void 0 : _b.filter((x) => x.isAuthCollection).length) > 1) {
2660
2658
  ctx.addIssue({
2661
2659
  code: z.z.ZodIssueCode.custom,
2662
- message: `Only one collection can be marked as isAuthCollection`,
2660
+ message: "Only one collection can be marked as `isAuthCollection`.",
2663
2661
  fatal: true
2664
2662
  });
2665
2663
  }
@@ -2667,7 +2665,7 @@ ${JSON.stringify(
2667
2665
  if (media && media.tina && media.loadCustomStore) {
2668
2666
  ctx.addIssue({
2669
2667
  code: z.z.ZodIssueCode.custom,
2670
- message: "can not have both loadCustomStore and tina. Must use one or the other",
2668
+ message: "Cannot have both `loadCustomStore` and `tina`. Must use one or the other.",
2671
2669
  fatal: true,
2672
2670
  path: ["config", "media"]
2673
2671
  });
@@ -2676,7 +2674,7 @@ ${JSON.stringify(
2676
2674
  if (search && search.tina && search.searchClient) {
2677
2675
  ctx.addIssue({
2678
2676
  code: z.z.ZodIssueCode.custom,
2679
- message: "can not have both searchClient and tina. Must use one or the other",
2677
+ message: "Cannot have both `searchClient` and `tina`. Must use one or the other.",
2680
2678
  fatal: true,
2681
2679
  path: ["config", "search"]
2682
2680
  });
@@ -2694,7 +2692,7 @@ ${JSON.stringify(
2694
2692
  } catch (e) {
2695
2693
  if (e instanceof z.ZodError) {
2696
2694
  const errors = parseZodError({ zodError: e });
2697
- throw new TinaSchemaValidationError(errors.join(", \n"));
2695
+ throw new TinaSchemaValidationError(errors.join("\n"));
2698
2696
  }
2699
2697
  throw new Error(e);
2700
2698
  }
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 === "string") {
5
+ if (typeof maybeNode !== "object" || maybeNode === null) {
6
6
  return maybeNode;
7
7
  }
8
- if (typeof maybeNode === "boolean") {
9
- return maybeNode;
10
- }
11
- if (typeof maybeNode === "function") {
12
- return maybeNode;
13
- }
14
- const newNode = { ...maybeNode };
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
- const value = element.name || element.value;
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
- if (!m) {
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 { ...newNode, namespace };
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,29 +1927,8 @@ class TinaSchema {
1943
1927
  }
1944
1928
  }
1945
1929
  };
1946
- this.walkFields = (cb) => {
1947
- const walk = (collectionOrObject, collection, path) => {
1948
- if (collectionOrObject.templates) {
1949
- collectionOrObject.templates.forEach((template) => {
1950
- template.fields.forEach((field) => {
1951
- cb({ field, collection, path: [...path, template.name] });
1952
- });
1953
- });
1954
- }
1955
- if (collectionOrObject.fields) {
1956
- collectionOrObject.fields.forEach((field) => {
1957
- cb({ field, collection, path: [...path, field.name] });
1958
- if (field.type === "rich-text" || field.type === "object") {
1959
- walk(field, collection, [...path, field.name]);
1960
- }
1961
- });
1962
- }
1963
- };
1964
- const collections = this.getCollections();
1965
- collections.forEach((collection) => walk(collection, collection, []));
1966
- };
1967
1930
  this.schema = config;
1968
- this.walkFields(({ field, collection, path }) => {
1931
+ this.walkFields(({ field, collection }) => {
1969
1932
  if (!("searchable" in field)) {
1970
1933
  if (field.type === "image") {
1971
1934
  field.searchable = false;
@@ -1986,6 +1949,51 @@ class TinaSchema {
1986
1949
  field.uid = field.uid || false;
1987
1950
  });
1988
1951
  }
1952
+ findReferencesFromCollection(name2) {
1953
+ const result = {};
1954
+ this.walkFields(({ field, collection: c, path }) => {
1955
+ if (c.name !== name2) {
1956
+ return;
1957
+ }
1958
+ if (field.type === "reference") {
1959
+ field.collections.forEach((name22) => {
1960
+ if (result[name22] === void 0) {
1961
+ result[name22] = [];
1962
+ }
1963
+ result[name22].push(path);
1964
+ });
1965
+ }
1966
+ });
1967
+ return result;
1968
+ }
1969
+ walkFields(cb) {
1970
+ const walk = (collectionOrObject, collection, path = "$") => {
1971
+ if (collectionOrObject.templates) {
1972
+ collectionOrObject.templates.forEach((template) => {
1973
+ const templatePath = `${path}.${template.name}`;
1974
+ template.fields.forEach((field) => {
1975
+ const fieldPath = field.list ? `${templatePath}[*].${field.name}` : `${templatePath}.${field.name}`;
1976
+ cb({ field, collection, path: fieldPath });
1977
+ if (field.type === "object") {
1978
+ walk(field, collection, fieldPath);
1979
+ }
1980
+ });
1981
+ });
1982
+ }
1983
+ if (collectionOrObject.fields) {
1984
+ collectionOrObject.fields.forEach((field) => {
1985
+ const fieldPath = field.list ? `${path}.${field.name}[*]` : `${path}.${field.name}`;
1986
+ cb({ field, collection, path: fieldPath });
1987
+ if (field.type === "object" && field.fields) {
1988
+ walk(field, collection, fieldPath);
1989
+ }
1990
+ });
1991
+ }
1992
+ };
1993
+ this.getCollections().forEach((collection) => {
1994
+ walk(collection, collection);
1995
+ });
1996
+ }
1989
1997
  /**
1990
1998
  * This function returns an array of glob matches for a given collection.
1991
1999
  *
@@ -2208,9 +2216,12 @@ const parseZodError = ({ zodError }) => {
2208
2216
  moreInfo.push(parseZodError({ zodError: unionError }));
2209
2217
  });
2210
2218
  }
2211
- const errorMessage = `Error ${issue == null ? void 0 : issue.message} at path ${issue.path.join(
2219
+ const errorMessage = `${issue == null ? void 0 : issue.message}
2220
+ Additional information:
2221
+ - Error found at path ${issue.path.join(
2212
2222
  "."
2213
- )}`;
2223
+ )}
2224
+ `;
2214
2225
  const errorMessages = [errorMessage, ...moreInfo];
2215
2226
  return {
2216
2227
  errors: errorMessages
@@ -2245,6 +2256,9 @@ If you need to use this value in your content you can use the \`nameOverride\` p
2245
2256
  });
2246
2257
  }
2247
2258
  });
2259
+ const duplicateFieldErrorMessage = (fields) => `Fields must have unique names. Found duplicate field names: [${fields}]`;
2260
+ const duplicateTemplateErrorMessage = (templates) => `Templates must have unique names. Found duplicate template names: [${templates}]`;
2261
+ const duplicateCollectionErrorMessage = (collection) => `Collections must have unique names. Found duplicate collection names: [${collection}]`;
2248
2262
  const TypeName = [
2249
2263
  "string",
2250
2264
  "boolean",
@@ -2255,10 +2269,11 @@ const TypeName = [
2255
2269
  "reference",
2256
2270
  "rich-text"
2257
2271
  ];
2258
- const typeTypeError = `type must be one of ${TypeName.join(", ")}`;
2259
- const typeRequiredError = `type is required and must be one of ${TypeName.join(
2260
- ", "
2261
- )}`;
2272
+ const formattedTypes = ` - ${TypeName.join("\n - ")}`;
2273
+ const typeTypeError = `Invalid \`type\` property. \`type\` expected to be one of the following values:
2274
+ ${formattedTypes}`;
2275
+ const typeRequiredError = `Missing \`type\` property. Please add a \`type\` property with one of the following:
2276
+ ${formattedTypes}`;
2262
2277
  const Option = z.union(
2263
2278
  [
2264
2279
  z.string(),
@@ -2344,7 +2359,7 @@ const TinaFieldZod = z.lazy(() => {
2344
2359
  if (dups) {
2345
2360
  ctx.addIssue({
2346
2361
  code: z.ZodIssueCode.custom,
2347
- message: `Fields must have a unique name, duplicate field names: ${dups}`
2362
+ message: duplicateFieldErrorMessage(dups)
2348
2363
  });
2349
2364
  }
2350
2365
  });
@@ -2354,21 +2369,21 @@ const TinaFieldZod = z.lazy(() => {
2354
2369
  invalid_type_error: typeTypeError,
2355
2370
  required_error: typeRequiredError
2356
2371
  }),
2357
- fields: z.array(TinaFieldZod).min(1).optional().superRefine((val, ctx) => {
2372
+ fields: z.array(TinaFieldZod).min(1, "Property `fields` cannot be empty.").optional().superRefine((val, ctx) => {
2358
2373
  const dups = findDuplicates(val == null ? void 0 : val.map((x) => x.name));
2359
2374
  if (dups) {
2360
2375
  ctx.addIssue({
2361
2376
  code: z.ZodIssueCode.custom,
2362
- message: `Fields must have a unique name, duplicate field names: ${dups}`
2377
+ message: duplicateFieldErrorMessage(dups)
2363
2378
  });
2364
2379
  }
2365
2380
  }),
2366
- templates: z.array(TemplateTemp).min(1).optional().superRefine((val, ctx) => {
2381
+ templates: z.array(TemplateTemp).min(1, "Property `templates` cannot be empty.").optional().superRefine((val, ctx) => {
2367
2382
  const dups = findDuplicates(val == null ? void 0 : val.map((x) => x.name));
2368
2383
  if (dups) {
2369
2384
  ctx.addIssue({
2370
2385
  code: z.ZodIssueCode.custom,
2371
- message: `Templates must have a unique name, duplicate template names: ${dups}`
2386
+ message: duplicateTemplateErrorMessage(dups)
2372
2387
  });
2373
2388
  }
2374
2389
  })
@@ -2383,7 +2398,7 @@ const TinaFieldZod = z.lazy(() => {
2383
2398
  if (dups) {
2384
2399
  ctx.addIssue({
2385
2400
  code: z.ZodIssueCode.custom,
2386
- message: `Templates must have a unique name, duplicate template names: ${dups}`
2401
+ message: duplicateTemplateErrorMessage(dups)
2387
2402
  });
2388
2403
  }
2389
2404
  })
@@ -2403,10 +2418,17 @@ const TinaFieldZod = z.lazy(() => {
2403
2418
  ],
2404
2419
  {
2405
2420
  errorMap: (issue, ctx) => {
2406
- var _a;
2421
+ var _a, _b;
2407
2422
  if (issue.code === "invalid_union_discriminator") {
2423
+ if (!((_a = ctx.data) == null ? void 0 : _a.type)) {
2424
+ return {
2425
+ message: `Missing \`type\` property in field \`${ctx.data.name}\`. Please add a \`type\` property with one of the following:
2426
+ ${formattedTypes}`
2427
+ };
2428
+ }
2408
2429
  return {
2409
- message: `Invalid \`type\` property. In the schema is 'type: ${(_a = ctx.data) == null ? void 0 : _a.type}' and expected one of ${TypeName.join(", ")}`
2430
+ 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:
2431
+ ${formattedTypes}`
2410
2432
  };
2411
2433
  }
2412
2434
  return {
@@ -2416,77 +2438,52 @@ const TinaFieldZod = z.lazy(() => {
2416
2438
  }
2417
2439
  ).superRefine((val, ctx) => {
2418
2440
  if (val.type === "string") {
2419
- if (val.isTitle) {
2420
- if (val.list) {
2421
- ctx.addIssue({
2422
- code: z.ZodIssueCode.custom,
2423
- message: `Can not have \`list: true\` when using \`isTitle\`. Error in value
2424
- ${JSON.stringify(
2425
- val,
2426
- null,
2427
- 2
2428
- )}
2429
- `
2430
- });
2431
- }
2432
- if (!val.required) {
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
- }
2441
+ const stringifiedField = JSON.stringify(val, null, 2);
2442
+ if (val.isTitle && val.list) {
2443
+ ctx.addIssue({
2444
+ code: z.ZodIssueCode.custom,
2445
+ message: `\`list: true\` is not allowed when using \`isTitle\` for fields of \`type: string\`. Error found in field:
2446
+ ${stringifiedField}`
2447
+ });
2448
+ }
2449
+ if (val.isTitle && !val.required) {
2450
+ ctx.addIssue({
2451
+ code: z.ZodIssueCode.custom,
2452
+ message: `Property \`required: true\` is required when using \`isTitle\` for fields of \`type: string\`. Error found in field:
2453
+ ${stringifiedField}`
2454
+ });
2444
2455
  }
2445
- if (val.uid) {
2456
+ if (val.uid && val.list) {
2446
2457
  if (val.list) {
2447
2458
  ctx.addIssue({
2448
2459
  code: z.ZodIssueCode.custom,
2449
- message: `Can not have \`list: true\` when using \`uid\`. Error in value
2450
- ${JSON.stringify(
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
- `
2460
+ message: `\`list: true\` is not allowed when using \`uid\` for fields of \`type: string\`. Error found in field:
2461
+ ${stringifiedField}`
2468
2462
  });
2469
2463
  }
2470
2464
  }
2465
+ if (val.uid && !val.required) {
2466
+ ctx.addIssue({
2467
+ code: z.ZodIssueCode.custom,
2468
+ message: `Property \`required: true\` is required when using \`uid\` for fields of \`type: string\`. Error found in field:
2469
+ ${stringifiedField}`
2470
+ });
2471
+ }
2471
2472
  }
2472
2473
  if (val.type === "object") {
2473
- const message = "Must provide one of templates or fields in your collection";
2474
- let isValid = Boolean(val == null ? void 0 : val.templates) || Boolean(val == null ? void 0 : val.fields);
2475
- if (!isValid) {
2474
+ if (!(val == null ? void 0 : val.templates) && !(val == null ? void 0 : val.fields)) {
2476
2475
  ctx.addIssue({
2477
2476
  code: z.ZodIssueCode.custom,
2478
- message
2477
+ message: "Fields of `type: object` must have either `templates` or `fields` property."
2478
+ });
2479
+ return false;
2480
+ }
2481
+ if ((val == null ? void 0 : val.templates) && (val == null ? void 0 : val.fields)) {
2482
+ ctx.addIssue({
2483
+ code: z.ZodIssueCode.custom,
2484
+ message: "Fields of `type: object` must have either `templates` or `fields` property, not both."
2479
2485
  });
2480
2486
  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
2487
  }
2491
2488
  }
2492
2489
  return true;
@@ -2530,8 +2527,8 @@ const FORMATS = [
2530
2527
  ];
2531
2528
  const Template = z.object({
2532
2529
  label: z.string({
2533
- invalid_type_error: "label must be a string",
2534
- required_error: "label was not provided but is required"
2530
+ invalid_type_error: "Invalid data type for property `label`. Must be of type `string`",
2531
+ required_error: "Missing `label` property. Property `label` is required."
2535
2532
  }),
2536
2533
  name,
2537
2534
  fields: z.array(TinaFieldZod)
@@ -2541,7 +2538,7 @@ const Template = z.object({
2541
2538
  if (dups) {
2542
2539
  ctx.addIssue({
2543
2540
  code: z.ZodIssueCode.custom,
2544
- message: `Fields must have a unique name, duplicate field names: ${dups}`
2541
+ message: duplicateFieldErrorMessage(dups)
2545
2542
  });
2546
2543
  }
2547
2544
  });
@@ -2551,7 +2548,7 @@ const CollectionBaseSchema = z.object({
2551
2548
  if (val === "relativePath") {
2552
2549
  ctx.addIssue({
2553
2550
  code: z.ZodIssueCode.custom,
2554
- message: `name cannot be 'relativePath'. 'relativePath' is a reserved field name.`
2551
+ message: "Invalid `name` property. `name` cannot be 'relativePath' as it is a reserved field name."
2555
2552
  });
2556
2553
  }
2557
2554
  }),
@@ -2559,7 +2556,7 @@ const CollectionBaseSchema = z.object({
2559
2556
  if (val === ".") {
2560
2557
  ctx.addIssue({
2561
2558
  code: z.ZodIssueCode.custom,
2562
- message: `path cannot be '.'. Please use '/' or '' instead. `
2559
+ message: "Invalid `path` property. `path` cannot be '.'. Please use '/' or '' instead."
2563
2560
  });
2564
2561
  }
2565
2562
  }),
@@ -2568,63 +2565,64 @@ const CollectionBaseSchema = z.object({
2568
2565
  isDetached: z.boolean().optional()
2569
2566
  });
2570
2567
  const TinaCloudCollection = CollectionBaseSchema.extend({
2571
- fields: z.array(TinaFieldZod).min(1).optional().superRefine((val, ctx) => {
2568
+ fields: z.array(TinaFieldZod).min(1, "Property `fields` cannot be empty.").optional().superRefine((val, ctx) => {
2572
2569
  const dups = findDuplicates(val == null ? void 0 : val.map((x) => x.name));
2573
2570
  if (dups) {
2574
2571
  ctx.addIssue({
2575
2572
  code: z.ZodIssueCode.custom,
2576
- message: `Fields must have a unique name, duplicate field names: ${dups}`
2573
+ message: duplicateFieldErrorMessage(dups)
2577
2574
  });
2578
2575
  }
2579
- }).refine(
2580
- // It is valid if it is 0 or 1
2581
- (val) => {
2582
- const arr = (val == null ? void 0 : val.filter((x) => x.type === "string" && x.isTitle)) || [];
2583
- return arr.length < 2;
2584
- },
2585
- {
2586
- message: "Fields can only have one use of `isTitle`"
2587
- }
2588
- ).refine(
2589
- // It is valid if it is 0 or 1
2590
- (val) => {
2591
- const arr = (val == null ? void 0 : val.filter((x) => x.uid)) || [];
2592
- return arr.length < 2;
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"
2576
+ }).superRefine((val, ctx) => {
2577
+ const arr = (val == null ? void 0 : val.filter((x) => x.type === "string" && x.isTitle)) || [];
2578
+ if (arr.length > 1) {
2579
+ ctx.addIssue({
2580
+ code: z.ZodIssueCode.custom,
2581
+ message: `The following fields have the property \`isTitle\`: [${arr.map((field) => field.name).join(", ")}]. Only one can contain the property \`isTitle\`.`
2582
+ });
2605
2583
  }
2606
- ),
2607
- templates: z.array(Template).min(1).optional().superRefine((val, ctx) => {
2584
+ }).superRefine((val, ctx) => {
2585
+ const arr = (val == null ? void 0 : val.filter((x) => x.uid)) || [];
2586
+ if (arr.length > 2) {
2587
+ ctx.addIssue({
2588
+ code: z.ZodIssueCode.custom,
2589
+ message: `The following fields have the property \`uid\`: [${arr.map((field) => field.name).join(", ")}]. Only one can contain the property \`uid\`.`
2590
+ });
2591
+ }
2592
+ }).superRefine((val, ctx) => {
2593
+ const arr = (val == null ? void 0 : val.filter((x) => x.type === "password")) || [];
2594
+ if (arr.length > 2) {
2595
+ ctx.addIssue({
2596
+ code: z.ZodIssueCode.custom,
2597
+ message: `The following fields have \`type: password\`: [${arr.map((field) => field.name).join(", ")}]. Only one can be of \`type: password\`.`
2598
+ });
2599
+ }
2600
+ }),
2601
+ templates: z.array(Template).min(1, "Property `templates` cannot be empty.").optional().superRefine((val, ctx) => {
2608
2602
  const dups = findDuplicates(val == null ? void 0 : val.map((x) => x.name));
2609
2603
  if (dups) {
2610
2604
  ctx.addIssue({
2611
2605
  code: z.ZodIssueCode.custom,
2612
- message: `Templates must have a unique name, duplicate template names: ${dups}`
2606
+ message: duplicateFieldErrorMessage(dups)
2613
2607
  });
2614
2608
  }
2615
2609
  })
2616
- }).refine(
2617
- (val) => {
2618
- let isValid = Boolean(val == null ? void 0 : val.templates) || Boolean(val == null ? void 0 : val.fields);
2619
- if (!isValid) {
2620
- return false;
2621
- } else {
2622
- isValid = !((val == null ? void 0 : val.templates) && (val == null ? void 0 : val.fields));
2623
- return isValid;
2624
- }
2625
- },
2626
- { message: "Must provide one of templates or fields in your collection" }
2627
- );
2610
+ }).superRefine((val, ctx) => {
2611
+ if (!(val == null ? void 0 : val.templates) && !(val == null ? void 0 : val.fields)) {
2612
+ ctx.addIssue({
2613
+ code: z.ZodIssueCode.custom,
2614
+ message: "Fields of `type: object` must have either `templates` or `fields` property."
2615
+ });
2616
+ return false;
2617
+ }
2618
+ if ((val == null ? void 0 : val.templates) && (val == null ? void 0 : val.fields)) {
2619
+ ctx.addIssue({
2620
+ code: z.ZodIssueCode.custom,
2621
+ message: "Fields of `type: object` must have either `templates` or `fields` property, not both."
2622
+ });
2623
+ return false;
2624
+ }
2625
+ });
2628
2626
  const TinaCloudSchemaZod = z.object({
2629
2627
  collections: z.array(TinaCloudCollection),
2630
2628
  config: tinaConfigZod.optional()
@@ -2634,14 +2632,14 @@ const TinaCloudSchemaZod = z.object({
2634
2632
  if (dups) {
2635
2633
  ctx.addIssue({
2636
2634
  code: z.ZodIssueCode.custom,
2637
- message: `${dups} are duplicate names in your collections. Collection names must be unique.`,
2635
+ message: duplicateCollectionErrorMessage(dups),
2638
2636
  fatal: true
2639
2637
  });
2640
2638
  }
2641
2639
  if (((_b = val.collections) == null ? void 0 : _b.filter((x) => x.isAuthCollection).length) > 1) {
2642
2640
  ctx.addIssue({
2643
2641
  code: z.ZodIssueCode.custom,
2644
- message: `Only one collection can be marked as isAuthCollection`,
2642
+ message: "Only one collection can be marked as `isAuthCollection`.",
2645
2643
  fatal: true
2646
2644
  });
2647
2645
  }
@@ -2649,7 +2647,7 @@ const TinaCloudSchemaZod = z.object({
2649
2647
  if (media && media.tina && media.loadCustomStore) {
2650
2648
  ctx.addIssue({
2651
2649
  code: z.ZodIssueCode.custom,
2652
- message: "can not have both loadCustomStore and tina. Must use one or the other",
2650
+ message: "Cannot have both `loadCustomStore` and `tina`. Must use one or the other.",
2653
2651
  fatal: true,
2654
2652
  path: ["config", "media"]
2655
2653
  });
@@ -2658,7 +2656,7 @@ const TinaCloudSchemaZod = z.object({
2658
2656
  if (search && search.tina && search.searchClient) {
2659
2657
  ctx.addIssue({
2660
2658
  code: z.ZodIssueCode.custom,
2661
- message: "can not have both searchClient and tina. Must use one or the other",
2659
+ message: "Cannot have both `searchClient` and `tina`. Must use one or the other.",
2662
2660
  fatal: true,
2663
2661
  path: ["config", "search"]
2664
2662
  });
@@ -2676,7 +2674,7 @@ const validateSchema = ({ schema }) => {
2676
2674
  } catch (e) {
2677
2675
  if (e instanceof ZodError) {
2678
2676
  const errors = parseZodError({ zodError: e });
2679
- throw new TinaSchemaValidationError(errors.join(", \n"));
2677
+ throw new TinaSchemaValidationError(errors.join("\n"));
2680
2678
  }
2681
2679
  throw new Error(e);
2682
2680
  }
@@ -1,4 +1,4 @@
1
- import type { Schema, Collection, Template, Collectable, CollectionTemplateable, TinaField } from '../types/index';
1
+ import type { Schema, Collection, Template, Collectable, CollectionTemplateable } from '../types/index';
2
2
  type Version = {
3
3
  fullVersion: string;
4
4
  major: string;
@@ -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,11 +60,12 @@ export declare class TinaSchema {
59
60
  *
60
61
  */
61
62
  getTemplatesForCollectable: (collection: Collectable) => CollectionTemplateable;
62
- walkFields: (cb: (args: {
63
- field: TinaField;
64
- collection: Collection;
65
- path: string[];
66
- }) => void) => void;
63
+ walkFields(cb: (args: {
64
+ field: any;
65
+ collection: any;
66
+ path: string;
67
+ isListItem?: boolean;
68
+ }) => void): void;
67
69
  /**
68
70
  * This function returns an array of glob matches for a given collection.
69
71
  *
@@ -1,4 +1,8 @@
1
- /**
2
-
3
- */
4
- export declare function addNamespaceToSchema<T extends object | string>(maybeNode: T, namespace?: string[]): T;
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 {};
@@ -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 toolbarItemName = 'heading' | 'link' | 'image' | 'quote' | 'ul' | 'ol' | 'code' | 'codeBlock' | 'bold' | 'italic' | 'raw' | 'embed';
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
- toolbarOverride?: toolbarItemName[];
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`).
@@ -630,6 +636,7 @@ type Document = {
630
636
  relativePath: string;
631
637
  filename: string;
632
638
  extension: string;
639
+ hasReferences?: boolean;
633
640
  };
634
641
  };
635
642
  export interface UICollection<Form = any, CMS = any, TinaForm = any> {
@@ -1,6 +1,3 @@
1
- /**
2
-
3
- */
4
1
  import { z } from 'zod';
5
2
  import type { TinaField as TinaFieldType } from '../types/index';
6
3
  export declare const TinaFieldZod: z.ZodType<TinaFieldType>;
@@ -1,6 +1,3 @@
1
- /**
2
-
3
- */
4
1
  import { z } from 'zod';
5
2
  export declare const CollectionBaseSchema: z.ZodObject<{
6
3
  label: z.ZodOptional<z.ZodString>;
@@ -0,0 +1,3 @@
1
+ export declare const duplicateFieldErrorMessage: (fields: string) => string;
2
+ export declare const duplicateTemplateErrorMessage: (templates: string) => string;
3
+ export declare const duplicateCollectionErrorMessage: (collection: string) => string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tinacms/schema-tools",
3
- "version": "0.0.0-d69e892-20241003042309",
3
+ "version": "0.0.0-d9672bc-20250218033222",
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.13",
26
+ "@types/jest": "^29.5.14",
27
27
  "@types/micromatch": "^4.0.9",
28
- "@types/react": "^18.3.10",
28
+ "@types/react": "^18.3.12",
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.6.2",
33
+ "typescript": "^5.6.3",
34
34
  "yup": "^0.32.11",
35
- "@tinacms/scripts": "1.2.3"
35
+ "@tinacms/scripts": "1.3.1"
36
36
  },
37
37
  "peerDependencies": {
38
38
  "react": ">=16.14.0",