@tinacms/schema-tools 1.6.8 → 1.7.0

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;
@@ -2240,9 +2224,12 @@
2240
2224
  moreInfo.push(parseZodError({ zodError: unionError }));
2241
2225
  });
2242
2226
  }
2243
- const errorMessage = `Error ${issue == null ? void 0 : issue.message} at path ${issue.path.join(
2227
+ const errorMessage = `${issue == null ? void 0 : issue.message}
2228
+ Additional information:
2229
+ - Error found at path ${issue.path.join(
2244
2230
  "."
2245
- )}`;
2231
+ )}
2232
+ `;
2246
2233
  const errorMessages = [errorMessage, ...moreInfo];
2247
2234
  return {
2248
2235
  errors: errorMessages
@@ -2277,6 +2264,9 @@ If you need to use this value in your content you can use the \`nameOverride\` p
2277
2264
  });
2278
2265
  }
2279
2266
  });
2267
+ const duplicateFieldErrorMessage = (fields) => `Fields must have unique names. Found duplicate field names: [${fields}]`;
2268
+ const duplicateTemplateErrorMessage = (templates) => `Templates must have unique names. Found duplicate template names: [${templates}]`;
2269
+ const duplicateCollectionErrorMessage = (collection) => `Collections must have unique names. Found duplicate collection names: [${collection}]`;
2280
2270
  const TypeName = [
2281
2271
  "string",
2282
2272
  "boolean",
@@ -2287,10 +2277,11 @@ If you need to use this value in your content you can use the \`nameOverride\` p
2287
2277
  "reference",
2288
2278
  "rich-text"
2289
2279
  ];
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
- )}`;
2280
+ const formattedTypes = ` - ${TypeName.join("\n - ")}`;
2281
+ const typeTypeError = `Invalid \`type\` property. \`type\` expected to be one of the following values:
2282
+ ${formattedTypes}`;
2283
+ const typeRequiredError = `Missing \`type\` property. Please add a \`type\` property with one of the following:
2284
+ ${formattedTypes}`;
2294
2285
  const Option = z.z.union(
2295
2286
  [
2296
2287
  z.z.string(),
@@ -2376,7 +2367,7 @@ If you need to use this value in your content you can use the \`nameOverride\` p
2376
2367
  if (dups) {
2377
2368
  ctx.addIssue({
2378
2369
  code: z.z.ZodIssueCode.custom,
2379
- message: `Fields must have a unique name, duplicate field names: ${dups}`
2370
+ message: duplicateFieldErrorMessage(dups)
2380
2371
  });
2381
2372
  }
2382
2373
  });
@@ -2386,21 +2377,21 @@ If you need to use this value in your content you can use the \`nameOverride\` p
2386
2377
  invalid_type_error: typeTypeError,
2387
2378
  required_error: typeRequiredError
2388
2379
  }),
2389
- fields: z.z.array(TinaFieldZod).min(1).optional().superRefine((val, ctx) => {
2380
+ fields: z.z.array(TinaFieldZod).min(1, "Property `fields` cannot be empty.").optional().superRefine((val, ctx) => {
2390
2381
  const dups = findDuplicates(val == null ? void 0 : val.map((x) => x.name));
2391
2382
  if (dups) {
2392
2383
  ctx.addIssue({
2393
2384
  code: z.z.ZodIssueCode.custom,
2394
- message: `Fields must have a unique name, duplicate field names: ${dups}`
2385
+ message: duplicateFieldErrorMessage(dups)
2395
2386
  });
2396
2387
  }
2397
2388
  }),
2398
- templates: z.z.array(TemplateTemp).min(1).optional().superRefine((val, ctx) => {
2389
+ templates: z.z.array(TemplateTemp).min(1, "Property `templates` cannot be empty.").optional().superRefine((val, ctx) => {
2399
2390
  const dups = findDuplicates(val == null ? void 0 : val.map((x) => x.name));
2400
2391
  if (dups) {
2401
2392
  ctx.addIssue({
2402
2393
  code: z.z.ZodIssueCode.custom,
2403
- message: `Templates must have a unique name, duplicate template names: ${dups}`
2394
+ message: duplicateTemplateErrorMessage(dups)
2404
2395
  });
2405
2396
  }
2406
2397
  })
@@ -2415,7 +2406,7 @@ If you need to use this value in your content you can use the \`nameOverride\` p
2415
2406
  if (dups) {
2416
2407
  ctx.addIssue({
2417
2408
  code: z.z.ZodIssueCode.custom,
2418
- message: `Templates must have a unique name, duplicate template names: ${dups}`
2409
+ message: duplicateTemplateErrorMessage(dups)
2419
2410
  });
2420
2411
  }
2421
2412
  })
@@ -2435,10 +2426,17 @@ If you need to use this value in your content you can use the \`nameOverride\` p
2435
2426
  ],
2436
2427
  {
2437
2428
  errorMap: (issue, ctx) => {
2438
- var _a;
2429
+ var _a, _b;
2439
2430
  if (issue.code === "invalid_union_discriminator") {
2431
+ if (!((_a = ctx.data) == null ? void 0 : _a.type)) {
2432
+ return {
2433
+ message: `Missing \`type\` property in field \`${ctx.data.name}\`. Please add a \`type\` property with one of the following:
2434
+ ${formattedTypes}`
2435
+ };
2436
+ }
2440
2437
  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(", ")}`
2438
+ 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:
2439
+ ${formattedTypes}`
2442
2440
  };
2443
2441
  }
2444
2442
  return {
@@ -2448,77 +2446,52 @@ If you need to use this value in your content you can use the \`nameOverride\` p
2448
2446
  }
2449
2447
  ).superRefine((val, ctx) => {
2450
2448
  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
- }
2449
+ const stringifiedField = JSON.stringify(val, null, 2);
2450
+ if (val.isTitle && val.list) {
2451
+ ctx.addIssue({
2452
+ code: z.z.ZodIssueCode.custom,
2453
+ message: `\`list: true\` is not allowed when using \`isTitle\` for fields of \`type: string\`. Error found in field:
2454
+ ${stringifiedField}`
2455
+ });
2456
+ }
2457
+ if (val.isTitle && !val.required) {
2458
+ ctx.addIssue({
2459
+ code: z.z.ZodIssueCode.custom,
2460
+ message: `Property \`required: true\` is required when using \`isTitle\` for fields of \`type: string\`. Error found in field:
2461
+ ${stringifiedField}`
2462
+ });
2476
2463
  }
2477
- if (val.uid) {
2464
+ if (val.uid && val.list) {
2478
2465
  if (val.list) {
2479
2466
  ctx.addIssue({
2480
2467
  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
- `
2468
+ message: `\`list: true\` is not allowed when using \`uid\` for fields of \`type: string\`. Error found in field:
2469
+ ${stringifiedField}`
2500
2470
  });
2501
2471
  }
2502
2472
  }
2473
+ if (val.uid && !val.required) {
2474
+ ctx.addIssue({
2475
+ code: z.z.ZodIssueCode.custom,
2476
+ message: `Property \`required: true\` is required when using \`uid\` for fields of \`type: string\`. Error found in field:
2477
+ ${stringifiedField}`
2478
+ });
2479
+ }
2503
2480
  }
2504
2481
  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) {
2482
+ if (!(val == null ? void 0 : val.templates) && !(val == null ? void 0 : val.fields)) {
2508
2483
  ctx.addIssue({
2509
2484
  code: z.z.ZodIssueCode.custom,
2510
- message
2485
+ message: "Fields of `type: object` must have either `templates` or `fields` property."
2486
+ });
2487
+ return false;
2488
+ }
2489
+ if ((val == null ? void 0 : val.templates) && (val == null ? void 0 : val.fields)) {
2490
+ ctx.addIssue({
2491
+ code: z.z.ZodIssueCode.custom,
2492
+ message: "Fields of `type: object` must have either `templates` or `fields` property, not both."
2511
2493
  });
2512
2494
  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
2495
  }
2523
2496
  }
2524
2497
  return true;
@@ -2562,8 +2535,8 @@ ${JSON.stringify(
2562
2535
  ];
2563
2536
  const Template = z.z.object({
2564
2537
  label: z.z.string({
2565
- invalid_type_error: "label must be a string",
2566
- required_error: "label was not provided but is required"
2538
+ invalid_type_error: "Invalid data type for property `label`. Must be of type `string`",
2539
+ required_error: "Missing `label` property. Property `label` is required."
2567
2540
  }),
2568
2541
  name,
2569
2542
  fields: z.z.array(TinaFieldZod)
@@ -2573,7 +2546,7 @@ ${JSON.stringify(
2573
2546
  if (dups) {
2574
2547
  ctx.addIssue({
2575
2548
  code: z.z.ZodIssueCode.custom,
2576
- message: `Fields must have a unique name, duplicate field names: ${dups}`
2549
+ message: duplicateFieldErrorMessage(dups)
2577
2550
  });
2578
2551
  }
2579
2552
  });
@@ -2583,7 +2556,7 @@ ${JSON.stringify(
2583
2556
  if (val === "relativePath") {
2584
2557
  ctx.addIssue({
2585
2558
  code: z.z.ZodIssueCode.custom,
2586
- message: `name cannot be 'relativePath'. 'relativePath' is a reserved field name.`
2559
+ message: "Invalid `name` property. `name` cannot be 'relativePath' as it is a reserved field name."
2587
2560
  });
2588
2561
  }
2589
2562
  }),
@@ -2591,7 +2564,7 @@ ${JSON.stringify(
2591
2564
  if (val === ".") {
2592
2565
  ctx.addIssue({
2593
2566
  code: z.z.ZodIssueCode.custom,
2594
- message: `path cannot be '.'. Please use '/' or '' instead. `
2567
+ message: "Invalid `path` property. `path` cannot be '.'. Please use '/' or '' instead."
2595
2568
  });
2596
2569
  }
2597
2570
  }),
@@ -2600,63 +2573,64 @@ ${JSON.stringify(
2600
2573
  isDetached: z.z.boolean().optional()
2601
2574
  });
2602
2575
  const TinaCloudCollection = CollectionBaseSchema.extend({
2603
- fields: z.z.array(TinaFieldZod).min(1).optional().superRefine((val, ctx) => {
2576
+ fields: z.z.array(TinaFieldZod).min(1, "Property `fields` cannot be empty.").optional().superRefine((val, ctx) => {
2604
2577
  const dups = findDuplicates(val == null ? void 0 : val.map((x) => x.name));
2605
2578
  if (dups) {
2606
2579
  ctx.addIssue({
2607
2580
  code: z.z.ZodIssueCode.custom,
2608
- message: `Fields must have a unique name, duplicate field names: ${dups}`
2581
+ message: duplicateFieldErrorMessage(dups)
2609
2582
  });
2610
2583
  }
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"
2584
+ }).superRefine((val, ctx) => {
2585
+ const arr = (val == null ? void 0 : val.filter((x) => x.type === "string" && x.isTitle)) || [];
2586
+ if (arr.length > 1) {
2587
+ ctx.addIssue({
2588
+ code: z.z.ZodIssueCode.custom,
2589
+ message: `The following fields have the property \`isTitle\`: [${arr.map((field) => field.name).join(", ")}]. Only one can contain the property \`isTitle\`.`
2590
+ });
2591
+ }
2592
+ }).superRefine((val, ctx) => {
2593
+ const arr = (val == null ? void 0 : val.filter((x) => x.uid)) || [];
2594
+ if (arr.length > 2) {
2595
+ ctx.addIssue({
2596
+ code: z.z.ZodIssueCode.custom,
2597
+ message: `The following fields have the property \`uid\`: [${arr.map((field) => field.name).join(", ")}]. Only one can contain the property \`uid\`.`
2598
+ });
2599
+ }
2600
+ }).superRefine((val, ctx) => {
2601
+ const arr = (val == null ? void 0 : val.filter((x) => x.type === "password")) || [];
2602
+ if (arr.length > 2) {
2603
+ ctx.addIssue({
2604
+ code: z.z.ZodIssueCode.custom,
2605
+ message: `The following fields have \`type: password\`: [${arr.map((field) => field.name).join(", ")}]. Only one can be of \`type: password\`.`
2606
+ });
2637
2607
  }
2638
- ),
2639
- templates: z.z.array(Template).min(1).optional().superRefine((val, ctx) => {
2608
+ }),
2609
+ templates: z.z.array(Template).min(1, "Property `templates` cannot be empty.").optional().superRefine((val, ctx) => {
2640
2610
  const dups = findDuplicates(val == null ? void 0 : val.map((x) => x.name));
2641
2611
  if (dups) {
2642
2612
  ctx.addIssue({
2643
2613
  code: z.z.ZodIssueCode.custom,
2644
- message: `Templates must have a unique name, duplicate template names: ${dups}`
2614
+ message: duplicateFieldErrorMessage(dups)
2645
2615
  });
2646
2616
  }
2647
2617
  })
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
- );
2618
+ }).superRefine((val, ctx) => {
2619
+ if (!(val == null ? void 0 : val.templates) && !(val == null ? void 0 : val.fields)) {
2620
+ ctx.addIssue({
2621
+ code: z.z.ZodIssueCode.custom,
2622
+ message: "Fields of `type: object` must have either `templates` or `fields` property."
2623
+ });
2624
+ return false;
2625
+ }
2626
+ if ((val == null ? void 0 : val.templates) && (val == null ? void 0 : val.fields)) {
2627
+ ctx.addIssue({
2628
+ code: z.z.ZodIssueCode.custom,
2629
+ message: "Fields of `type: object` must have either `templates` or `fields` property, not both."
2630
+ });
2631
+ return false;
2632
+ }
2633
+ });
2660
2634
  const TinaCloudSchemaZod = z.z.object({
2661
2635
  collections: z.z.array(TinaCloudCollection),
2662
2636
  config: tinaConfigZod.optional()
@@ -2666,14 +2640,14 @@ ${JSON.stringify(
2666
2640
  if (dups) {
2667
2641
  ctx.addIssue({
2668
2642
  code: z.z.ZodIssueCode.custom,
2669
- message: `${dups} are duplicate names in your collections. Collection names must be unique.`,
2643
+ message: duplicateCollectionErrorMessage(dups),
2670
2644
  fatal: true
2671
2645
  });
2672
2646
  }
2673
2647
  if (((_b = val.collections) == null ? void 0 : _b.filter((x) => x.isAuthCollection).length) > 1) {
2674
2648
  ctx.addIssue({
2675
2649
  code: z.z.ZodIssueCode.custom,
2676
- message: `Only one collection can be marked as isAuthCollection`,
2650
+ message: "Only one collection can be marked as `isAuthCollection`.",
2677
2651
  fatal: true
2678
2652
  });
2679
2653
  }
@@ -2681,7 +2655,7 @@ ${JSON.stringify(
2681
2655
  if (media && media.tina && media.loadCustomStore) {
2682
2656
  ctx.addIssue({
2683
2657
  code: z.z.ZodIssueCode.custom,
2684
- message: "can not have both loadCustomStore and tina. Must use one or the other",
2658
+ message: "Cannot have both `loadCustomStore` and `tina`. Must use one or the other.",
2685
2659
  fatal: true,
2686
2660
  path: ["config", "media"]
2687
2661
  });
@@ -2690,7 +2664,7 @@ ${JSON.stringify(
2690
2664
  if (search && search.tina && search.searchClient) {
2691
2665
  ctx.addIssue({
2692
2666
  code: z.z.ZodIssueCode.custom,
2693
- message: "can not have both searchClient and tina. Must use one or the other",
2667
+ message: "Cannot have both `searchClient` and `tina`. Must use one or the other.",
2694
2668
  fatal: true,
2695
2669
  path: ["config", "search"]
2696
2670
  });
@@ -2708,7 +2682,7 @@ ${JSON.stringify(
2708
2682
  } catch (e) {
2709
2683
  if (e instanceof z.ZodError) {
2710
2684
  const errors = parseZodError({ zodError: e });
2711
- throw new TinaSchemaValidationError(errors.join(", \n"));
2685
+ throw new TinaSchemaValidationError(errors.join("\n"));
2712
2686
  }
2713
2687
  throw new Error(e);
2714
2688
  }
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;
@@ -2222,9 +2206,12 @@ const parseZodError = ({ zodError }) => {
2222
2206
  moreInfo.push(parseZodError({ zodError: unionError }));
2223
2207
  });
2224
2208
  }
2225
- const errorMessage = `Error ${issue == null ? void 0 : issue.message} at path ${issue.path.join(
2209
+ const errorMessage = `${issue == null ? void 0 : issue.message}
2210
+ Additional information:
2211
+ - Error found at path ${issue.path.join(
2226
2212
  "."
2227
- )}`;
2213
+ )}
2214
+ `;
2228
2215
  const errorMessages = [errorMessage, ...moreInfo];
2229
2216
  return {
2230
2217
  errors: errorMessages
@@ -2259,6 +2246,9 @@ If you need to use this value in your content you can use the \`nameOverride\` p
2259
2246
  });
2260
2247
  }
2261
2248
  });
2249
+ const duplicateFieldErrorMessage = (fields) => `Fields must have unique names. Found duplicate field names: [${fields}]`;
2250
+ const duplicateTemplateErrorMessage = (templates) => `Templates must have unique names. Found duplicate template names: [${templates}]`;
2251
+ const duplicateCollectionErrorMessage = (collection) => `Collections must have unique names. Found duplicate collection names: [${collection}]`;
2262
2252
  const TypeName = [
2263
2253
  "string",
2264
2254
  "boolean",
@@ -2269,10 +2259,11 @@ const TypeName = [
2269
2259
  "reference",
2270
2260
  "rich-text"
2271
2261
  ];
2272
- const typeTypeError = `type must be one of ${TypeName.join(", ")}`;
2273
- const typeRequiredError = `type is required and must be one of ${TypeName.join(
2274
- ", "
2275
- )}`;
2262
+ const formattedTypes = ` - ${TypeName.join("\n - ")}`;
2263
+ const typeTypeError = `Invalid \`type\` property. \`type\` expected to be one of the following values:
2264
+ ${formattedTypes}`;
2265
+ const typeRequiredError = `Missing \`type\` property. Please add a \`type\` property with one of the following:
2266
+ ${formattedTypes}`;
2276
2267
  const Option = z.union(
2277
2268
  [
2278
2269
  z.string(),
@@ -2358,7 +2349,7 @@ const TinaFieldZod = z.lazy(() => {
2358
2349
  if (dups) {
2359
2350
  ctx.addIssue({
2360
2351
  code: z.ZodIssueCode.custom,
2361
- message: `Fields must have a unique name, duplicate field names: ${dups}`
2352
+ message: duplicateFieldErrorMessage(dups)
2362
2353
  });
2363
2354
  }
2364
2355
  });
@@ -2368,21 +2359,21 @@ const TinaFieldZod = z.lazy(() => {
2368
2359
  invalid_type_error: typeTypeError,
2369
2360
  required_error: typeRequiredError
2370
2361
  }),
2371
- fields: z.array(TinaFieldZod).min(1).optional().superRefine((val, ctx) => {
2362
+ fields: z.array(TinaFieldZod).min(1, "Property `fields` cannot be empty.").optional().superRefine((val, ctx) => {
2372
2363
  const dups = findDuplicates(val == null ? void 0 : val.map((x) => x.name));
2373
2364
  if (dups) {
2374
2365
  ctx.addIssue({
2375
2366
  code: z.ZodIssueCode.custom,
2376
- message: `Fields must have a unique name, duplicate field names: ${dups}`
2367
+ message: duplicateFieldErrorMessage(dups)
2377
2368
  });
2378
2369
  }
2379
2370
  }),
2380
- templates: z.array(TemplateTemp).min(1).optional().superRefine((val, ctx) => {
2371
+ templates: z.array(TemplateTemp).min(1, "Property `templates` cannot be empty.").optional().superRefine((val, ctx) => {
2381
2372
  const dups = findDuplicates(val == null ? void 0 : val.map((x) => x.name));
2382
2373
  if (dups) {
2383
2374
  ctx.addIssue({
2384
2375
  code: z.ZodIssueCode.custom,
2385
- message: `Templates must have a unique name, duplicate template names: ${dups}`
2376
+ message: duplicateTemplateErrorMessage(dups)
2386
2377
  });
2387
2378
  }
2388
2379
  })
@@ -2397,7 +2388,7 @@ const TinaFieldZod = z.lazy(() => {
2397
2388
  if (dups) {
2398
2389
  ctx.addIssue({
2399
2390
  code: z.ZodIssueCode.custom,
2400
- message: `Templates must have a unique name, duplicate template names: ${dups}`
2391
+ message: duplicateTemplateErrorMessage(dups)
2401
2392
  });
2402
2393
  }
2403
2394
  })
@@ -2417,10 +2408,17 @@ const TinaFieldZod = z.lazy(() => {
2417
2408
  ],
2418
2409
  {
2419
2410
  errorMap: (issue, ctx) => {
2420
- var _a;
2411
+ var _a, _b;
2421
2412
  if (issue.code === "invalid_union_discriminator") {
2413
+ if (!((_a = ctx.data) == null ? void 0 : _a.type)) {
2414
+ return {
2415
+ message: `Missing \`type\` property in field \`${ctx.data.name}\`. Please add a \`type\` property with one of the following:
2416
+ ${formattedTypes}`
2417
+ };
2418
+ }
2422
2419
  return {
2423
- message: `Invalid \`type\` property. In the schema is 'type: ${(_a = ctx.data) == null ? void 0 : _a.type}' and expected one of ${TypeName.join(", ")}`
2420
+ 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:
2421
+ ${formattedTypes}`
2424
2422
  };
2425
2423
  }
2426
2424
  return {
@@ -2430,77 +2428,52 @@ const TinaFieldZod = z.lazy(() => {
2430
2428
  }
2431
2429
  ).superRefine((val, ctx) => {
2432
2430
  if (val.type === "string") {
2433
- if (val.isTitle) {
2434
- if (val.list) {
2435
- ctx.addIssue({
2436
- code: z.ZodIssueCode.custom,
2437
- message: `Can not have \`list: true\` when using \`isTitle\`. Error in value
2438
- ${JSON.stringify(
2439
- val,
2440
- null,
2441
- 2
2442
- )}
2443
- `
2444
- });
2445
- }
2446
- if (!val.required) {
2447
- ctx.addIssue({
2448
- code: z.ZodIssueCode.custom,
2449
- message: `Must have { required: true } when using \`isTitle\` Error in value
2450
- ${JSON.stringify(
2451
- val,
2452
- null,
2453
- 2
2454
- )}
2455
- `
2456
- });
2457
- }
2431
+ const stringifiedField = JSON.stringify(val, null, 2);
2432
+ if (val.isTitle && val.list) {
2433
+ ctx.addIssue({
2434
+ code: z.ZodIssueCode.custom,
2435
+ message: `\`list: true\` is not allowed when using \`isTitle\` for fields of \`type: string\`. Error found in field:
2436
+ ${stringifiedField}`
2437
+ });
2438
+ }
2439
+ if (val.isTitle && !val.required) {
2440
+ ctx.addIssue({
2441
+ code: z.ZodIssueCode.custom,
2442
+ message: `Property \`required: true\` is required when using \`isTitle\` for fields of \`type: string\`. Error found in field:
2443
+ ${stringifiedField}`
2444
+ });
2458
2445
  }
2459
- if (val.uid) {
2446
+ if (val.uid && val.list) {
2460
2447
  if (val.list) {
2461
2448
  ctx.addIssue({
2462
2449
  code: z.ZodIssueCode.custom,
2463
- message: `Can not have \`list: true\` when using \`uid\`. Error in value
2464
- ${JSON.stringify(
2465
- val,
2466
- null,
2467
- 2
2468
- )}
2469
- `
2470
- });
2471
- }
2472
- if (!val.required) {
2473
- ctx.addIssue({
2474
- code: z.ZodIssueCode.custom,
2475
- message: `Must have { required: true } when using \`uid\` Error in value
2476
- ${JSON.stringify(
2477
- val,
2478
- null,
2479
- 2
2480
- )}
2481
- `
2450
+ message: `\`list: true\` is not allowed when using \`uid\` for fields of \`type: string\`. Error found in field:
2451
+ ${stringifiedField}`
2482
2452
  });
2483
2453
  }
2484
2454
  }
2455
+ if (val.uid && !val.required) {
2456
+ ctx.addIssue({
2457
+ code: z.ZodIssueCode.custom,
2458
+ message: `Property \`required: true\` is required when using \`uid\` for fields of \`type: string\`. Error found in field:
2459
+ ${stringifiedField}`
2460
+ });
2461
+ }
2485
2462
  }
2486
2463
  if (val.type === "object") {
2487
- const message = "Must provide one of templates or fields in your collection";
2488
- let isValid = Boolean(val == null ? void 0 : val.templates) || Boolean(val == null ? void 0 : val.fields);
2489
- if (!isValid) {
2464
+ if (!(val == null ? void 0 : val.templates) && !(val == null ? void 0 : val.fields)) {
2490
2465
  ctx.addIssue({
2491
2466
  code: z.ZodIssueCode.custom,
2492
- message
2467
+ message: "Fields of `type: object` must have either `templates` or `fields` property."
2468
+ });
2469
+ return false;
2470
+ }
2471
+ if ((val == null ? void 0 : val.templates) && (val == null ? void 0 : val.fields)) {
2472
+ ctx.addIssue({
2473
+ code: z.ZodIssueCode.custom,
2474
+ message: "Fields of `type: object` must have either `templates` or `fields` property, not both."
2493
2475
  });
2494
2476
  return false;
2495
- } else {
2496
- isValid = !((val == null ? void 0 : val.templates) && (val == null ? void 0 : val.fields));
2497
- if (!isValid) {
2498
- ctx.addIssue({
2499
- code: z.ZodIssueCode.custom,
2500
- message
2501
- });
2502
- }
2503
- return isValid;
2504
2477
  }
2505
2478
  }
2506
2479
  return true;
@@ -2544,8 +2517,8 @@ const FORMATS = [
2544
2517
  ];
2545
2518
  const Template = z.object({
2546
2519
  label: z.string({
2547
- invalid_type_error: "label must be a string",
2548
- required_error: "label was not provided but is required"
2520
+ invalid_type_error: "Invalid data type for property `label`. Must be of type `string`",
2521
+ required_error: "Missing `label` property. Property `label` is required."
2549
2522
  }),
2550
2523
  name,
2551
2524
  fields: z.array(TinaFieldZod)
@@ -2555,7 +2528,7 @@ const Template = z.object({
2555
2528
  if (dups) {
2556
2529
  ctx.addIssue({
2557
2530
  code: z.ZodIssueCode.custom,
2558
- message: `Fields must have a unique name, duplicate field names: ${dups}`
2531
+ message: duplicateFieldErrorMessage(dups)
2559
2532
  });
2560
2533
  }
2561
2534
  });
@@ -2565,7 +2538,7 @@ const CollectionBaseSchema = z.object({
2565
2538
  if (val === "relativePath") {
2566
2539
  ctx.addIssue({
2567
2540
  code: z.ZodIssueCode.custom,
2568
- message: `name cannot be 'relativePath'. 'relativePath' is a reserved field name.`
2541
+ message: "Invalid `name` property. `name` cannot be 'relativePath' as it is a reserved field name."
2569
2542
  });
2570
2543
  }
2571
2544
  }),
@@ -2573,7 +2546,7 @@ const CollectionBaseSchema = z.object({
2573
2546
  if (val === ".") {
2574
2547
  ctx.addIssue({
2575
2548
  code: z.ZodIssueCode.custom,
2576
- message: `path cannot be '.'. Please use '/' or '' instead. `
2549
+ message: "Invalid `path` property. `path` cannot be '.'. Please use '/' or '' instead."
2577
2550
  });
2578
2551
  }
2579
2552
  }),
@@ -2582,63 +2555,64 @@ const CollectionBaseSchema = z.object({
2582
2555
  isDetached: z.boolean().optional()
2583
2556
  });
2584
2557
  const TinaCloudCollection = CollectionBaseSchema.extend({
2585
- fields: z.array(TinaFieldZod).min(1).optional().superRefine((val, ctx) => {
2558
+ fields: z.array(TinaFieldZod).min(1, "Property `fields` cannot be empty.").optional().superRefine((val, ctx) => {
2586
2559
  const dups = findDuplicates(val == null ? void 0 : val.map((x) => x.name));
2587
2560
  if (dups) {
2588
2561
  ctx.addIssue({
2589
2562
  code: z.ZodIssueCode.custom,
2590
- message: `Fields must have a unique name, duplicate field names: ${dups}`
2563
+ message: duplicateFieldErrorMessage(dups)
2591
2564
  });
2592
2565
  }
2593
- }).refine(
2594
- // It is valid if it is 0 or 1
2595
- (val) => {
2596
- const arr = (val == null ? void 0 : val.filter((x) => x.type === "string" && x.isTitle)) || [];
2597
- return arr.length < 2;
2598
- },
2599
- {
2600
- message: "Fields can only have one use of `isTitle`"
2601
- }
2602
- ).refine(
2603
- // It is valid if it is 0 or 1
2604
- (val) => {
2605
- const arr = (val == null ? void 0 : val.filter((x) => x.uid)) || [];
2606
- return arr.length < 2;
2607
- },
2608
- {
2609
- message: "Fields can only have one use of `uid`"
2610
- }
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 === "password")) || [];
2615
- return arr.length < 2;
2616
- },
2617
- {
2618
- message: "Fields can only have one use of `password` type"
2566
+ }).superRefine((val, ctx) => {
2567
+ const arr = (val == null ? void 0 : val.filter((x) => x.type === "string" && x.isTitle)) || [];
2568
+ if (arr.length > 1) {
2569
+ ctx.addIssue({
2570
+ code: z.ZodIssueCode.custom,
2571
+ message: `The following fields have the property \`isTitle\`: [${arr.map((field) => field.name).join(", ")}]. Only one can contain the property \`isTitle\`.`
2572
+ });
2573
+ }
2574
+ }).superRefine((val, ctx) => {
2575
+ const arr = (val == null ? void 0 : val.filter((x) => x.uid)) || [];
2576
+ if (arr.length > 2) {
2577
+ ctx.addIssue({
2578
+ code: z.ZodIssueCode.custom,
2579
+ message: `The following fields have the property \`uid\`: [${arr.map((field) => field.name).join(", ")}]. Only one can contain the property \`uid\`.`
2580
+ });
2581
+ }
2582
+ }).superRefine((val, ctx) => {
2583
+ const arr = (val == null ? void 0 : val.filter((x) => x.type === "password")) || [];
2584
+ if (arr.length > 2) {
2585
+ ctx.addIssue({
2586
+ code: z.ZodIssueCode.custom,
2587
+ message: `The following fields have \`type: password\`: [${arr.map((field) => field.name).join(", ")}]. Only one can be of \`type: password\`.`
2588
+ });
2619
2589
  }
2620
- ),
2621
- templates: z.array(Template).min(1).optional().superRefine((val, ctx) => {
2590
+ }),
2591
+ templates: z.array(Template).min(1, "Property `templates` cannot be empty.").optional().superRefine((val, ctx) => {
2622
2592
  const dups = findDuplicates(val == null ? void 0 : val.map((x) => x.name));
2623
2593
  if (dups) {
2624
2594
  ctx.addIssue({
2625
2595
  code: z.ZodIssueCode.custom,
2626
- message: `Templates must have a unique name, duplicate template names: ${dups}`
2596
+ message: duplicateFieldErrorMessage(dups)
2627
2597
  });
2628
2598
  }
2629
2599
  })
2630
- }).refine(
2631
- (val) => {
2632
- let isValid = Boolean(val == null ? void 0 : val.templates) || Boolean(val == null ? void 0 : val.fields);
2633
- if (!isValid) {
2634
- return false;
2635
- } else {
2636
- isValid = !((val == null ? void 0 : val.templates) && (val == null ? void 0 : val.fields));
2637
- return isValid;
2638
- }
2639
- },
2640
- { message: "Must provide one of templates or fields in your collection" }
2641
- );
2600
+ }).superRefine((val, ctx) => {
2601
+ if (!(val == null ? void 0 : val.templates) && !(val == null ? void 0 : val.fields)) {
2602
+ ctx.addIssue({
2603
+ code: z.ZodIssueCode.custom,
2604
+ message: "Fields of `type: object` must have either `templates` or `fields` property."
2605
+ });
2606
+ return false;
2607
+ }
2608
+ if ((val == null ? void 0 : val.templates) && (val == null ? void 0 : val.fields)) {
2609
+ ctx.addIssue({
2610
+ code: z.ZodIssueCode.custom,
2611
+ message: "Fields of `type: object` must have either `templates` or `fields` property, not both."
2612
+ });
2613
+ return false;
2614
+ }
2615
+ });
2642
2616
  const TinaCloudSchemaZod = z.object({
2643
2617
  collections: z.array(TinaCloudCollection),
2644
2618
  config: tinaConfigZod.optional()
@@ -2648,14 +2622,14 @@ const TinaCloudSchemaZod = z.object({
2648
2622
  if (dups) {
2649
2623
  ctx.addIssue({
2650
2624
  code: z.ZodIssueCode.custom,
2651
- message: `${dups} are duplicate names in your collections. Collection names must be unique.`,
2625
+ message: duplicateCollectionErrorMessage(dups),
2652
2626
  fatal: true
2653
2627
  });
2654
2628
  }
2655
2629
  if (((_b = val.collections) == null ? void 0 : _b.filter((x) => x.isAuthCollection).length) > 1) {
2656
2630
  ctx.addIssue({
2657
2631
  code: z.ZodIssueCode.custom,
2658
- message: `Only one collection can be marked as isAuthCollection`,
2632
+ message: "Only one collection can be marked as `isAuthCollection`.",
2659
2633
  fatal: true
2660
2634
  });
2661
2635
  }
@@ -2663,7 +2637,7 @@ const TinaCloudSchemaZod = z.object({
2663
2637
  if (media && media.tina && media.loadCustomStore) {
2664
2638
  ctx.addIssue({
2665
2639
  code: z.ZodIssueCode.custom,
2666
- message: "can not have both loadCustomStore and tina. Must use one or the other",
2640
+ message: "Cannot have both `loadCustomStore` and `tina`. Must use one or the other.",
2667
2641
  fatal: true,
2668
2642
  path: ["config", "media"]
2669
2643
  });
@@ -2672,7 +2646,7 @@ const TinaCloudSchemaZod = z.object({
2672
2646
  if (search && search.tina && search.searchClient) {
2673
2647
  ctx.addIssue({
2674
2648
  code: z.ZodIssueCode.custom,
2675
- message: "can not have both searchClient and tina. Must use one or the other",
2649
+ message: "Cannot have both `searchClient` and `tina`. Must use one or the other.",
2676
2650
  fatal: true,
2677
2651
  path: ["config", "search"]
2678
2652
  });
@@ -2690,7 +2664,7 @@ const validateSchema = ({ schema }) => {
2690
2664
  } catch (e) {
2691
2665
  if (e instanceof ZodError) {
2692
2666
  const errors = parseZodError({ zodError: e });
2693
- throw new TinaSchemaValidationError(errors.join(", \n"));
2667
+ throw new TinaSchemaValidationError(errors.join("\n"));
2694
2668
  }
2695
2669
  throw new Error(e);
2696
2670
  }
@@ -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 {};
@@ -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
+ /**@deprecated use overrides.toolbar */
201
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`).
@@ -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": "1.6.8",
3
+ "version": "1.7.0",
4
4
  "main": "dist/index.js",
5
5
  "module": "./dist/index.mjs",
6
6
  "exports": {