@tinacms/schema-tools 0.0.0-c45ac5d-20241213020122 → 0.0.0-c466c52-20250801052040

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) => {
@@ -2540,15 +2583,6 @@ ${stringifiedField}`
2540
2583
  const newConfig = tinaConfigZod.parse(config);
2541
2584
  return newConfig;
2542
2585
  };
2543
- const FORMATS = [
2544
- "json",
2545
- "md",
2546
- "markdown",
2547
- "mdx",
2548
- "toml",
2549
- "yaml",
2550
- "yml"
2551
- ];
2552
2586
  const Template = z.z.object({
2553
2587
  label: z.z.string({
2554
2588
  invalid_type_error: "Invalid data type for property `label`. Must be of type `string`",
@@ -2584,7 +2618,7 @@ ${stringifiedField}`
2584
2618
  });
2585
2619
  }
2586
2620
  }),
2587
- format: z.z.enum(FORMATS).optional(),
2621
+ format: z.z.enum(CONTENT_FORMATS).optional(),
2588
2622
  isAuthCollection: z.z.boolean().optional(),
2589
2623
  isDetached: z.z.boolean().optional()
2590
2624
  });
@@ -2703,11 +2737,13 @@ ${stringifiedField}`
2703
2737
  throw new Error(e);
2704
2738
  }
2705
2739
  };
2740
+ exports2.CONTENT_FORMATS = CONTENT_FORMATS;
2706
2741
  exports2.NAMER = NAMER;
2707
2742
  exports2.TINA_HOST = TINA_HOST;
2708
2743
  exports2.TinaSchema = TinaSchema;
2709
2744
  exports2.TinaSchemaValidationError = TinaSchemaValidationError;
2710
2745
  exports2.addNamespaceToSchema = addNamespaceToSchema;
2746
+ exports2.canonicalPath = canonicalPath;
2711
2747
  exports2.normalizePath = normalizePath;
2712
2748
  exports2.parseURL = parseURL;
2713
2749
  exports2.resolveField = resolveField;
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;
@@ -1662,6 +1646,9 @@ const parseURL = (url) => {
1662
1646
  };
1663
1647
  };
1664
1648
  const normalizePath = (filepath) => filepath.replace(/\\/g, "/");
1649
+ const canonicalPath = (filepath) => {
1650
+ return normalizePath(filepath).split("/").filter((name2) => name2 !== "").join("/");
1651
+ };
1665
1652
  class TinaSchema {
1666
1653
  /**
1667
1654
  * Create a schema class from a user defined schema object
@@ -1711,21 +1698,21 @@ class TinaSchema {
1711
1698
  };
1712
1699
  this.getCollectionByFullPath = (filepath) => {
1713
1700
  const fileExtension = filepath.split(".").pop();
1714
- const normalizedPath = filepath.replace(/\\/g, "/");
1701
+ const canonicalFilepath = canonicalPath(filepath);
1715
1702
  const possibleCollections = this.getCollections().filter((collection) => {
1716
1703
  var _a, _b;
1717
- if (!normalizedPath.endsWith(`.gitkeep.${collection.format || "md"}`) && fileExtension !== (collection.format || "md")) {
1704
+ if (!canonicalFilepath.endsWith(`.gitkeep.${collection.format || "md"}`) && fileExtension !== (collection.format || "md")) {
1718
1705
  return false;
1719
1706
  }
1720
1707
  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)) {
1721
1708
  const matches = this.getMatches({ collection });
1722
- const match = picomatch$1.isMatch(normalizedPath, matches);
1709
+ const match = picomatch$1.isMatch(canonicalFilepath, matches);
1723
1710
  if (!match) {
1724
1711
  return false;
1725
1712
  }
1726
1713
  }
1727
- const path = collection.path ? collection.path.replace(/\/?$/, "/") : "";
1728
- return normalizedPath.startsWith(path);
1714
+ const collectionPath = canonicalPath(collection.path);
1715
+ return collectionPath === "" || canonicalFilepath.startsWith(`${collectionPath}/`);
1729
1716
  });
1730
1717
  if (possibleCollections.length === 0) {
1731
1718
  throw new Error(`Unable to find collection for file at ${filepath}`);
@@ -1943,7 +1930,7 @@ class TinaSchema {
1943
1930
  }
1944
1931
  }
1945
1932
  };
1946
- this.walkFields = (cb) => {
1933
+ this.legacyWalkFields = (cb) => {
1947
1934
  const walk = (collectionOrObject, collection, path) => {
1948
1935
  if (collectionOrObject.templates) {
1949
1936
  collectionOrObject.templates.forEach((template) => {
@@ -1965,7 +1952,7 @@ class TinaSchema {
1965
1952
  collections.forEach((collection) => walk(collection, collection, []));
1966
1953
  };
1967
1954
  this.schema = config;
1968
- this.walkFields(({ field, collection, path }) => {
1955
+ this.legacyWalkFields(({ field, collection }) => {
1969
1956
  if (!("searchable" in field)) {
1970
1957
  if (field.type === "image") {
1971
1958
  field.searchable = false;
@@ -1986,20 +1973,67 @@ class TinaSchema {
1986
1973
  field.uid = field.uid || false;
1987
1974
  });
1988
1975
  }
1989
- findReferences(name2) {
1976
+ findReferencesFromCollection(name2) {
1990
1977
  const result = {};
1991
1978
  this.walkFields(({ field, collection: c, path }) => {
1979
+ if (c.name !== name2) {
1980
+ return;
1981
+ }
1992
1982
  if (field.type === "reference") {
1993
- if (field.collections.includes(name2)) {
1994
- if (result[c.name] === void 0) {
1995
- result[c.name] = [];
1983
+ field.collections.forEach((name22) => {
1984
+ if (result[name22] === void 0) {
1985
+ result[name22] = [];
1996
1986
  }
1997
- result[c.name].push({ path, field });
1998
- }
1987
+ result[name22].push(path);
1988
+ });
1999
1989
  }
2000
1990
  });
2001
1991
  return result;
2002
1992
  }
1993
+ /**
1994
+ * Walk all fields in tina schema
1995
+ *
1996
+ * @param cb callback function invoked for each field
1997
+ */
1998
+ walkFields(cb) {
1999
+ const walk = (collectionOrObject, collection, path = "$") => {
2000
+ if (collectionOrObject.templates) {
2001
+ collectionOrObject.templates.forEach((template) => {
2002
+ const templatePath = `${path}.${template.name}`;
2003
+ template.fields.forEach((field) => {
2004
+ const fieldPath = field.list ? `${templatePath}[*].${field.name}` : `${templatePath}.${field.name}`;
2005
+ cb({ field, collection, path: fieldPath });
2006
+ if (field.type === "object") {
2007
+ walk(field, collection, fieldPath);
2008
+ }
2009
+ });
2010
+ });
2011
+ }
2012
+ if (collectionOrObject.fields) {
2013
+ collectionOrObject.fields.forEach((field) => {
2014
+ const fieldPath = field.list ? `${path}.${field.name}[*]` : `${path}.${field.name}`;
2015
+ cb({ field, collection, path: fieldPath });
2016
+ if (field.type === "object" && field.fields) {
2017
+ walk(field, collection, fieldPath);
2018
+ } else if (field.templates) {
2019
+ field.templates.forEach((template) => {
2020
+ const templatePath = `${fieldPath}.${template.name}`;
2021
+ template.fields.forEach((field2) => {
2022
+ const fieldPath2 = field2.list ? `${templatePath}[*].${field2.name}` : `${templatePath}.${field2.name}`;
2023
+ cb({ field: field2, collection, path: fieldPath2 });
2024
+ if (field2.type === "object") {
2025
+ walk(field2, collection, fieldPath2);
2026
+ }
2027
+ });
2028
+ });
2029
+ }
2030
+ });
2031
+ }
2032
+ };
2033
+ this.getCollections().forEach((collection) => {
2034
+ walk(collection, collection);
2035
+ });
2036
+ }
2003
2037
  /**
2004
2038
  * This function returns an array of glob matches for a given collection.
2005
2039
  *
@@ -2011,16 +2045,16 @@ class TinaSchema {
2011
2045
  }) {
2012
2046
  var _a, _b;
2013
2047
  const collection = typeof collectionOrString === "string" ? this.getCollection(collectionOrString) : collectionOrString;
2014
- const normalPath = normalizePath(collection.path);
2015
- const pathSuffix = normalPath ? "/" : "";
2048
+ const collectionPath = canonicalPath(collection.path);
2049
+ const pathSuffix = collectionPath ? "/" : "";
2016
2050
  const format = collection.format || "md";
2017
2051
  const matches = [];
2018
2052
  if ((_a = collection == null ? void 0 : collection.match) == null ? void 0 : _a.include) {
2019
- const match = `${normalPath}${pathSuffix}${collection.match.include}.${format}`;
2053
+ const match = `${collectionPath}${pathSuffix}${collection.match.include}.${format}`;
2020
2054
  matches.push(match);
2021
2055
  }
2022
2056
  if ((_b = collection == null ? void 0 : collection.match) == null ? void 0 : _b.exclude) {
2023
- const exclude = `!(${normalPath}${pathSuffix}${collection.match.exclude}.${format})`;
2057
+ const exclude = `!(${collectionPath}${pathSuffix}${collection.match.exclude}.${format})`;
2024
2058
  matches.push(exclude);
2025
2059
  }
2026
2060
  return matches;
@@ -2213,6 +2247,15 @@ const resolveForm = ({
2213
2247
  })
2214
2248
  };
2215
2249
  };
2250
+ const CONTENT_FORMATS = [
2251
+ "mdx",
2252
+ "md",
2253
+ "markdown",
2254
+ "json",
2255
+ "yaml",
2256
+ "yml",
2257
+ "toml"
2258
+ ];
2216
2259
  const parseZodError = ({ zodError }) => {
2217
2260
  var _a, _b, _c, _d;
2218
2261
  const errors = zodError.flatten((issue) => {
@@ -2522,15 +2565,6 @@ const validateTinaCloudSchemaConfig = (config) => {
2522
2565
  const newConfig = tinaConfigZod.parse(config);
2523
2566
  return newConfig;
2524
2567
  };
2525
- const FORMATS = [
2526
- "json",
2527
- "md",
2528
- "markdown",
2529
- "mdx",
2530
- "toml",
2531
- "yaml",
2532
- "yml"
2533
- ];
2534
2568
  const Template = z.object({
2535
2569
  label: z.string({
2536
2570
  invalid_type_error: "Invalid data type for property `label`. Must be of type `string`",
@@ -2566,7 +2600,7 @@ const CollectionBaseSchema = z.object({
2566
2600
  });
2567
2601
  }
2568
2602
  }),
2569
- format: z.enum(FORMATS).optional(),
2603
+ format: z.enum(CONTENT_FORMATS).optional(),
2570
2604
  isAuthCollection: z.boolean().optional(),
2571
2605
  isDetached: z.boolean().optional()
2572
2606
  });
@@ -2686,11 +2720,13 @@ const validateSchema = ({ schema }) => {
2686
2720
  }
2687
2721
  };
2688
2722
  export {
2723
+ CONTENT_FORMATS,
2689
2724
  NAMER,
2690
2725
  TINA_HOST,
2691
2726
  TinaSchema,
2692
2727
  TinaSchemaValidationError,
2693
2728
  addNamespaceToSchema,
2729
+ canonicalPath,
2694
2730
  normalizePath,
2695
2731
  parseURL,
2696
2732
  resolveField,
@@ -28,10 +28,7 @@ export declare class TinaSchema {
28
28
  } & Schema);
29
29
  getIsTitleFieldName: (collection: string) => string;
30
30
  getCollectionsByName: (collectionNames: string[]) => Collection<true>[];
31
- findReferences(name: string): Record<string, {
32
- path: string[];
33
- field: TinaField;
34
- }[]>;
31
+ findReferencesFromCollection(name: string): Record<string, string[]>;
35
32
  getCollection: (collectionName: string) => Collection<true>;
36
33
  getCollections: () => Collection<true>[];
37
34
  getCollectionByFullPath: (filepath: string) => Collection<true>;
@@ -63,7 +60,26 @@ export declare class TinaSchema {
63
60
  *
64
61
  */
65
62
  getTemplatesForCollectable: (collection: Collectable) => CollectionTemplateable;
66
- walkFields: (cb: (args: {
63
+ /**
64
+ * Walk all fields in tina schema
65
+ *
66
+ * @param cb callback function invoked for each field
67
+ */
68
+ walkFields(cb: (args: {
69
+ field: any;
70
+ collection: any;
71
+ path: string;
72
+ isListItem?: boolean;
73
+ }) => void): void;
74
+ /**
75
+ * Walk all fields in Tina Schema
76
+ *
77
+ * This is a legacy version to preserve backwards compatibility for the tina generated schema. It does not
78
+ * traverse fields in object lists in rich-text templates.
79
+ *
80
+ * @param cb callback function invoked for each field
81
+ */
82
+ legacyWalkFields: (cb: (args: {
67
83
  field: TinaField;
68
84
  collection: Collection;
69
85
  path: string[];
@@ -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 {};
@@ -1,5 +1,23 @@
1
1
  import type { FC } from 'react';
2
2
  import type React from 'react';
3
+ export declare const CONTENT_FORMATS: readonly ["mdx", "md", "markdown", "json", "yaml", "yml", "toml"];
4
+ export type ContentFormat = (typeof CONTENT_FORMATS)[number];
5
+ export type ContentFrontmatterFormat = 'yaml' | 'toml' | 'json';
6
+ export type Parser = {
7
+ type: 'mdx';
8
+ } | {
9
+ type: 'markdown';
10
+ /**
11
+ * Tina will escape entities like `<` and `[` by default. You can choose to turn
12
+ * off all escaping, or specify HTML, so `<div>` will not be turned into `\<div>`
13
+ */
14
+ skipEscaping?: 'all' | 'html' | 'none';
15
+ } | {
16
+ /**
17
+ * Experimental: Returns the native Slate.js document as JSON. Ideal to retain the pure editor content structure.
18
+ */
19
+ type: 'slatejson';
20
+ };
3
21
  type Meta = {
4
22
  active?: boolean;
5
23
  dirty?: boolean;
@@ -111,6 +129,11 @@ export type UIField<Type, List extends boolean> = {
111
129
  type FieldGeneric<Type, List extends boolean | undefined, ExtraFieldUIProps = {}> = List extends true ? {
112
130
  list: true;
113
131
  ui?: UIField<Type, true> & ExtraFieldUIProps;
132
+ /**
133
+ * Defines where new items will be added in the list.
134
+ * If not specified, defaults to `append`.
135
+ */
136
+ addItemBehavior?: 'append' | 'prepend';
114
137
  } : List extends false ? {
115
138
  list?: false;
116
139
  ui?: UIField<Type, false> & ExtraFieldUIProps;
@@ -198,24 +221,21 @@ export type RichTextField<WithNamespace extends boolean = false> = (FieldGeneric
198
221
  * will be stored as frontmatter
199
222
  */
200
223
  isBody?: boolean;
224
+ /**@deprecated use overrides.toolbar */
201
225
  toolbarOverride?: ToolbarOverrideType[];
202
226
  templates?: RichTextTemplate<WithNamespace>[];
227
+ overrides?: {
228
+ toolbar?: ToolbarOverrideType[];
229
+ /**Default set to true */
230
+ showFloatingToolbar?: boolean;
231
+ };
203
232
  /**
204
233
  * By default, Tina parses markdown with MDX, this is a more strict parser
205
234
  * that allows you to use structured content inside markdown (via `templates`).
206
235
  *
207
236
  * Specify `"markdown"` if you're having problems with Tina parsing your content.
208
237
  */
209
- parser?: {
210
- type: 'markdown';
211
- /**
212
- * Tina will escape entities like `<` and `[` by default. You can choose to turn
213
- * off all escaping, or specify HTML, so `<div>` will not be turned into `\<div>`
214
- */
215
- skipEscaping?: 'all' | 'html' | 'none';
216
- } | {
217
- type: 'mdx';
218
- };
238
+ parser?: Parser;
219
239
  };
220
240
  export type RichTextTemplate<WithNamespace extends boolean = false> = Template<WithNamespace> & {
221
241
  inline?: boolean;
@@ -394,7 +414,7 @@ export interface Config<CMSCallback = undefined, FormifyCallback = undefined, Do
394
414
  token?: string | null;
395
415
  ui?: {
396
416
  /**
397
- * When using Tina Cloud's branching feature, provide the URL for your given branch
417
+ * When using TinaCloud's branching feature, provide the URL for your given branch
398
418
  *
399
419
  * Eg. If you're deplying to Vercel, and your repo name is 'my-app',
400
420
  * Vercel's preview URL would be based on the branch:
@@ -408,11 +428,17 @@ export interface Config<CMSCallback = undefined, FormifyCallback = undefined, Do
408
428
  * ```
409
429
  * [more info](https://vercel.com/docs/concepts/deployments/generated-urls#url-with-git-branch)
410
430
  */
411
- previewUrl: (context: {
431
+ previewUrl?: (context: {
412
432
  branch: string;
413
433
  }) => {
414
434
  url: string;
415
435
  };
436
+ /**
437
+ * Opt out of update checks - this will prevent the CMS for checking for new versions
438
+ * If true, the CMS will not check for updates.
439
+ * Defaults to false if not specified.
440
+ */
441
+ optOutOfUpdateCheck?: boolean;
416
442
  };
417
443
  /**
418
444
  * Configurations for the autogenerated GraphQL HTTP client
@@ -521,7 +547,7 @@ export interface Config<CMSCallback = undefined, FormifyCallback = undefined, Do
521
547
  } | {
522
548
  searchClient?: never;
523
549
  /**
524
- * Use the Tina Cloud search index
550
+ * Use the TinaCloud search index
525
551
  */
526
552
  tina: {
527
553
  /**
@@ -548,7 +574,7 @@ export interface Config<CMSCallback = undefined, FormifyCallback = undefined, Do
548
574
  maxSearchIndexFieldLength?: number;
549
575
  };
550
576
  /**
551
- * Used to override the default Tina Cloud API URL
577
+ * Used to override the default TinaCloud API URL
552
578
  *
553
579
  * [mostly for internal use only]
554
580
  */
@@ -581,7 +607,7 @@ interface BaseCollection {
581
607
  name: string;
582
608
  path: string;
583
609
  indexes?: IndexType[];
584
- format?: 'json' | 'md' | 'markdown' | 'mdx' | 'yaml' | 'yml' | 'toml';
610
+ format?: ContentFormat;
585
611
  ui?: UICollection;
586
612
  /**
587
613
  * @deprecated - use `ui.defaultItem` on the each `template` instead
@@ -590,7 +616,7 @@ interface BaseCollection {
590
616
  /**
591
617
  * This format will be used to parse the markdown frontmatter
592
618
  */
593
- frontmatterFormat?: 'yaml' | 'toml' | 'json';
619
+ frontmatterFormat?: ContentFrontmatterFormat;
594
620
  /**
595
621
  * The delimiters used to parse the frontmatter.
596
622
  */
@@ -1 +1,9 @@
1
1
  export declare const normalizePath: (filepath: string) => string;
2
+ /**
3
+ * Returns the given path such that:
4
+ * - The path separator is converted from '\' to '/' if necessary.
5
+ * - Duplicate '/' are removed
6
+ * - Leading and trailing '/' are cleared
7
+ * @param filepath Filepath to convert to its canonical form
8
+ */
9
+ export declare const canonicalPath: (filepath: string) => string;
@@ -3,21 +3,21 @@ export declare const CollectionBaseSchema: z.ZodObject<{
3
3
  label: z.ZodOptional<z.ZodString>;
4
4
  name: z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, string, string>;
5
5
  path: z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, string, string>;
6
- format: z.ZodOptional<z.ZodEnum<["json", "md", "markdown", "mdx", "toml", "yaml", "yml"]>>;
6
+ format: z.ZodOptional<z.ZodEnum<["mdx", "md", "markdown", "json", "yaml", "yml", "toml"]>>;
7
7
  isAuthCollection: z.ZodOptional<z.ZodBoolean>;
8
8
  isDetached: z.ZodOptional<z.ZodBoolean>;
9
9
  }, "strip", z.ZodTypeAny, {
10
10
  name?: string;
11
11
  label?: string;
12
12
  path?: string;
13
- format?: "markdown" | "mdx" | "json" | "md" | "yaml" | "yml" | "toml";
13
+ format?: "mdx" | "md" | "markdown" | "json" | "yaml" | "yml" | "toml";
14
14
  isDetached?: boolean;
15
15
  isAuthCollection?: boolean;
16
16
  }, {
17
17
  name?: string;
18
18
  label?: string;
19
19
  path?: string;
20
- format?: "markdown" | "mdx" | "json" | "md" | "yaml" | "yml" | "toml";
20
+ format?: "mdx" | "md" | "markdown" | "json" | "yaml" | "yml" | "toml";
21
21
  isDetached?: boolean;
22
22
  isAuthCollection?: boolean;
23
23
  }>;
@@ -26,90 +26,90 @@ export declare const TinaCloudSchemaZod: z.ZodEffects<z.ZodObject<{
26
26
  label: z.ZodOptional<z.ZodString>;
27
27
  name: z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, string, string>;
28
28
  path: z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, string, string>;
29
- format: z.ZodOptional<z.ZodEnum<["json", "md", "markdown", "mdx", "toml", "yaml", "yml"]>>;
29
+ format: z.ZodOptional<z.ZodEnum<["mdx", "md", "markdown", "json", "yaml", "yml", "toml"]>>;
30
30
  isAuthCollection: z.ZodOptional<z.ZodBoolean>;
31
31
  isDetached: z.ZodOptional<z.ZodBoolean>;
32
32
  }, {
33
- fields: z.ZodEffects<z.ZodEffects<z.ZodEffects<z.ZodEffects<z.ZodOptional<z.ZodArray<z.ZodType<import("..").TinaField, z.ZodTypeDef, import("..").TinaField>, "many">>, import("..").TinaField[], import("..").TinaField[]>, import("..").TinaField[], import("..").TinaField[]>, import("..").TinaField[], import("..").TinaField[]>, import("..").TinaField[], import("..").TinaField[]>;
33
+ fields: z.ZodEffects<z.ZodEffects<z.ZodEffects<z.ZodEffects<z.ZodOptional<z.ZodArray<z.ZodType<import("../types/index").TinaField, z.ZodTypeDef, import("../types/index").TinaField>, "many">>, import("../types/index").TinaField[], import("../types/index").TinaField[]>, import("../types/index").TinaField[], import("../types/index").TinaField[]>, import("../types/index").TinaField[], import("../types/index").TinaField[]>, import("../types/index").TinaField[], import("../types/index").TinaField[]>;
34
34
  templates: z.ZodEffects<z.ZodOptional<z.ZodArray<z.ZodEffects<z.ZodObject<{
35
35
  label: z.ZodString;
36
36
  name: z.ZodEffects<z.ZodString, string, string>;
37
- fields: z.ZodArray<z.ZodType<import("..").TinaField, z.ZodTypeDef, import("..").TinaField>, "many">;
37
+ fields: z.ZodArray<z.ZodType<import("../types/index").TinaField, z.ZodTypeDef, import("../types/index").TinaField>, "many">;
38
38
  }, "strip", z.ZodTypeAny, {
39
39
  name?: string;
40
- fields?: import("..").TinaField[];
40
+ fields?: import("../types/index").TinaField[];
41
41
  label?: string;
42
42
  }, {
43
43
  name?: string;
44
- fields?: import("..").TinaField[];
44
+ fields?: import("../types/index").TinaField[];
45
45
  label?: string;
46
46
  }>, {
47
47
  name?: string;
48
- fields?: import("..").TinaField[];
48
+ fields?: import("../types/index").TinaField[];
49
49
  label?: string;
50
50
  }, {
51
51
  name?: string;
52
- fields?: import("..").TinaField[];
52
+ fields?: import("../types/index").TinaField[];
53
53
  label?: string;
54
54
  }>, "many">>, {
55
55
  name?: string;
56
- fields?: import("..").TinaField[];
56
+ fields?: import("../types/index").TinaField[];
57
57
  label?: string;
58
58
  }[], {
59
59
  name?: string;
60
- fields?: import("..").TinaField[];
60
+ fields?: import("../types/index").TinaField[];
61
61
  label?: string;
62
62
  }[]>;
63
63
  }>, "strip", z.ZodTypeAny, {
64
64
  name?: string;
65
65
  templates?: {
66
66
  name?: string;
67
- fields?: import("..").TinaField[];
67
+ fields?: import("../types/index").TinaField[];
68
68
  label?: string;
69
69
  }[];
70
- fields?: import("..").TinaField[];
70
+ fields?: import("../types/index").TinaField[];
71
71
  label?: string;
72
72
  path?: string;
73
- format?: "markdown" | "mdx" | "json" | "md" | "yaml" | "yml" | "toml";
73
+ format?: "mdx" | "md" | "markdown" | "json" | "yaml" | "yml" | "toml";
74
74
  isDetached?: boolean;
75
75
  isAuthCollection?: boolean;
76
76
  }, {
77
77
  name?: string;
78
78
  templates?: {
79
79
  name?: string;
80
- fields?: import("..").TinaField[];
80
+ fields?: import("../types/index").TinaField[];
81
81
  label?: string;
82
82
  }[];
83
- fields?: import("..").TinaField[];
83
+ fields?: import("../types/index").TinaField[];
84
84
  label?: string;
85
85
  path?: string;
86
- format?: "markdown" | "mdx" | "json" | "md" | "yaml" | "yml" | "toml";
86
+ format?: "mdx" | "md" | "markdown" | "json" | "yaml" | "yml" | "toml";
87
87
  isDetached?: boolean;
88
88
  isAuthCollection?: boolean;
89
89
  }>, {
90
90
  name?: string;
91
91
  templates?: {
92
92
  name?: string;
93
- fields?: import("..").TinaField[];
93
+ fields?: import("../types/index").TinaField[];
94
94
  label?: string;
95
95
  }[];
96
- fields?: import("..").TinaField[];
96
+ fields?: import("../types/index").TinaField[];
97
97
  label?: string;
98
98
  path?: string;
99
- format?: "markdown" | "mdx" | "json" | "md" | "yaml" | "yml" | "toml";
99
+ format?: "mdx" | "md" | "markdown" | "json" | "yaml" | "yml" | "toml";
100
100
  isDetached?: boolean;
101
101
  isAuthCollection?: boolean;
102
102
  }, {
103
103
  name?: string;
104
104
  templates?: {
105
105
  name?: string;
106
- fields?: import("..").TinaField[];
106
+ fields?: import("../types/index").TinaField[];
107
107
  label?: string;
108
108
  }[];
109
- fields?: import("..").TinaField[];
109
+ fields?: import("../types/index").TinaField[];
110
110
  label?: string;
111
111
  path?: string;
112
- format?: "markdown" | "mdx" | "json" | "md" | "yaml" | "yml" | "toml";
112
+ format?: "mdx" | "md" | "markdown" | "json" | "yaml" | "yml" | "toml";
113
113
  isDetached?: boolean;
114
114
  isAuthCollection?: boolean;
115
115
  }>, "many">;
@@ -237,13 +237,13 @@ export declare const TinaCloudSchemaZod: z.ZodEffects<z.ZodObject<{
237
237
  name?: string;
238
238
  templates?: {
239
239
  name?: string;
240
- fields?: import("..").TinaField[];
240
+ fields?: import("../types/index").TinaField[];
241
241
  label?: string;
242
242
  }[];
243
- fields?: import("..").TinaField[];
243
+ fields?: import("../types/index").TinaField[];
244
244
  label?: string;
245
245
  path?: string;
246
- format?: "markdown" | "mdx" | "json" | "md" | "yaml" | "yml" | "toml";
246
+ format?: "mdx" | "md" | "markdown" | "json" | "yaml" | "yml" | "toml";
247
247
  isDetached?: boolean;
248
248
  isAuthCollection?: boolean;
249
249
  }[];
@@ -275,13 +275,13 @@ export declare const TinaCloudSchemaZod: z.ZodEffects<z.ZodObject<{
275
275
  name?: string;
276
276
  templates?: {
277
277
  name?: string;
278
- fields?: import("..").TinaField[];
278
+ fields?: import("../types/index").TinaField[];
279
279
  label?: string;
280
280
  }[];
281
- fields?: import("..").TinaField[];
281
+ fields?: import("../types/index").TinaField[];
282
282
  label?: string;
283
283
  path?: string;
284
- format?: "markdown" | "mdx" | "json" | "md" | "yaml" | "yml" | "toml";
284
+ format?: "mdx" | "md" | "markdown" | "json" | "yaml" | "yml" | "toml";
285
285
  isDetached?: boolean;
286
286
  isAuthCollection?: boolean;
287
287
  }[];
@@ -313,13 +313,13 @@ export declare const TinaCloudSchemaZod: z.ZodEffects<z.ZodObject<{
313
313
  name?: string;
314
314
  templates?: {
315
315
  name?: string;
316
- fields?: import("..").TinaField[];
316
+ fields?: import("../types/index").TinaField[];
317
317
  label?: string;
318
318
  }[];
319
- fields?: import("..").TinaField[];
319
+ fields?: import("../types/index").TinaField[];
320
320
  label?: string;
321
321
  path?: string;
322
- format?: "markdown" | "mdx" | "json" | "md" | "yaml" | "yml" | "toml";
322
+ format?: "mdx" | "md" | "markdown" | "json" | "yaml" | "yml" | "toml";
323
323
  isDetached?: boolean;
324
324
  isAuthCollection?: boolean;
325
325
  }[];
@@ -351,13 +351,13 @@ export declare const TinaCloudSchemaZod: z.ZodEffects<z.ZodObject<{
351
351
  name?: string;
352
352
  templates?: {
353
353
  name?: string;
354
- fields?: import("..").TinaField[];
354
+ fields?: import("../types/index").TinaField[];
355
355
  label?: string;
356
356
  }[];
357
- fields?: import("..").TinaField[];
357
+ fields?: import("../types/index").TinaField[];
358
358
  label?: string;
359
359
  path?: string;
360
- format?: "markdown" | "mdx" | "json" | "md" | "yaml" | "yml" | "toml";
360
+ format?: "mdx" | "md" | "markdown" | "json" | "yaml" | "yml" | "toml";
361
361
  isDetached?: boolean;
362
362
  isAuthCollection?: boolean;
363
363
  }[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tinacms/schema-tools",
3
- "version": "0.0.0-c45ac5d-20241213020122",
3
+ "version": "0.0.0-c466c52-20250801052040",
4
4
  "main": "dist/index.js",
5
5
  "module": "./dist/index.mjs",
6
6
  "exports": {
@@ -25,14 +25,14 @@
25
25
  "devDependencies": {
26
26
  "@types/jest": "^29.5.14",
27
27
  "@types/micromatch": "^4.0.9",
28
- "@types/react": "^18.3.12",
28
+ "@types/react": "^18.3.18",
29
29
  "@types/yup": "^0.29.14",
30
30
  "jest": "^29.7.0",
31
31
  "react": "^18.3.1",
32
32
  "ts-jest": "^29.2.5",
33
- "typescript": "^5.6.3",
33
+ "typescript": "^5.7.3",
34
34
  "yup": "^0.32.11",
35
- "@tinacms/scripts": "1.3.1"
35
+ "@tinacms/scripts": "1.4.0"
36
36
  },
37
37
  "peerDependencies": {
38
38
  "react": ">=16.14.0",
@@ -48,7 +48,7 @@
48
48
  "dependencies": {
49
49
  "picomatch-browser": "2.2.6",
50
50
  "url-pattern": "^1.0.3",
51
- "zod": "^3.23.8"
51
+ "zod": "^3.24.2"
52
52
  },
53
53
  "scripts": {
54
54
  "build": "tinacms-scripts build",