@tinacms/graphql 0.0.0-fbcd928-20241024223724 → 0.0.0-fd664d8-20250407054012

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
@@ -17,14 +17,18 @@ var __copyProps = (to, from, except, desc) => {
17
17
  return to;
18
18
  };
19
19
  var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
20
24
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
21
25
  mod
22
26
  ));
23
27
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
24
28
 
25
29
  // src/index.ts
26
- var src_exports = {};
27
- __export(src_exports, {
30
+ var index_exports = {};
31
+ __export(index_exports, {
28
32
  AuditFileSystemBridge: () => AuditFileSystemBridge,
29
33
  Database: () => Database,
30
34
  FilesystemBridge: () => FilesystemBridge,
@@ -58,7 +62,7 @@ __export(src_exports, {
58
62
  transformDocument: () => transformDocument,
59
63
  transformDocumentIntoPayload: () => transformDocumentIntoPayload
60
64
  });
61
- module.exports = __toCommonJS(src_exports);
65
+ module.exports = __toCommonJS(index_exports);
62
66
 
63
67
  // src/build.ts
64
68
  var import_graphql2 = require("graphql");
@@ -130,6 +134,15 @@ var SysFieldDefinition = {
130
134
  selectionSet: {
131
135
  kind: "SelectionSet",
132
136
  selections: [
137
+ // {
138
+ // kind: 'Field' as const,
139
+ // name: {
140
+ // kind: 'Name' as const,
141
+ // value: 'title',
142
+ // },
143
+ // arguments: [],
144
+ // directives: [],
145
+ // },
133
146
  {
134
147
  kind: "Field",
135
148
  name: {
@@ -197,6 +210,10 @@ var SysFieldDefinition = {
197
210
  }
198
211
  };
199
212
  var astBuilder = {
213
+ /**
214
+ * `FormFieldBuilder` acts as a shortcut to building an entire `ObjectTypeDefinition`, we use this
215
+ * because all Tina field objects share a common set of fields ('name', 'label', 'component')
216
+ */
200
217
  FormFieldBuilder: ({
201
218
  name,
202
219
  additionalFields
@@ -420,6 +437,8 @@ var astBuilder = {
420
437
  kind: "Name",
421
438
  value: name
422
439
  },
440
+ // @ts-ignore FIXME; this is being handled properly but we're lying to
441
+ // ts and then fixing it in the `extractInlineTypes` function
423
442
  fields
424
443
  }),
425
444
  UnionTypeDefinition: ({
@@ -432,6 +451,8 @@ var astBuilder = {
432
451
  value: name
433
452
  },
434
453
  directives: [],
454
+ // @ts-ignore FIXME; this is being handled properly but we're lying to
455
+ // ts and then fixing it in the `extractInlineTypes` function
435
456
  types: types.map((name2) => ({
436
457
  kind: "NamedType",
437
458
  name: {
@@ -528,8 +549,11 @@ var astBuilder = {
528
549
  string: "String",
529
550
  boolean: "Boolean",
530
551
  number: "Float",
552
+ // FIXME - needs to be float or int
531
553
  datetime: "String",
554
+ // FIXME
532
555
  image: "String",
556
+ // FIXME
533
557
  text: "String"
534
558
  };
535
559
  return scalars[type];
@@ -1028,8 +1052,7 @@ var astBuilder = {
1028
1052
  }
1029
1053
  };
1030
1054
  var capitalize = (s) => {
1031
- if (typeof s !== "string")
1032
- return "";
1055
+ if (typeof s !== "string") return "";
1033
1056
  return s.charAt(0).toUpperCase() + s.slice(1);
1034
1057
  };
1035
1058
  var extractInlineTypes = (item) => {
@@ -1072,41 +1095,6 @@ function* walk(maybeNode, visited = /* @__PURE__ */ new WeakSet()) {
1072
1095
  yield maybeNode;
1073
1096
  visited.add(maybeNode);
1074
1097
  }
1075
- function addNamespaceToSchema(maybeNode, namespace = []) {
1076
- if (typeof maybeNode === "string") {
1077
- return maybeNode;
1078
- }
1079
- if (typeof maybeNode === "boolean") {
1080
- return maybeNode;
1081
- }
1082
- const newNode = maybeNode;
1083
- const keys = Object.keys(maybeNode);
1084
- Object.values(maybeNode).map((m, index) => {
1085
- const key = keys[index];
1086
- if (Array.isArray(m)) {
1087
- newNode[key] = m.map((element) => {
1088
- if (!element) {
1089
- return;
1090
- }
1091
- if (!element.hasOwnProperty("name")) {
1092
- return element;
1093
- }
1094
- const value = element.name || element.value;
1095
- return addNamespaceToSchema(element, [...namespace, value]);
1096
- });
1097
- } else {
1098
- if (!m) {
1099
- return;
1100
- }
1101
- if (!m.hasOwnProperty("name")) {
1102
- newNode[key] = m;
1103
- } else {
1104
- newNode[key] = addNamespaceToSchema(m, [...namespace, m.name]);
1105
- }
1106
- }
1107
- });
1108
- return { ...newNode, namespace };
1109
- }
1110
1098
  var generateNamespacedFieldName = (names, suffix = "") => {
1111
1099
  return (suffix ? [...names, suffix] : names).map(capitalize).join("");
1112
1100
  };
@@ -1485,6 +1473,19 @@ var Builder = class {
1485
1473
  this.addToLookupMap = (lookup) => {
1486
1474
  this.lookupMap[lookup.type] = lookup;
1487
1475
  };
1476
+ /**
1477
+ * ```graphql
1478
+ * # ex.
1479
+ * {
1480
+ * getCollection(collection: $collection) {
1481
+ * name
1482
+ * documents {...}
1483
+ * }
1484
+ * }
1485
+ * ```
1486
+ *
1487
+ * @param collections
1488
+ */
1488
1489
  this.buildCollectionDefinition = async (collections) => {
1489
1490
  const name = "collection";
1490
1491
  const typeName = "Collection";
@@ -1555,6 +1556,19 @@ var Builder = class {
1555
1556
  required: true
1556
1557
  });
1557
1558
  };
1559
+ /**
1560
+ * ```graphql
1561
+ * # ex.
1562
+ * {
1563
+ * getCollections {
1564
+ * name
1565
+ * documents {...}
1566
+ * }
1567
+ * }
1568
+ * ```
1569
+ *
1570
+ * @param collections
1571
+ */
1558
1572
  this.buildMultiCollectionDefinition = async (collections) => {
1559
1573
  const name = "collections";
1560
1574
  const typeName = "Collection";
@@ -1565,6 +1579,17 @@ var Builder = class {
1565
1579
  required: true
1566
1580
  });
1567
1581
  };
1582
+ /**
1583
+ * ```graphql
1584
+ * # ex.
1585
+ * {
1586
+ * node(id: $id) {
1587
+ * id
1588
+ * data {...}
1589
+ * }
1590
+ * }
1591
+ * ```
1592
+ */
1568
1593
  this.multiNodeDocument = async () => {
1569
1594
  const name = "node";
1570
1595
  const args = [
@@ -1585,6 +1610,19 @@ var Builder = class {
1585
1610
  required: true
1586
1611
  });
1587
1612
  };
1613
+ /**
1614
+ * ```graphql
1615
+ * # ex.
1616
+ * {
1617
+ * getDocument(collection: $collection, relativePath: $relativePath) {
1618
+ * id
1619
+ * data {...}
1620
+ * }
1621
+ * }
1622
+ * ```
1623
+ *
1624
+ * @param collections
1625
+ */
1588
1626
  this.multiCollectionDocument = async (collections) => {
1589
1627
  const name = "document";
1590
1628
  const args = [
@@ -1610,6 +1648,19 @@ var Builder = class {
1610
1648
  required: true
1611
1649
  });
1612
1650
  };
1651
+ /**
1652
+ * ```graphql
1653
+ * # ex.
1654
+ * {
1655
+ * addPendingDocument(collection: $collection, relativePath: $relativePath, params: $params) {
1656
+ * id
1657
+ * data {...}
1658
+ * }
1659
+ * }
1660
+ * ```
1661
+ *
1662
+ * @param collections
1663
+ */
1613
1664
  this.addMultiCollectionDocumentMutation = async () => {
1614
1665
  return astBuilder.FieldDefinition({
1615
1666
  name: "addPendingDocument",
@@ -1634,6 +1685,19 @@ var Builder = class {
1634
1685
  type: astBuilder.TYPES.MultiCollectionDocument
1635
1686
  });
1636
1687
  };
1688
+ /**
1689
+ * ```graphql
1690
+ * # ex.
1691
+ * {
1692
+ * createDocument(relativePath: $relativePath, params: $params) {
1693
+ * id
1694
+ * data {...}
1695
+ * }
1696
+ * }
1697
+ * ```
1698
+ *
1699
+ * @param collections
1700
+ */
1637
1701
  this.buildCreateCollectionDocumentMutation = async (collections) => {
1638
1702
  return astBuilder.FieldDefinition({
1639
1703
  name: "createDocument",
@@ -1661,6 +1725,19 @@ var Builder = class {
1661
1725
  type: astBuilder.TYPES.MultiCollectionDocument
1662
1726
  });
1663
1727
  };
1728
+ /**
1729
+ * ```graphql
1730
+ * # ex.
1731
+ * {
1732
+ * updateDocument(relativePath: $relativePath, params: $params) {
1733
+ * id
1734
+ * data {...}
1735
+ * }
1736
+ * }
1737
+ * ```
1738
+ *
1739
+ * @param collections
1740
+ */
1664
1741
  this.buildUpdateCollectionDocumentMutation = async (collections) => {
1665
1742
  return astBuilder.FieldDefinition({
1666
1743
  name: "updateDocument",
@@ -1688,6 +1765,19 @@ var Builder = class {
1688
1765
  type: astBuilder.TYPES.MultiCollectionDocument
1689
1766
  });
1690
1767
  };
1768
+ /**
1769
+ * ```graphql
1770
+ * # ex.
1771
+ * {
1772
+ * deleteDocument(relativePath: $relativePath, params: $params) {
1773
+ * id
1774
+ * data {...}
1775
+ * }
1776
+ * }
1777
+ * ```
1778
+ *
1779
+ * @param collections
1780
+ */
1691
1781
  this.buildDeleteCollectionDocumentMutation = async (collections) => {
1692
1782
  return astBuilder.FieldDefinition({
1693
1783
  name: "deleteDocument",
@@ -1707,6 +1797,19 @@ var Builder = class {
1707
1797
  type: astBuilder.TYPES.MultiCollectionDocument
1708
1798
  });
1709
1799
  };
1800
+ /**
1801
+ * ```graphql
1802
+ * # ex.
1803
+ * {
1804
+ * createFolder(folderName: $folderName, params: $params) {
1805
+ * id
1806
+ * data {...}
1807
+ * }
1808
+ * }
1809
+ * ```
1810
+ *
1811
+ * @param collections
1812
+ */
1710
1813
  this.buildCreateCollectionFolderMutation = async () => {
1711
1814
  return astBuilder.FieldDefinition({
1712
1815
  name: "createFolder",
@@ -1726,6 +1829,19 @@ var Builder = class {
1726
1829
  type: astBuilder.TYPES.MultiCollectionDocument
1727
1830
  });
1728
1831
  };
1832
+ /**
1833
+ * ```graphql
1834
+ * # ex.
1835
+ * {
1836
+ * getPostDocument(relativePath: $relativePath) {
1837
+ * id
1838
+ * data {...}
1839
+ * }
1840
+ * }
1841
+ * ```
1842
+ *
1843
+ * @param collection
1844
+ */
1729
1845
  this.collectionDocument = async (collection) => {
1730
1846
  const name = NAMER.queryName([collection.name]);
1731
1847
  const type = await this._buildCollectionDocumentType(collection);
@@ -1786,6 +1902,20 @@ var Builder = class {
1786
1902
  const args = [];
1787
1903
  return astBuilder.FieldDefinition({ type, name, args, required: false });
1788
1904
  };
1905
+ /**
1906
+ * Turns a collection into a fragment that gets updated on build. This fragment does not resolve references
1907
+ * ```graphql
1908
+ * # ex.
1909
+ * fragment AuthorsParts on Authors {
1910
+ * name
1911
+ * avatar
1912
+ * ...
1913
+ * }
1914
+ * ```
1915
+ *
1916
+ * @public
1917
+ * @param collection a TinaCloud collection
1918
+ */
1789
1919
  this.collectionFragment = async (collection) => {
1790
1920
  const name = NAMER.dataTypeName(collection.namespace);
1791
1921
  const fragmentName = NAMER.fragmentName(collection.namespace);
@@ -1799,6 +1929,20 @@ var Builder = class {
1799
1929
  selections: filterSelections(selections)
1800
1930
  });
1801
1931
  };
1932
+ /**
1933
+ * Given a collection this function returns its selections set. For example for Post this would return
1934
+ *
1935
+ * "
1936
+ * body
1937
+ * title
1938
+ * ... on Author {
1939
+ * name
1940
+ * heroImg
1941
+ * }
1942
+ *
1943
+ * But in the AST format
1944
+ *
1945
+ * */
1802
1946
  this._getCollectionFragmentSelections = async (collection, depth) => {
1803
1947
  var _a;
1804
1948
  const selections = [];
@@ -1882,9 +2026,9 @@ var Builder = class {
1882
2026
  ]
1883
2027
  });
1884
2028
  }
2029
+ // TODO: Should we throw here?
1885
2030
  case "reference":
1886
- if (depth >= this.maxDepth)
1887
- return false;
2031
+ if (depth >= this.maxDepth) return false;
1888
2032
  if (!("collections" in field)) {
1889
2033
  return false;
1890
2034
  }
@@ -1916,6 +2060,7 @@ var Builder = class {
1916
2060
  name: field.name,
1917
2061
  selections: [
1918
2062
  ...selections,
2063
+ // This is ... on Document { id }
1919
2064
  {
1920
2065
  kind: "InlineFragment",
1921
2066
  typeCondition: {
@@ -1946,6 +2091,19 @@ var Builder = class {
1946
2091
  });
1947
2092
  }
1948
2093
  };
2094
+ /**
2095
+ * ```graphql
2096
+ * # ex.
2097
+ * mutation {
2098
+ * updatePostDocument(relativePath: $relativePath, params: $params) {
2099
+ * id
2100
+ * data {...}
2101
+ * }
2102
+ * }
2103
+ * ```
2104
+ *
2105
+ * @param collection
2106
+ */
1949
2107
  this.updateCollectionDocumentMutation = async (collection) => {
1950
2108
  return astBuilder.FieldDefinition({
1951
2109
  type: await this._buildCollectionDocumentType(collection),
@@ -1965,6 +2123,19 @@ var Builder = class {
1965
2123
  ]
1966
2124
  });
1967
2125
  };
2126
+ /**
2127
+ * ```graphql
2128
+ * # ex.
2129
+ * mutation {
2130
+ * createPostDocument(relativePath: $relativePath, params: $params) {
2131
+ * id
2132
+ * data {...}
2133
+ * }
2134
+ * }
2135
+ * ```
2136
+ *
2137
+ * @param collection
2138
+ */
1968
2139
  this.createCollectionDocumentMutation = async (collection) => {
1969
2140
  return astBuilder.FieldDefinition({
1970
2141
  type: await this._buildCollectionDocumentType(collection),
@@ -1984,6 +2155,22 @@ var Builder = class {
1984
2155
  ]
1985
2156
  });
1986
2157
  };
2158
+ /**
2159
+ * ```graphql
2160
+ * # ex.
2161
+ * {
2162
+ * getPostList(first: 10) {
2163
+ * edges {
2164
+ * node {
2165
+ * id
2166
+ * }
2167
+ * }
2168
+ * }
2169
+ * }
2170
+ * ```
2171
+ *
2172
+ * @param collection
2173
+ */
1987
2174
  this.collectionDocumentList = async (collection) => {
1988
2175
  const connectionName = NAMER.referenceConnectionType(collection.namespace);
1989
2176
  this.addToLookupMap({
@@ -1999,6 +2186,10 @@ var Builder = class {
1999
2186
  collection
2000
2187
  });
2001
2188
  };
2189
+ /**
2190
+ * GraphQL type definitions which remain unchanged regardless
2191
+ * of the supplied Tina schema. Ex. "node" interface
2192
+ */
2002
2193
  this.buildStaticDefinitions = () => staticDefinitions;
2003
2194
  this._buildCollectionDocumentType = async (collection, suffix = "", extraFields = [], extraInterfaces = []) => {
2004
2195
  const documentTypeName = NAMER.documentTypeName(collection.namespace);
@@ -2503,6 +2694,7 @@ var Builder = class {
2503
2694
  name: NAMER.dataFilterTypeName(namespace),
2504
2695
  fields: await sequential(collections, async (collection2) => {
2505
2696
  return astBuilder.InputValueDefinition({
2697
+ // @ts-ignore
2506
2698
  name: collection2.name,
2507
2699
  type: NAMER.dataFilterTypeName(collection2.namespace)
2508
2700
  });
@@ -2692,7 +2884,8 @@ Visit https://tina.io/docs/errors/ui-not-supported/ for more information
2692
2884
  });
2693
2885
  };
2694
2886
  var _a, _b, _c, _d;
2695
- this.maxDepth = (_d = (_c = (_b = (_a = config == null ? void 0 : config.tinaSchema.schema) == null ? void 0 : _a.config) == null ? void 0 : _b.client) == null ? void 0 : _c.referenceDepth) != null ? _d : 2;
2887
+ this.maxDepth = // @ts-ignore
2888
+ (_d = (_c = (_b = (_a = config == null ? void 0 : config.tinaSchema.schema) == null ? void 0 : _a.config) == null ? void 0 : _b.client) == null ? void 0 : _c.referenceDepth) != null ? _d : 2;
2696
2889
  this.tinaSchema = config.tinaSchema;
2697
2890
  this.lookupMap = {};
2698
2891
  }
@@ -2703,8 +2896,7 @@ Visit https://tina.io/docs/errors/ui-not-supported/ for more information
2703
2896
  selections.push(field);
2704
2897
  });
2705
2898
  const filteredSelections = filterSelections(selections);
2706
- if (!filteredSelections.length)
2707
- return false;
2899
+ if (!filteredSelections.length) return false;
2708
2900
  return astBuilder.InlineFragmentDefinition({
2709
2901
  selections: filteredSelections,
2710
2902
  name: NAMER.dataTypeName(template.namespace)
@@ -2738,12 +2930,13 @@ var filterSelections = (arr) => {
2738
2930
  };
2739
2931
 
2740
2932
  // src/schema/createSchema.ts
2741
- var import_schema_tools2 = require("@tinacms/schema-tools");
2933
+ var import_schema_tools3 = require("@tinacms/schema-tools");
2742
2934
 
2743
2935
  // src/schema/validate.ts
2936
+ var import_schema_tools = require("@tinacms/schema-tools");
2744
2937
  var import_lodash2 = __toESM(require("lodash.clonedeep"));
2745
2938
  var yup2 = __toESM(require("yup"));
2746
- var import_schema_tools = require("@tinacms/schema-tools");
2939
+ var import_schema_tools2 = require("@tinacms/schema-tools");
2747
2940
  var FIELD_TYPES = [
2748
2941
  "string",
2749
2942
  "number",
@@ -2756,7 +2949,7 @@ var FIELD_TYPES = [
2756
2949
  "password"
2757
2950
  ];
2758
2951
  var validateSchema = async (schema) => {
2759
- const schema2 = addNamespaceToSchema(
2952
+ const schema2 = (0, import_schema_tools.addNamespaceToSchema)(
2760
2953
  (0, import_lodash2.default)(schema)
2761
2954
  );
2762
2955
  const collections = await sequential(
@@ -2765,7 +2958,7 @@ var validateSchema = async (schema) => {
2765
2958
  );
2766
2959
  validationCollectionsPathAndMatch(collections);
2767
2960
  if (schema2.config) {
2768
- const config = (0, import_schema_tools.validateTinaCloudSchemaConfig)(schema2.config);
2961
+ const config = (0, import_schema_tools2.validateTinaCloudSchemaConfig)(schema2.config);
2769
2962
  return {
2770
2963
  collections,
2771
2964
  config
@@ -2785,6 +2978,7 @@ var validationCollectionsPathAndMatch = (collections) => {
2785
2978
  }).map((x) => `${x.path}${x.format || "md"}`);
2786
2979
  if (noMatchCollections.length !== new Set(noMatchCollections).size) {
2787
2980
  throw new Error(
2981
+ // TODO: add a link to the docs
2788
2982
  "Two collections without match can not have the same `path`. Please make the `path` unique or add a matches property to the collection."
2789
2983
  );
2790
2984
  }
@@ -2896,7 +3090,7 @@ var validateField = async (field) => {
2896
3090
  // package.json
2897
3091
  var package_default = {
2898
3092
  name: "@tinacms/graphql",
2899
- version: "1.5.6",
3093
+ version: "1.5.15",
2900
3094
  main: "dist/index.js",
2901
3095
  module: "dist/index.mjs",
2902
3096
  typings: "dist/index.d.ts",
@@ -2923,8 +3117,8 @@ var package_default = {
2923
3117
  build: "tinacms-scripts build",
2924
3118
  docs: "pnpm typedoc",
2925
3119
  serve: "pnpm nodemon dist/server.js",
2926
- test: "jest",
2927
- "test-watch": "jest --watch"
3120
+ test: "vitest run",
3121
+ "test-watch": "vitest"
2928
3122
  },
2929
3123
  dependencies: {
2930
3124
  "@iarna/toml": "^2.2.5",
@@ -2932,22 +3126,22 @@ var package_default = {
2932
3126
  "@tinacms/schema-tools": "workspace:*",
2933
3127
  "abstract-level": "^1.0.4",
2934
3128
  "date-fns": "^2.30.0",
2935
- "fast-glob": "^3.3.2",
2936
- "fs-extra": "^11.2.0",
3129
+ "fast-glob": "^3.3.3",
3130
+ "fs-extra": "^11.3.0",
2937
3131
  "glob-parent": "^6.0.2",
2938
3132
  graphql: "15.8.0",
2939
3133
  "gray-matter": "^4.0.3",
2940
- "isomorphic-git": "^1.27.1",
3134
+ "isomorphic-git": "^1.29.0",
2941
3135
  "js-sha1": "^0.6.0",
2942
3136
  "js-yaml": "^3.14.1",
2943
- "jsonpath-plus": "^6.0.1",
3137
+ "jsonpath-plus": "10.1.0",
2944
3138
  "lodash.clonedeep": "^4.5.0",
2945
3139
  "lodash.set": "^4.3.2",
2946
3140
  "lodash.uniqby": "^4.7.0",
2947
3141
  "many-level": "^2.0.0",
2948
3142
  micromatch: "4.0.8",
2949
3143
  "normalize-path": "^3.0.0",
2950
- "readable-stream": "^4.5.2",
3144
+ "readable-stream": "^4.7.0",
2951
3145
  scmp: "^2.1.0",
2952
3146
  yup: "^0.32.11"
2953
3147
  },
@@ -2965,24 +3159,23 @@ var package_default = {
2965
3159
  "@types/estree": "^0.0.50",
2966
3160
  "@types/express": "^4.17.21",
2967
3161
  "@types/fs-extra": "^9.0.13",
2968
- "@types/jest": "^26.0.24",
2969
3162
  "@types/js-yaml": "^3.12.10",
2970
3163
  "@types/lodash.camelcase": "^4.3.9",
2971
3164
  "@types/lodash.upperfirst": "^4.3.9",
2972
3165
  "@types/lru-cache": "^5.1.1",
2973
3166
  "@types/mdast": "^3.0.15",
2974
3167
  "@types/micromatch": "^4.0.9",
2975
- "@types/node": "^22.7.4",
3168
+ "@types/node": "^22.13.1",
2976
3169
  "@types/normalize-path": "^3.0.2",
2977
3170
  "@types/ws": "^7.4.7",
2978
3171
  "@types/yup": "^0.29.14",
2979
- jest: "^29.7.0",
2980
- "jest-diff": "^29.7.0",
2981
3172
  "jest-file-snapshot": "^0.5.0",
2982
- "jest-matcher-utils": "^29.7.0",
2983
3173
  "memory-level": "^1.0.0",
2984
3174
  nodemon: "3.1.4",
2985
- typescript: "^5.6.2"
3175
+ typescript: "^5.7.3",
3176
+ vite: "^4.5.9",
3177
+ vitest: "^0.32.4",
3178
+ zod: "^3.24.2"
2986
3179
  }
2987
3180
  };
2988
3181
 
@@ -2997,7 +3190,7 @@ var createSchema = async ({
2997
3190
  if (flags && flags.length > 0) {
2998
3191
  meta["flags"] = flags;
2999
3192
  }
3000
- return new import_schema_tools2.TinaSchema({
3193
+ return new import_schema_tools3.TinaSchema({
3001
3194
  version: {
3002
3195
  fullVersion: package_default.version,
3003
3196
  major,
@@ -3053,6 +3246,7 @@ var _buildFragments = async (builder, tinaSchema) => {
3053
3246
  const fragDoc = {
3054
3247
  kind: "Document",
3055
3248
  definitions: (0, import_lodash3.default)(
3249
+ // @ts-ignore
3056
3250
  extractInlineTypes(fragmentDefinitionsFields),
3057
3251
  (node) => node.name.value
3058
3252
  )
@@ -3076,6 +3270,7 @@ var _buildQueries = async (builder, tinaSchema) => {
3076
3270
  fragName,
3077
3271
  queryName: queryListName,
3078
3272
  filterType: queryFilterTypeName,
3273
+ // look for flag to see if the data layer is enabled
3079
3274
  dataLayer: Boolean(
3080
3275
  (_c = (_b = (_a = tinaSchema.config) == null ? void 0 : _a.meta) == null ? void 0 : _b.flags) == null ? void 0 : _c.find((x) => x === "experimentalData")
3081
3276
  )
@@ -3085,6 +3280,7 @@ var _buildQueries = async (builder, tinaSchema) => {
3085
3280
  const queryDoc = {
3086
3281
  kind: "Document",
3087
3282
  definitions: (0, import_lodash3.default)(
3283
+ // @ts-ignore
3088
3284
  extractInlineTypes(operationsDefinitions),
3089
3285
  (node) => node.name.value
3090
3286
  )
@@ -3136,7 +3332,9 @@ var _buildSchema = async (builder, tinaSchema) => {
3136
3332
  await builder.buildCreateCollectionFolderMutation()
3137
3333
  );
3138
3334
  await sequential(collections, async (collection) => {
3139
- queryTypeDefinitionFields.push(await builder.collectionDocument(collection));
3335
+ queryTypeDefinitionFields.push(
3336
+ await builder.collectionDocument(collection)
3337
+ );
3140
3338
  if (collection.isAuthCollection) {
3141
3339
  queryTypeDefinitionFields.push(
3142
3340
  await builder.authenticationCollectionDocument(collection)
@@ -3173,6 +3371,7 @@ var _buildSchema = async (builder, tinaSchema) => {
3173
3371
  return {
3174
3372
  kind: "Document",
3175
3373
  definitions: (0, import_lodash3.default)(
3374
+ // @ts-ignore
3176
3375
  extractInlineTypes(definitions),
3177
3376
  (node) => node.name.value
3178
3377
  )
@@ -3377,8 +3576,7 @@ var resolveMediaCloudToRelative = (value, config = { useRelativeMedia: true }, s
3377
3576
  }
3378
3577
  if (Array.isArray(value)) {
3379
3578
  return value.map((v) => {
3380
- if (!v || typeof v !== "string")
3381
- return v;
3579
+ if (!v || typeof v !== "string") return v;
3382
3580
  const cleanMediaRoot = cleanUpSlashes(
3383
3581
  schema.config.media.tina.mediaRoot
3384
3582
  );
@@ -3406,8 +3604,7 @@ var resolveMediaRelativeToCloud = (value, config = { useRelativeMedia: true }, s
3406
3604
  }
3407
3605
  if (Array.isArray(value)) {
3408
3606
  return value.map((v) => {
3409
- if (!v || typeof v !== "string")
3410
- return v;
3607
+ if (!v || typeof v !== "string") return v;
3411
3608
  const strippedValue = v.replace(cleanMediaRoot, "");
3412
3609
  return `https://${config.assetsHost}/${config.clientId}${strippedValue}`;
3413
3610
  });
@@ -3426,8 +3623,7 @@ var cleanUpSlashes = (path7) => {
3426
3623
  };
3427
3624
  var hasTinaMediaConfig = (schema) => {
3428
3625
  var _a, _b, _c, _d, _e, _f, _g, _h;
3429
- if (!((_b = (_a = schema.config) == null ? void 0 : _a.media) == null ? void 0 : _b.tina))
3430
- return false;
3626
+ if (!((_b = (_a = schema.config) == null ? void 0 : _a.media) == null ? void 0 : _b.tina)) return false;
3431
3627
  if (typeof ((_e = (_d = (_c = schema.config) == null ? void 0 : _c.media) == null ? void 0 : _d.tina) == null ? void 0 : _e.publicFolder) !== "string" && typeof ((_h = (_g = (_f = schema.config) == null ? void 0 : _f.media) == null ? void 0 : _g.tina) == null ? void 0 : _h.mediaRoot) !== "string")
3432
3628
  return false;
3433
3629
  return true;
@@ -3454,7 +3650,9 @@ var LevelProxyHandler = {
3454
3650
  throw new Error(`The property, ${property.toString()}, doesn't exist`);
3455
3651
  }
3456
3652
  if (typeof target[property] !== "function") {
3457
- throw new Error(`The property, ${property.toString()}, is not a function`);
3653
+ throw new Error(
3654
+ `The property, ${property.toString()}, is not a function`
3655
+ );
3458
3656
  }
3459
3657
  if (property === "get") {
3460
3658
  return async (...args) => {
@@ -3471,6 +3669,7 @@ var LevelProxyHandler = {
3471
3669
  } else if (property === "sublevel") {
3472
3670
  return (...args) => {
3473
3671
  return new Proxy(
3672
+ // eslint-disable-next-line prefer-spread
3474
3673
  target[property].apply(target, args),
3475
3674
  LevelProxyHandler
3476
3675
  );
@@ -3493,7 +3692,7 @@ var import_path2 = __toESM(require("path"));
3493
3692
  var import_toml = __toESM(require("@iarna/toml"));
3494
3693
  var import_js_yaml = __toESM(require("js-yaml"));
3495
3694
  var import_gray_matter = __toESM(require("gray-matter"));
3496
- var import_schema_tools3 = require("@tinacms/schema-tools");
3695
+ var import_schema_tools4 = require("@tinacms/schema-tools");
3497
3696
  var import_micromatch = __toESM(require("micromatch"));
3498
3697
  var import_path = __toESM(require("path"));
3499
3698
 
@@ -3706,7 +3905,7 @@ var scanAllContent = async (tinaSchema, bridge, callback) => {
3706
3905
  const filesSeen = /* @__PURE__ */ new Map();
3707
3906
  const duplicateFiles = /* @__PURE__ */ new Set();
3708
3907
  await sequential(tinaSchema.getCollections(), async (collection) => {
3709
- const normalPath = (0, import_schema_tools3.normalizePath)(collection.path);
3908
+ const normalPath = (0, import_schema_tools4.normalizePath)(collection.path);
3710
3909
  const format = collection.format || "md";
3711
3910
  const documentPaths = await bridge.glob(normalPath, format);
3712
3911
  const matches = tinaSchema.getMatches({ collection });
@@ -3818,7 +4017,7 @@ var getTemplateForFile = (templateInfo, data) => {
3818
4017
  throw new Error(`Unable to determine template`);
3819
4018
  };
3820
4019
  var loadAndParseWithAliases = async (bridge, filepath, collection, templateInfo) => {
3821
- const dataString = await bridge.get((0, import_schema_tools3.normalizePath)(filepath));
4020
+ const dataString = await bridge.get((0, import_schema_tools4.normalizePath)(filepath));
3822
4021
  const data = parseFile(
3823
4022
  dataString,
3824
4023
  import_path.default.extname(filepath),
@@ -3840,6 +4039,9 @@ var loadAndParseWithAliases = async (bridge, filepath, collection, templateInfo)
3840
4039
 
3841
4040
  // src/database/datalayer.ts
3842
4041
  var DEFAULT_COLLECTION_SORT_KEY = "__filepath__";
4042
+ var REFS_COLLECTIONS_SORT_KEY = "__refs__";
4043
+ var REFS_REFERENCE_FIELD = "__tina_ref__";
4044
+ var REFS_PATH_FIELD = "__tina_ref_path__";
3843
4045
  var DEFAULT_NUMERIC_LPAD = 4;
3844
4046
  var applyPadding = (input, pad) => {
3845
4047
  if (pad) {
@@ -4297,7 +4499,7 @@ var FolderTreeBuilder = class {
4297
4499
  return this._tree;
4298
4500
  }
4299
4501
  update(documentPath, collectionPath) {
4300
- let folderPath = import_path2.default.dirname((0, import_schema_tools3.normalizePath)(documentPath));
4502
+ let folderPath = import_path2.default.dirname((0, import_schema_tools4.normalizePath)(documentPath));
4301
4503
  if (folderPath === ".") {
4302
4504
  folderPath = "";
4303
4505
  }
@@ -4310,7 +4512,7 @@ var FolderTreeBuilder = class {
4310
4512
  if (!this._tree[current2]) {
4311
4513
  this._tree[current2] = /* @__PURE__ */ new Set();
4312
4514
  }
4313
- this._tree[current2].add((0, import_schema_tools3.normalizePath)(import_path2.default.join(current2, part)));
4515
+ this._tree[current2].add((0, import_schema_tools4.normalizePath)(import_path2.default.join(current2, part)));
4314
4516
  parent.push(part);
4315
4517
  });
4316
4518
  const current = parent.join("/");
@@ -4349,6 +4551,7 @@ var makeFolderOpsForCollection = (folderTree, collection, indexDefinitions, opTy
4349
4551
  result.push({
4350
4552
  type: opType,
4351
4553
  key: `${collection.path}/${subFolderKey}.${collection.format}`,
4554
+ // replace the root with the collection path
4352
4555
  sublevel: indexSublevel,
4353
4556
  value: {}
4354
4557
  });
@@ -4412,6 +4615,57 @@ var makeIndexOpsForDocument = (filepath, collection, indexDefinitions, data, opT
4412
4615
  }
4413
4616
  return result;
4414
4617
  };
4618
+ var makeRefOpsForDocument = (filepath, collection, references, data, opType, level) => {
4619
+ const result = [];
4620
+ if (collection) {
4621
+ for (const [c, referencePaths] of Object.entries(references || {})) {
4622
+ if (!referencePaths.length) {
4623
+ continue;
4624
+ }
4625
+ const collectionSublevel = level.sublevel(c, SUBLEVEL_OPTIONS);
4626
+ const refSublevel = collectionSublevel.sublevel(
4627
+ REFS_COLLECTIONS_SORT_KEY,
4628
+ SUBLEVEL_OPTIONS
4629
+ );
4630
+ const references2 = {};
4631
+ for (const path7 of referencePaths) {
4632
+ const ref = (0, import_jsonpath_plus.JSONPath)({ path: path7, json: data });
4633
+ if (!ref) {
4634
+ continue;
4635
+ }
4636
+ if (Array.isArray(ref)) {
4637
+ for (const r of ref) {
4638
+ if (!r) {
4639
+ continue;
4640
+ }
4641
+ if (references2[r]) {
4642
+ references2[r].push(path7);
4643
+ } else {
4644
+ references2[r] = [path7];
4645
+ }
4646
+ }
4647
+ } else {
4648
+ if (references2[ref]) {
4649
+ references2[ref].push(path7);
4650
+ } else {
4651
+ references2[ref] = [path7];
4652
+ }
4653
+ }
4654
+ }
4655
+ for (const ref of Object.keys(references2)) {
4656
+ for (const path7 of references2[ref]) {
4657
+ result.push({
4658
+ type: opType,
4659
+ key: `${ref}${INDEX_KEY_FIELD_SEPARATOR}${path7}${INDEX_KEY_FIELD_SEPARATOR}${filepath}`,
4660
+ sublevel: refSublevel,
4661
+ value: opType === "put" ? {} : void 0
4662
+ });
4663
+ }
4664
+ }
4665
+ }
4666
+ }
4667
+ return result;
4668
+ };
4415
4669
  var makeStringEscaper = (regex, replacement) => {
4416
4670
  return (input) => {
4417
4671
  if (Array.isArray(input)) {
@@ -4464,6 +4718,7 @@ var resolveFieldData = async ({ namespace, ...field }, rawData, accumulator, tin
4464
4718
  case "password":
4465
4719
  accumulator[field.name] = {
4466
4720
  value: void 0,
4721
+ // never resolve the password hash
4467
4722
  passwordChangeRequired: (_a = value["passwordChangeRequired"]) != null ? _a : false
4468
4723
  };
4469
4724
  break;
@@ -4632,24 +4887,33 @@ var transformDocumentIntoPayload = async (fullPath, rawData, tinaSchema, config,
4632
4887
  throw e;
4633
4888
  }
4634
4889
  };
4635
- var updateObjectWithJsonPath = (obj, path7, newValue) => {
4890
+ var updateObjectWithJsonPath = (obj, path7, oldValue, newValue) => {
4891
+ let updated = false;
4636
4892
  if (!path7.includes(".") && !path7.includes("[")) {
4637
- if (path7 in obj) {
4893
+ if (path7 in obj && obj[path7] === oldValue) {
4638
4894
  obj[path7] = newValue;
4895
+ updated = true;
4639
4896
  }
4640
- return obj;
4641
- }
4642
- const parentPath = path7.replace(/\.[^.]+$/, "");
4643
- const keyToUpdate = path7.match(/[^.]+$/)[0];
4644
- const parents = (0, import_jsonpath_plus2.JSONPath)({ path: parentPath, json: obj, resultType: "value" });
4897
+ return { object: obj, updated };
4898
+ }
4899
+ const parentPath = path7.replace(/\.[^.\[\]]+$/, "");
4900
+ const keyToUpdate = path7.match(/[^.\[\]]+$/)[0];
4901
+ const parents = (0, import_jsonpath_plus2.JSONPath)({
4902
+ path: parentPath,
4903
+ json: obj,
4904
+ resultType: "value"
4905
+ });
4645
4906
  if (parents.length > 0) {
4646
4907
  parents.forEach((parent) => {
4647
4908
  if (parent && typeof parent === "object" && keyToUpdate in parent) {
4648
- parent[keyToUpdate] = newValue;
4909
+ if (parent[keyToUpdate] === oldValue) {
4910
+ parent[keyToUpdate] = newValue;
4911
+ updated = true;
4912
+ }
4649
4913
  }
4650
4914
  });
4651
4915
  }
4652
- return obj;
4916
+ return { object: obj, updated };
4653
4917
  };
4654
4918
  var Resolver = class {
4655
4919
  constructor(init) {
@@ -4658,6 +4922,7 @@ var Resolver = class {
4658
4922
  const collection = this.tinaSchema.getCollection(collectionName);
4659
4923
  const extraFields = {};
4660
4924
  return {
4925
+ // return the collection and hasDocuments to resolve documents at a lower level
4661
4926
  documents: { collection, hasDocuments },
4662
4927
  ...collection,
4663
4928
  ...extraFields
@@ -4665,7 +4930,9 @@ var Resolver = class {
4665
4930
  };
4666
4931
  this.getRaw = async (fullPath) => {
4667
4932
  if (typeof fullPath !== "string") {
4668
- throw new Error(`fullPath must be of type string for getDocument request`);
4933
+ throw new Error(
4934
+ `fullPath must be of type string for getDocument request`
4935
+ );
4669
4936
  }
4670
4937
  return this.database.get(fullPath);
4671
4938
  };
@@ -4694,7 +4961,9 @@ var Resolver = class {
4694
4961
  };
4695
4962
  this.getDocument = async (fullPath, opts = {}) => {
4696
4963
  if (typeof fullPath !== "string") {
4697
- throw new Error(`fullPath must be of type string for getDocument request`);
4964
+ throw new Error(
4965
+ `fullPath must be of type string for getDocument request`
4966
+ );
4698
4967
  }
4699
4968
  const rawData = await this.getRaw(fullPath);
4700
4969
  const hasReferences = (opts == null ? void 0 : opts.checkReferences) ? await this.hasReferences(fullPath, opts.collection) : void 0;
@@ -4709,7 +4978,9 @@ var Resolver = class {
4709
4978
  };
4710
4979
  this.deleteDocument = async (fullPath) => {
4711
4980
  if (typeof fullPath !== "string") {
4712
- throw new Error(`fullPath must be of type string for getDocument request`);
4981
+ throw new Error(
4982
+ `fullPath must be of type string for getDocument request`
4983
+ );
4713
4984
  }
4714
4985
  await this.database.delete(fullPath);
4715
4986
  };
@@ -4744,7 +5015,9 @@ var Resolver = class {
4744
5015
  );
4745
5016
  } else {
4746
5017
  return this.buildFieldMutations(
5018
+ // @ts-ignore FIXME Argument of type 'string | object' is not assignable to parameter of type '{ [fieldName: string]: string | object | (string | object)[]; }'
4747
5019
  fieldValue,
5020
+ //@ts-ignore
4748
5021
  objectTemplate,
4749
5022
  existingData
4750
5023
  );
@@ -4756,6 +5029,7 @@ var Resolver = class {
4756
5029
  fieldValue.map(async (item) => {
4757
5030
  if (typeof item === "string") {
4758
5031
  throw new Error(
5032
+ //@ts-ignore
4759
5033
  `Expected object for template value for field ${field.name}`
4760
5034
  );
4761
5035
  }
@@ -4764,16 +5038,19 @@ var Resolver = class {
4764
5038
  });
4765
5039
  const [templateName] = Object.entries(item)[0];
4766
5040
  const template = templates.find(
5041
+ //@ts-ignore
4767
5042
  (template2) => template2.name === templateName
4768
5043
  );
4769
5044
  if (!template) {
4770
5045
  throw new Error(`Expected to find template ${templateName}`);
4771
5046
  }
4772
5047
  return {
5048
+ // @ts-ignore FIXME Argument of type 'unknown' is not assignable to parameter of type '{ [fieldName: string]: string | { [key: string]: unknown; } | (string | { [key: string]: unknown; })[]; }'
4773
5049
  ...await this.buildFieldMutations(
4774
5050
  item[template.name],
4775
5051
  template
4776
5052
  ),
5053
+ //@ts-ignore
4777
5054
  _template: template.name
4778
5055
  };
4779
5056
  })
@@ -4781,6 +5058,7 @@ var Resolver = class {
4781
5058
  } else {
4782
5059
  if (typeof fieldValue === "string") {
4783
5060
  throw new Error(
5061
+ //@ts-ignore
4784
5062
  `Expected object for template value for field ${field.name}`
4785
5063
  );
4786
5064
  }
@@ -4789,16 +5067,19 @@ var Resolver = class {
4789
5067
  });
4790
5068
  const [templateName] = Object.entries(fieldValue)[0];
4791
5069
  const template = templates.find(
5070
+ //@ts-ignore
4792
5071
  (template2) => template2.name === templateName
4793
5072
  );
4794
5073
  if (!template) {
4795
5074
  throw new Error(`Expected to find template ${templateName}`);
4796
5075
  }
4797
5076
  return {
5077
+ // @ts-ignore FIXME Argument of type 'unknown' is not assignable to parameter of type '{ [fieldName: string]: string | { [key: string]: unknown; } | (string | { [key: string]: unknown; })[]; }'
4798
5078
  ...await this.buildFieldMutations(
4799
5079
  fieldValue[template.name],
4800
5080
  template
4801
5081
  ),
5082
+ //@ts-ignore
4802
5083
  _template: template.name
4803
5084
  };
4804
5085
  }
@@ -4838,6 +5119,7 @@ var Resolver = class {
4838
5119
  return this.getDocument(realPath);
4839
5120
  }
4840
5121
  const params = await this.buildObjectMutations(
5122
+ // @ts-ignore
4841
5123
  args.params[collection.name],
4842
5124
  collection
4843
5125
  );
@@ -4883,6 +5165,7 @@ var Resolver = class {
4883
5165
  const values = {
4884
5166
  ...oldDoc,
4885
5167
  ...await this.buildFieldMutations(
5168
+ // @ts-ignore FIXME: failing on unknown, which we don't need to know because it's recursive
4886
5169
  templateParams,
4887
5170
  template,
4888
5171
  doc == null ? void 0 : doc._rawData
@@ -4896,13 +5179,22 @@ var Resolver = class {
4896
5179
  return this.getDocument(realPath);
4897
5180
  }
4898
5181
  const params = await this.buildObjectMutations(
5182
+ //@ts-ignore
4899
5183
  isCollectionSpecific ? args.params : args.params[collection.name],
4900
5184
  collection,
4901
5185
  doc == null ? void 0 : doc._rawData
4902
5186
  );
4903
- await this.database.put(realPath, { ...oldDoc, ...params }, collection.name);
5187
+ await this.database.put(
5188
+ realPath,
5189
+ { ...oldDoc, ...params },
5190
+ collection.name
5191
+ );
4904
5192
  return this.getDocument(realPath);
4905
5193
  };
5194
+ /**
5195
+ * Returns top-level fields which are not defined in the collection, so their
5196
+ * values are not eliminated from Tina when new values are saved
5197
+ */
4906
5198
  this.resolveLegacyValues = (oldDoc, collection) => {
4907
5199
  const legacyValues = {};
4908
5200
  Object.entries(oldDoc).forEach(([key, value]) => {
@@ -5010,17 +5302,35 @@ var Resolver = class {
5010
5302
  await this.deleteDocument(realPath);
5011
5303
  if (await this.hasReferences(realPath, collection)) {
5012
5304
  const collRefs = await this.findReferences(realPath, collection);
5013
- for (const [collection2, refFields] of Object.entries(collRefs)) {
5014
- for (const [refPath, refs] of Object.entries(refFields)) {
5015
- let refDoc = await this.getRaw(refPath);
5016
- for (const ref of refs) {
5017
- refDoc = updateObjectWithJsonPath(
5305
+ for (const [collection2, docsWithRefs] of Object.entries(collRefs)) {
5306
+ for (const [pathToDocWithRef, referencePaths] of Object.entries(
5307
+ docsWithRefs
5308
+ )) {
5309
+ let refDoc = await this.getRaw(pathToDocWithRef);
5310
+ let hasUpdate = false;
5311
+ for (const path7 of referencePaths) {
5312
+ const { object: object2, updated } = updateObjectWithJsonPath(
5018
5313
  refDoc,
5019
- ref.path.join("."),
5314
+ path7,
5315
+ realPath,
5020
5316
  null
5021
5317
  );
5318
+ refDoc = object2;
5319
+ hasUpdate = updated || hasUpdate;
5320
+ }
5321
+ if (hasUpdate) {
5322
+ const collectionWithRef = this.tinaSchema.getCollectionByFullPath(pathToDocWithRef);
5323
+ if (!collectionWithRef) {
5324
+ throw new Error(
5325
+ `Unable to find collection for ${pathToDocWithRef}`
5326
+ );
5327
+ }
5328
+ await this.database.put(
5329
+ pathToDocWithRef,
5330
+ refDoc,
5331
+ collectionWithRef.name
5332
+ );
5022
5333
  }
5023
- await this.database.put(refPath, refDoc, collection2);
5024
5334
  }
5025
5335
  }
5026
5336
  }
@@ -5040,26 +5350,49 @@ var Resolver = class {
5040
5350
  collection == null ? void 0 : collection.path,
5041
5351
  args.params.relativePath
5042
5352
  );
5353
+ if (newRealPath === realPath) {
5354
+ return doc;
5355
+ }
5043
5356
  await this.database.put(newRealPath, doc._rawData, collection.name);
5044
5357
  await this.deleteDocument(realPath);
5045
5358
  const collRefs = await this.findReferences(realPath, collection);
5046
- for (const [collection2, refFields] of Object.entries(collRefs)) {
5047
- for (const [refPath, refs] of Object.entries(refFields)) {
5048
- let refDoc = await this.getRaw(refPath);
5049
- for (const ref of refs) {
5050
- refDoc = updateObjectWithJsonPath(
5051
- refDoc,
5052
- ref.path.join("."),
5359
+ for (const [collection2, docsWithRefs] of Object.entries(collRefs)) {
5360
+ for (const [pathToDocWithRef, referencePaths] of Object.entries(
5361
+ docsWithRefs
5362
+ )) {
5363
+ let docWithRef = await this.getRaw(pathToDocWithRef);
5364
+ let hasUpdate = false;
5365
+ for (const path7 of referencePaths) {
5366
+ const { object: object2, updated } = updateObjectWithJsonPath(
5367
+ docWithRef,
5368
+ path7,
5369
+ realPath,
5053
5370
  newRealPath
5054
5371
  );
5372
+ docWithRef = object2;
5373
+ hasUpdate = updated || hasUpdate;
5374
+ }
5375
+ if (hasUpdate) {
5376
+ const collectionWithRef = this.tinaSchema.getCollectionByFullPath(pathToDocWithRef);
5377
+ if (!collectionWithRef) {
5378
+ throw new Error(
5379
+ `Unable to find collection for ${pathToDocWithRef}`
5380
+ );
5381
+ }
5382
+ await this.database.put(
5383
+ pathToDocWithRef,
5384
+ docWithRef,
5385
+ collectionWithRef.name
5386
+ );
5055
5387
  }
5056
- await this.database.put(refPath, refDoc, collection2);
5057
5388
  }
5058
5389
  }
5059
5390
  return this.getDocument(newRealPath);
5060
5391
  }
5061
5392
  if (alreadyExists === false) {
5062
- throw new Error(`Unable to update document, ${realPath} does not exist`);
5393
+ throw new Error(
5394
+ `Unable to update document, ${realPath} does not exist`
5395
+ );
5063
5396
  }
5064
5397
  return this.updateResolveDocument({
5065
5398
  collection,
@@ -5109,6 +5442,7 @@ var Resolver = class {
5109
5442
  },
5110
5443
  collection: referencedCollection,
5111
5444
  hydrator: (path7) => path7
5445
+ // just return the path
5112
5446
  }
5113
5447
  );
5114
5448
  const { edges } = resolvedCollectionConnection;
@@ -5176,78 +5510,80 @@ var Resolver = class {
5176
5510
  }
5177
5511
  };
5178
5512
  };
5513
+ /**
5514
+ * Checks if a document has references to it
5515
+ * @param id The id of the document to check for references
5516
+ * @param c The collection to check for references
5517
+ * @returns true if the document has references, false otherwise
5518
+ */
5179
5519
  this.hasReferences = async (id, c) => {
5180
5520
  let count = 0;
5181
- const deepRefs = this.tinaSchema.findReferences(c.name);
5182
- for (const [collection, refs] of Object.entries(deepRefs)) {
5183
- for (const ref of refs) {
5184
- await this.database.query(
5185
- {
5186
- collection,
5187
- filterChain: makeFilterChain({
5188
- conditions: [
5189
- {
5190
- filterPath: ref.path.join("."),
5191
- filterExpression: {
5192
- _type: "reference",
5193
- _list: false,
5194
- eq: id
5195
- }
5196
- }
5197
- ]
5198
- }),
5199
- sort: ref.field.name
5200
- },
5201
- (refId) => {
5202
- count++;
5203
- return refId;
5204
- }
5205
- );
5206
- if (count) {
5207
- return true;
5208
- }
5521
+ await this.database.query(
5522
+ {
5523
+ collection: c.name,
5524
+ filterChain: makeFilterChain({
5525
+ conditions: [
5526
+ {
5527
+ filterPath: REFS_REFERENCE_FIELD,
5528
+ filterExpression: {
5529
+ _type: "string",
5530
+ _list: false,
5531
+ eq: id
5532
+ }
5533
+ }
5534
+ ]
5535
+ }),
5536
+ sort: REFS_COLLECTIONS_SORT_KEY
5537
+ },
5538
+ (refId) => {
5539
+ count++;
5540
+ return refId;
5209
5541
  }
5542
+ );
5543
+ if (count) {
5544
+ return true;
5210
5545
  }
5211
5546
  return false;
5212
5547
  };
5548
+ /**
5549
+ * Finds references to a document
5550
+ * @param id the id of the document to find references to
5551
+ * @param c the collection to find references in
5552
+ * @returns a map of references to the document
5553
+ */
5213
5554
  this.findReferences = async (id, c) => {
5214
5555
  const references = {};
5215
- const deepRefs = this.tinaSchema.findReferences(c.name);
5216
- for (const [collection, refs] of Object.entries(deepRefs)) {
5217
- for (const ref of refs) {
5218
- await this.database.query(
5219
- {
5220
- collection,
5221
- filterChain: makeFilterChain({
5222
- conditions: [
5223
- {
5224
- filterPath: ref.path.join("."),
5225
- filterExpression: {
5226
- _type: "reference",
5227
- _list: false,
5228
- eq: id
5229
- }
5230
- }
5231
- ]
5232
- }),
5233
- sort: ref.field.name
5234
- },
5235
- (refId) => {
5236
- if (!references[collection]) {
5237
- references[collection] = {};
5238
- }
5239
- if (!references[collection][refId]) {
5240
- references[collection][refId] = [];
5556
+ await this.database.query(
5557
+ {
5558
+ collection: c.name,
5559
+ filterChain: makeFilterChain({
5560
+ conditions: [
5561
+ {
5562
+ filterPath: REFS_REFERENCE_FIELD,
5563
+ filterExpression: {
5564
+ _type: "string",
5565
+ _list: false,
5566
+ eq: id
5567
+ }
5241
5568
  }
5242
- references[collection][refId].push({
5243
- path: ref.path,
5244
- field: ref.field
5245
- });
5246
- return refId;
5247
- }
5248
- );
5569
+ ]
5570
+ }),
5571
+ sort: REFS_COLLECTIONS_SORT_KEY
5572
+ },
5573
+ (refId, rawItem) => {
5574
+ if (!references[c.name]) {
5575
+ references[c.name] = {};
5576
+ }
5577
+ if (!references[c.name][refId]) {
5578
+ references[c.name][refId] = [];
5579
+ }
5580
+ const referencePath = rawItem == null ? void 0 : rawItem[REFS_PATH_FIELD];
5581
+ if (referencePath) {
5582
+ references[c.name][refId].push(referencePath);
5583
+ }
5584
+ return refId;
5249
5585
  }
5250
- }
5586
+ );
5251
5587
  return references;
5252
5588
  };
5253
5589
  this.buildFieldMutations = async (fieldParams, template, existingData) => {
@@ -5337,6 +5673,27 @@ var Resolver = class {
5337
5673
  }
5338
5674
  return accum;
5339
5675
  };
5676
+ /**
5677
+ * A mutation looks nearly identical between updateDocument:
5678
+ * ```graphql
5679
+ * updateDocument(collection: $collection,relativePath: $path, params: {
5680
+ * post: {
5681
+ * title: "Hello, World"
5682
+ * }
5683
+ * })`
5684
+ * ```
5685
+ * and `updatePostDocument`:
5686
+ * ```graphql
5687
+ * updatePostDocument(relativePath: $path, params: {
5688
+ * title: "Hello, World"
5689
+ * })
5690
+ * ```
5691
+ * The problem here is that we don't know whether the payload came from `updateDocument`
5692
+ * or `updatePostDocument` (we could, but for now it's easier not to pipe those details through),
5693
+ * But we do know that when given a `args.collection` value, we can assume that
5694
+ * this was a `updateDocument` request, and thus - should grab the data
5695
+ * from the corresponding field name in the key
5696
+ */
5340
5697
  this.buildParams = (args) => {
5341
5698
  try {
5342
5699
  assertShape(
@@ -5437,7 +5794,10 @@ var resolve = async ({
5437
5794
  const graphQLSchema = (0, import_graphql5.buildASTSchema)(graphQLSchemaAst);
5438
5795
  const tinaConfig = await database.getTinaSchema();
5439
5796
  const tinaSchema = await createSchema({
5797
+ // TODO: please update all the types to import from @tinacms/schema-tools
5798
+ // @ts-ignore
5440
5799
  schema: tinaConfig,
5800
+ // @ts-ignore
5441
5801
  flags: (_a = tinaConfig == null ? void 0 : tinaConfig.meta) == null ? void 0 : _a.flags
5442
5802
  });
5443
5803
  const resolver = createResolver({
@@ -5454,8 +5814,7 @@ var resolve = async ({
5454
5814
  database
5455
5815
  },
5456
5816
  typeResolver: async (source, _args, info) => {
5457
- if (source.__typename)
5458
- return source.__typename;
5817
+ if (source.__typename) return source.__typename;
5459
5818
  const namedType = (0, import_graphql5.getNamedType)(info.returnType).toString();
5460
5819
  const lookup = await database.getLookup(namedType);
5461
5820
  if (lookup.resolveType === "unionData") {
@@ -5607,11 +5966,13 @@ var resolve = async ({
5607
5966
  (0, import_lodash4.default)(
5608
5967
  params,
5609
5968
  userField.path.slice(1),
5969
+ // remove _rawData from users path
5610
5970
  users.map((u) => {
5611
5971
  if (user[idFieldName] === u[idFieldName]) {
5612
5972
  return user;
5613
5973
  }
5614
5974
  return {
5975
+ // don't overwrite other users' passwords
5615
5976
  ...u,
5616
5977
  [passwordFieldName]: {
5617
5978
  ...u[passwordFieldName],
@@ -5634,6 +5995,9 @@ var resolve = async ({
5634
5995
  }
5635
5996
  const isCreation = lookup[info.fieldName] === "create";
5636
5997
  switch (lookup.resolveType) {
5998
+ /**
5999
+ * `node(id: $id)`
6000
+ */
5637
6001
  case "nodeDocument":
5638
6002
  assertShape(
5639
6003
  args,
@@ -5665,6 +6029,7 @@ var resolve = async ({
5665
6029
  collection: args.collection,
5666
6030
  isMutation,
5667
6031
  isCreation,
6032
+ // Right now this is the only case for deletion
5668
6033
  isDeletion: info.fieldName === "deleteDocument",
5669
6034
  isFolderCreation: info.fieldName === "createFolder",
5670
6035
  isUpdateName: Boolean((_a2 = args == null ? void 0 : args.params) == null ? void 0 : _a2.relativePath),
@@ -5674,6 +6039,9 @@ var resolve = async ({
5674
6039
  return result;
5675
6040
  }
5676
6041
  return value;
6042
+ /**
6043
+ * eg `getMovieDocument.data.actors`
6044
+ */
5677
6045
  case "multiCollectionDocumentList":
5678
6046
  if (Array.isArray(value)) {
5679
6047
  return {
@@ -5685,7 +6053,15 @@ var resolve = async ({
5685
6053
  }
5686
6054
  if (info.fieldName === "documents" && (value == null ? void 0 : value.collection) && (value == null ? void 0 : value.hasDocuments)) {
5687
6055
  let filter = args.filter;
5688
- if (typeof (args == null ? void 0 : args.filter) !== "undefined" && (args == null ? void 0 : args.filter) !== null && typeof ((_b = value == null ? void 0 : value.collection) == null ? void 0 : _b.name) === "string" && Object.keys(args.filter).includes((_c = value == null ? void 0 : value.collection) == null ? void 0 : _c.name) && typeof args.filter[(_d = value == null ? void 0 : value.collection) == null ? void 0 : _d.name] !== "undefined") {
6056
+ if (
6057
+ // 1. Make sure that the filter exists
6058
+ typeof (args == null ? void 0 : args.filter) !== "undefined" && (args == null ? void 0 : args.filter) !== null && // 2. Make sure that the collection name exists
6059
+ // @ts-ignore
6060
+ typeof ((_b = value == null ? void 0 : value.collection) == null ? void 0 : _b.name) === "string" && // 3. Make sure that the collection name is in the filter and is not undefined
6061
+ // @ts-ignore
6062
+ Object.keys(args.filter).includes((_c = value == null ? void 0 : value.collection) == null ? void 0 : _c.name) && // @ts-ignore
6063
+ typeof args.filter[(_d = value == null ? void 0 : value.collection) == null ? void 0 : _d.name] !== "undefined"
6064
+ ) {
5689
6065
  filter = args.filter[value.collection.name];
5690
6066
  }
5691
6067
  return resolver.resolveCollectionConnection({
@@ -5693,12 +6069,20 @@ var resolve = async ({
5693
6069
  ...args,
5694
6070
  filter
5695
6071
  },
6072
+ // @ts-ignore
5696
6073
  collection: value.collection
5697
6074
  });
5698
6075
  }
5699
6076
  throw new Error(
5700
6077
  `Expected an array for result of ${info.fieldName} at ${info.path}`
5701
6078
  );
6079
+ /**
6080
+ * Collections-specific getter
6081
+ * eg. `getPostDocument`/`createPostDocument`/`updatePostDocument`
6082
+ *
6083
+ * if coming from a query result
6084
+ * the field will be `node`
6085
+ */
5702
6086
  case "collectionDocument": {
5703
6087
  if (value) {
5704
6088
  return value;
@@ -5713,11 +6097,32 @@ var resolve = async ({
5713
6097
  });
5714
6098
  return result;
5715
6099
  }
6100
+ /**
6101
+ * Collections-specific list getter
6102
+ * eg. `getPageList`
6103
+ */
5716
6104
  case "collectionDocumentList":
5717
6105
  return resolver.resolveCollectionConnection({
5718
6106
  args,
5719
6107
  collection: tinaSchema.getCollection(lookup.collection)
5720
6108
  });
6109
+ /**
6110
+ * A polymorphic data set, it can be from a document's data
6111
+ * of any nested object which can be one of many shapes
6112
+ *
6113
+ * ```graphql
6114
+ * getPostDocument(relativePath: $relativePath) {
6115
+ * data {...} <- this part
6116
+ * }
6117
+ * ```
6118
+ * ```graphql
6119
+ * getBlockDocument(relativePath: $relativePath) {
6120
+ * data {
6121
+ * blocks {...} <- or this part
6122
+ * }
6123
+ * }
6124
+ * ```
6125
+ */
5721
6126
  case "unionData":
5722
6127
  if (!value) {
5723
6128
  if (args.relativePath) {
@@ -5782,8 +6187,7 @@ var TinaLevelClient = class extends import_many_level.ManyLevelGuest {
5782
6187
  this.port = port || 9e3;
5783
6188
  }
5784
6189
  openConnection() {
5785
- if (this._connected)
5786
- return;
6190
+ if (this._connected) return;
5787
6191
  const socket = (0, import_net.connect)(this.port);
5788
6192
  (0, import_readable_stream.pipeline)(socket, this.createRpcStream(), socket, () => {
5789
6193
  this._connected = false;
@@ -5903,7 +6307,7 @@ var Database = class {
5903
6307
  const contentObject = await level.sublevel(
5904
6308
  CONTENT_ROOT_PREFIX,
5905
6309
  SUBLEVEL_OPTIONS
5906
- ).get((0, import_schema_tools3.normalizePath)(filepath));
6310
+ ).get((0, import_schema_tools4.normalizePath)(filepath));
5907
6311
  if (!contentObject) {
5908
6312
  throw new NotFoundError(`Unable to find record ${filepath}`);
5909
6313
  }
@@ -5915,6 +6319,7 @@ var Database = class {
5915
6319
  }
5916
6320
  };
5917
6321
  this.addPendingDocument = async (filepath, data) => {
6322
+ var _a;
5918
6323
  await this.initLevel();
5919
6324
  const dataFields = await this.formatBodyOnPayload(filepath, data);
5920
6325
  const collection = await this.collectionForPath(filepath);
@@ -5928,7 +6333,8 @@ var Database = class {
5928
6333
  );
5929
6334
  const indexDefinitions = await this.getIndexDefinitions(this.contentLevel);
5930
6335
  const collectionIndexDefinitions = indexDefinitions == null ? void 0 : indexDefinitions[collection.name];
5931
- const normalizedPath = (0, import_schema_tools3.normalizePath)(filepath);
6336
+ const collectionReferences = (_a = await this.getCollectionReferences()) == null ? void 0 : _a[collection.name];
6337
+ const normalizedPath = (0, import_schema_tools4.normalizePath)(filepath);
5932
6338
  if (!(collection == null ? void 0 : collection.isDetached)) {
5933
6339
  if (this.bridge) {
5934
6340
  await this.bridge.put(normalizedPath, stringifiedFile);
@@ -5956,6 +6362,14 @@ var Database = class {
5956
6362
  let delOps = [];
5957
6363
  if (!isGitKeep(normalizedPath, collection)) {
5958
6364
  putOps = [
6365
+ ...makeRefOpsForDocument(
6366
+ normalizedPath,
6367
+ collection == null ? void 0 : collection.name,
6368
+ collectionReferences,
6369
+ dataFields,
6370
+ "put",
6371
+ level
6372
+ ),
5959
6373
  ...makeIndexOpsForDocument(
5960
6374
  normalizedPath,
5961
6375
  collection == null ? void 0 : collection.name,
@@ -5964,6 +6378,7 @@ var Database = class {
5964
6378
  "put",
5965
6379
  level
5966
6380
  ),
6381
+ // folder indices
5967
6382
  ...makeIndexOpsForDocument(
5968
6383
  normalizedPath,
5969
6384
  `${collection == null ? void 0 : collection.name}_${folderKey}`,
@@ -5978,6 +6393,14 @@ var Database = class {
5978
6393
  SUBLEVEL_OPTIONS
5979
6394
  ).get(normalizedPath);
5980
6395
  delOps = existingItem ? [
6396
+ ...makeRefOpsForDocument(
6397
+ normalizedPath,
6398
+ collection == null ? void 0 : collection.name,
6399
+ collectionReferences,
6400
+ existingItem,
6401
+ "del",
6402
+ level
6403
+ ),
5981
6404
  ...makeIndexOpsForDocument(
5982
6405
  normalizedPath,
5983
6406
  collection == null ? void 0 : collection.name,
@@ -5986,6 +6409,7 @@ var Database = class {
5986
6409
  "del",
5987
6410
  level
5988
6411
  ),
6412
+ // folder indices
5989
6413
  ...makeIndexOpsForDocument(
5990
6414
  normalizedPath,
5991
6415
  `${collection == null ? void 0 : collection.name}_${folderKey}`,
@@ -6012,7 +6436,7 @@ var Database = class {
6012
6436
  await level.batch(ops);
6013
6437
  };
6014
6438
  this.put = async (filepath, data, collectionName) => {
6015
- var _a, _b;
6439
+ var _a, _b, _c;
6016
6440
  await this.initLevel();
6017
6441
  try {
6018
6442
  if (SYSTEM_FILES.includes(filepath)) {
@@ -6025,13 +6449,14 @@ var Database = class {
6025
6449
  );
6026
6450
  collectionIndexDefinitions = indexDefinitions == null ? void 0 : indexDefinitions[collectionName];
6027
6451
  }
6028
- const normalizedPath = (0, import_schema_tools3.normalizePath)(filepath);
6452
+ const collectionReferences = (_a = await this.getCollectionReferences()) == null ? void 0 : _a[collectionName];
6453
+ const normalizedPath = (0, import_schema_tools4.normalizePath)(filepath);
6029
6454
  const dataFields = await this.formatBodyOnPayload(filepath, data);
6030
6455
  const collection = await this.collectionForPath(filepath);
6031
6456
  if (!collection) {
6032
6457
  throw new import_graphql6.GraphQLError(`Unable to find collection for ${filepath}.`);
6033
6458
  }
6034
- if (((_a = collection.match) == null ? void 0 : _a.exclude) || ((_b = collection.match) == null ? void 0 : _b.include)) {
6459
+ if (((_b = collection.match) == null ? void 0 : _b.exclude) || ((_c = collection.match) == null ? void 0 : _c.include)) {
6035
6460
  const matches = this.tinaSchema.getMatches({ collection });
6036
6461
  const match = import_micromatch2.default.isMatch(filepath, matches);
6037
6462
  if (!match) {
@@ -6072,6 +6497,14 @@ var Database = class {
6072
6497
  let delOps = [];
6073
6498
  if (!isGitKeep(normalizedPath, collection)) {
6074
6499
  putOps = [
6500
+ ...makeRefOpsForDocument(
6501
+ normalizedPath,
6502
+ collectionName,
6503
+ collectionReferences,
6504
+ dataFields,
6505
+ "put",
6506
+ level
6507
+ ),
6075
6508
  ...makeIndexOpsForDocument(
6076
6509
  normalizedPath,
6077
6510
  collectionName,
@@ -6080,6 +6513,7 @@ var Database = class {
6080
6513
  "put",
6081
6514
  level
6082
6515
  ),
6516
+ // folder indices
6083
6517
  ...makeIndexOpsForDocument(
6084
6518
  normalizedPath,
6085
6519
  `${collection == null ? void 0 : collection.name}_${folderKey}`,
@@ -6094,6 +6528,14 @@ var Database = class {
6094
6528
  SUBLEVEL_OPTIONS
6095
6529
  ).get(normalizedPath);
6096
6530
  delOps = existingItem ? [
6531
+ ...makeRefOpsForDocument(
6532
+ normalizedPath,
6533
+ collectionName,
6534
+ collectionReferences,
6535
+ existingItem,
6536
+ "del",
6537
+ level
6538
+ ),
6097
6539
  ...makeIndexOpsForDocument(
6098
6540
  normalizedPath,
6099
6541
  collectionName,
@@ -6102,6 +6544,7 @@ var Database = class {
6102
6544
  "del",
6103
6545
  level
6104
6546
  ),
6547
+ // folder indices
6105
6548
  ...makeIndexOpsForDocument(
6106
6549
  normalizedPath,
6107
6550
  `${collection == null ? void 0 : collection.name}_${folderKey}`,
@@ -6179,6 +6622,7 @@ var Database = class {
6179
6622
  aliasedData,
6180
6623
  extension,
6181
6624
  writeTemplateKey,
6625
+ //templateInfo.type === 'union',
6182
6626
  {
6183
6627
  frontmatterFormat: collection == null ? void 0 : collection.frontmatterFormat,
6184
6628
  frontmatterDelimiters: collection == null ? void 0 : collection.frontmatterDelimiters
@@ -6196,7 +6640,7 @@ var Database = class {
6196
6640
  };
6197
6641
  this.getLookup = async (returnType) => {
6198
6642
  await this.initLevel();
6199
- const lookupPath = (0, import_schema_tools3.normalizePath)(
6643
+ const lookupPath = (0, import_schema_tools4.normalizePath)(
6200
6644
  import_node_path.default.join(this.getGeneratedFolder(), `_lookup.json`)
6201
6645
  );
6202
6646
  if (!this._lookup) {
@@ -6209,7 +6653,7 @@ var Database = class {
6209
6653
  };
6210
6654
  this.getGraphQLSchema = async () => {
6211
6655
  await this.initLevel();
6212
- const graphqlPath = (0, import_schema_tools3.normalizePath)(
6656
+ const graphqlPath = (0, import_schema_tools4.normalizePath)(
6213
6657
  import_node_path.default.join(this.getGeneratedFolder(), `_graphql.json`)
6214
6658
  );
6215
6659
  return await this.contentLevel.sublevel(
@@ -6217,11 +6661,12 @@ var Database = class {
6217
6661
  SUBLEVEL_OPTIONS
6218
6662
  ).get(graphqlPath);
6219
6663
  };
6664
+ //TODO - is there a reason why the database fetches some config with "bridge.get", and some with "store.get"?
6220
6665
  this.getGraphQLSchemaFromBridge = async () => {
6221
6666
  if (!this.bridge) {
6222
6667
  throw new Error(`No bridge configured`);
6223
6668
  }
6224
- const graphqlPath = (0, import_schema_tools3.normalizePath)(
6669
+ const graphqlPath = (0, import_schema_tools4.normalizePath)(
6225
6670
  import_node_path.default.join(this.getGeneratedFolder(), `_graphql.json`)
6226
6671
  );
6227
6672
  const _graphql = await this.bridge.get(graphqlPath);
@@ -6229,7 +6674,7 @@ var Database = class {
6229
6674
  };
6230
6675
  this.getTinaSchema = async (level) => {
6231
6676
  await this.initLevel();
6232
- const schemaPath = (0, import_schema_tools3.normalizePath)(
6677
+ const schemaPath = (0, import_schema_tools4.normalizePath)(
6233
6678
  import_node_path.default.join(this.getGeneratedFolder(), `_schema.json`)
6234
6679
  );
6235
6680
  return await (level || this.contentLevel).sublevel(
@@ -6245,7 +6690,7 @@ var Database = class {
6245
6690
  const schema = existingSchema || await this.getTinaSchema(level || this.contentLevel);
6246
6691
  if (!schema) {
6247
6692
  throw new Error(
6248
- `Unable to get schema from level db: ${(0, import_schema_tools3.normalizePath)(
6693
+ `Unable to get schema from level db: ${(0, import_schema_tools4.normalizePath)(
6249
6694
  import_node_path.default.join(this.getGeneratedFolder(), `_schema.json`)
6250
6695
  )}`
6251
6696
  );
@@ -6253,6 +6698,22 @@ var Database = class {
6253
6698
  this.tinaSchema = await createSchema({ schema });
6254
6699
  return this.tinaSchema;
6255
6700
  };
6701
+ this.getCollectionReferences = async (level) => {
6702
+ if (this.collectionReferences) {
6703
+ return this.collectionReferences;
6704
+ }
6705
+ const result = {};
6706
+ const schema = await this.getSchema(level || this.contentLevel);
6707
+ const collections = schema.getCollections();
6708
+ for (const collection of collections) {
6709
+ const collectionReferences = this.tinaSchema.findReferencesFromCollection(
6710
+ collection.name
6711
+ );
6712
+ result[collection.name] = collectionReferences;
6713
+ }
6714
+ this.collectionReferences = result;
6715
+ return result;
6716
+ };
6256
6717
  this.getIndexDefinitions = async (level) => {
6257
6718
  if (!this.collectionIndexDefinitions) {
6258
6719
  await new Promise(async (resolve2, reject) => {
@@ -6262,10 +6723,53 @@ var Database = class {
6262
6723
  const collections = schema.getCollections();
6263
6724
  for (const collection of collections) {
6264
6725
  const indexDefinitions = {
6265
- [DEFAULT_COLLECTION_SORT_KEY]: { fields: [] }
6726
+ [DEFAULT_COLLECTION_SORT_KEY]: { fields: [] },
6727
+ // provide a default sort key which is the file sort
6728
+ // pseudo-index for the collection's references
6729
+ [REFS_COLLECTIONS_SORT_KEY]: {
6730
+ fields: [
6731
+ {
6732
+ name: REFS_REFERENCE_FIELD,
6733
+ type: "string",
6734
+ list: false
6735
+ },
6736
+ {
6737
+ name: REFS_PATH_FIELD,
6738
+ type: "string",
6739
+ list: false
6740
+ }
6741
+ ]
6742
+ }
6266
6743
  };
6267
- if (collection.fields) {
6268
- for (const field of collection.fields) {
6744
+ let fields = [];
6745
+ if (collection.templates) {
6746
+ const templateFieldMap = {};
6747
+ const conflictedFields = /* @__PURE__ */ new Set();
6748
+ for (const template of collection.templates) {
6749
+ for (const field of template.fields) {
6750
+ if (!templateFieldMap[field.name]) {
6751
+ templateFieldMap[field.name] = field;
6752
+ } else {
6753
+ if (templateFieldMap[field.name].type !== field.type) {
6754
+ console.warn(
6755
+ `Field ${field.name} has conflicting types in templates - skipping index`
6756
+ );
6757
+ conflictedFields.add(field.name);
6758
+ }
6759
+ }
6760
+ }
6761
+ }
6762
+ for (const conflictedField in conflictedFields) {
6763
+ delete templateFieldMap[conflictedField];
6764
+ }
6765
+ for (const field of Object.values(templateFieldMap)) {
6766
+ fields.push(field);
6767
+ }
6768
+ } else if (collection.fields) {
6769
+ fields = collection.fields;
6770
+ }
6771
+ if (fields) {
6772
+ for (const field of fields) {
6269
6773
  if (field.indexed !== void 0 && field.indexed === false || field.type === "object") {
6270
6774
  continue;
6271
6775
  }
@@ -6414,29 +6918,36 @@ var Database = class {
6414
6918
  }
6415
6919
  startKey = startKey || key || "";
6416
6920
  endKey = key || "";
6417
- edges = [...edges, { cursor: key, path: filepath }];
6921
+ edges = [...edges, { cursor: key, path: filepath, value: itemRecord }];
6418
6922
  }
6419
6923
  return {
6420
- edges: await sequential(edges, async (edge) => {
6421
- try {
6422
- const node = await hydrator(edge.path);
6423
- return {
6424
- node,
6425
- cursor: btoa(edge.cursor)
6426
- };
6427
- } catch (error) {
6428
- console.log(error);
6429
- if (error instanceof Error && (!edge.path.includes(".tina/__generated__/_graphql.json") || !edge.path.includes("tina/__generated__/_graphql.json"))) {
6430
- throw new TinaQueryError({
6431
- originalError: error,
6432
- file: edge.path,
6433
- collection: collection.name,
6434
- stack: error.stack
6435
- });
6924
+ edges: await sequential(
6925
+ edges,
6926
+ async ({
6927
+ cursor,
6928
+ path: path7,
6929
+ value
6930
+ }) => {
6931
+ try {
6932
+ const node = await hydrator(path7, value);
6933
+ return {
6934
+ node,
6935
+ cursor: btoa(cursor)
6936
+ };
6937
+ } catch (error) {
6938
+ console.log(error);
6939
+ if (error instanceof Error && (!path7.includes(".tina/__generated__/_graphql.json") || !path7.includes("tina/__generated__/_graphql.json"))) {
6940
+ throw new TinaQueryError({
6941
+ originalError: error,
6942
+ file: path7,
6943
+ collection: collection.name,
6944
+ stack: error.stack
6945
+ });
6946
+ }
6947
+ throw error;
6436
6948
  }
6437
- throw error;
6438
6949
  }
6439
- }),
6950
+ ),
6440
6951
  pageInfo: {
6441
6952
  hasPreviousPage,
6442
6953
  hasNextPage,
@@ -6461,7 +6972,7 @@ var Database = class {
6461
6972
  try {
6462
6973
  lookup = lookupFromLockFile || JSON.parse(
6463
6974
  await this.bridge.get(
6464
- (0, import_schema_tools3.normalizePath)(
6975
+ (0, import_schema_tools4.normalizePath)(
6465
6976
  import_node_path.default.join(this.getGeneratedFolder(), "_lookup.json")
6466
6977
  )
6467
6978
  )
@@ -6486,15 +6997,15 @@ var Database = class {
6486
6997
  }
6487
6998
  const contentRootLevel = nextLevel.sublevel(CONTENT_ROOT_PREFIX, SUBLEVEL_OPTIONS);
6488
6999
  await contentRootLevel.put(
6489
- (0, import_schema_tools3.normalizePath)(import_node_path.default.join(this.getGeneratedFolder(), "_graphql.json")),
7000
+ (0, import_schema_tools4.normalizePath)(import_node_path.default.join(this.getGeneratedFolder(), "_graphql.json")),
6490
7001
  graphQLSchema
6491
7002
  );
6492
7003
  await contentRootLevel.put(
6493
- (0, import_schema_tools3.normalizePath)(import_node_path.default.join(this.getGeneratedFolder(), "_schema.json")),
7004
+ (0, import_schema_tools4.normalizePath)(import_node_path.default.join(this.getGeneratedFolder(), "_schema.json")),
6494
7005
  tinaSchema.schema
6495
7006
  );
6496
7007
  await contentRootLevel.put(
6497
- (0, import_schema_tools3.normalizePath)(import_node_path.default.join(this.getGeneratedFolder(), "_lookup.json")),
7008
+ (0, import_schema_tools4.normalizePath)(import_node_path.default.join(this.getGeneratedFolder(), "_lookup.json")),
6498
7009
  lookup
6499
7010
  );
6500
7011
  const result = await this._indexAllContent(
@@ -6576,23 +7087,25 @@ var Database = class {
6576
7087
  }
6577
7088
  };
6578
7089
  this.delete = async (filepath) => {
7090
+ var _a;
6579
7091
  await this.initLevel();
6580
7092
  const collection = await this.collectionForPath(filepath);
6581
7093
  if (!collection) {
6582
7094
  throw new Error(`No collection found for path: ${filepath}`);
6583
7095
  }
6584
7096
  const indexDefinitions = await this.getIndexDefinitions(this.contentLevel);
7097
+ const collectionReferences = (_a = await this.getCollectionReferences()) == null ? void 0 : _a[collection.name];
6585
7098
  const collectionIndexDefinitions = indexDefinitions == null ? void 0 : indexDefinitions[collection.name];
6586
7099
  let level = this.contentLevel;
6587
7100
  if (collection == null ? void 0 : collection.isDetached) {
6588
7101
  level = this.appLevel.sublevel(collection == null ? void 0 : collection.name, SUBLEVEL_OPTIONS);
6589
7102
  }
6590
- const itemKey = (0, import_schema_tools3.normalizePath)(filepath);
7103
+ const normalizedPath = (0, import_schema_tools4.normalizePath)(filepath);
6591
7104
  const rootSublevel = level.sublevel(
6592
7105
  CONTENT_ROOT_PREFIX,
6593
7106
  SUBLEVEL_OPTIONS
6594
7107
  );
6595
- const item = await rootSublevel.get(itemKey);
7108
+ const item = await rootSublevel.get(normalizedPath);
6596
7109
  if (item) {
6597
7110
  const folderTreeBuilder = new FolderTreeBuilder();
6598
7111
  const folderKey = folderTreeBuilder.update(
@@ -6600,16 +7113,25 @@ var Database = class {
6600
7113
  collection.path || ""
6601
7114
  );
6602
7115
  await this.contentLevel.batch([
7116
+ ...makeRefOpsForDocument(
7117
+ normalizedPath,
7118
+ collection.name,
7119
+ collectionReferences,
7120
+ item,
7121
+ "del",
7122
+ level
7123
+ ),
6603
7124
  ...makeIndexOpsForDocument(
6604
- filepath,
7125
+ normalizedPath,
6605
7126
  collection.name,
6606
7127
  collectionIndexDefinitions,
6607
7128
  item,
6608
7129
  "del",
6609
7130
  level
6610
7131
  ),
7132
+ // folder indices
6611
7133
  ...makeIndexOpsForDocument(
6612
- filepath,
7134
+ normalizedPath,
6613
7135
  `${collection.name}_${folderKey}`,
6614
7136
  collectionIndexDefinitions,
6615
7137
  item,
@@ -6618,17 +7140,17 @@ var Database = class {
6618
7140
  ),
6619
7141
  {
6620
7142
  type: "del",
6621
- key: itemKey,
7143
+ key: normalizedPath,
6622
7144
  sublevel: rootSublevel
6623
7145
  }
6624
7146
  ]);
6625
7147
  }
6626
7148
  if (!(collection == null ? void 0 : collection.isDetached)) {
6627
7149
  if (this.bridge) {
6628
- await this.bridge.delete((0, import_schema_tools3.normalizePath)(filepath));
7150
+ await this.bridge.delete(normalizedPath);
6629
7151
  }
6630
7152
  try {
6631
- await this.onDelete((0, import_schema_tools3.normalizePath)(filepath));
7153
+ await this.onDelete(normalizedPath);
6632
7154
  } catch (e) {
6633
7155
  throw new import_graphql6.GraphQLError(
6634
7156
  `Error running onDelete hook for ${filepath}: ${e}`,
@@ -6676,7 +7198,13 @@ var Database = class {
6676
7198
  );
6677
7199
  }
6678
7200
  } else {
6679
- await _indexContent(this, level, contentPaths, enqueueOps, collection);
7201
+ await _indexContent(
7202
+ this,
7203
+ level,
7204
+ contentPaths,
7205
+ enqueueOps,
7206
+ collection
7207
+ );
6680
7208
  }
6681
7209
  }
6682
7210
  );
@@ -6762,6 +7290,9 @@ var Database = class {
6762
7290
  info: templateInfo
6763
7291
  };
6764
7292
  }
7293
+ /**
7294
+ * Clears the internal cache of the tinaSchema and the lookup file. This allows the state to be reset
7295
+ */
6765
7296
  clearCache() {
6766
7297
  this.tinaSchema = null;
6767
7298
  this._lookup = null;
@@ -6813,6 +7344,7 @@ var hashPasswordValues = async (data, passwordFields) => Promise.all(
6813
7344
  );
6814
7345
  var isGitKeep = (filepath, collection) => filepath.endsWith(`.gitkeep.${(collection == null ? void 0 : collection.format) || "md"}`);
6815
7346
  var _indexContent = async (database, level, documentPaths, enqueueOps, collection, passwordFields) => {
7347
+ var _a;
6816
7348
  let collectionIndexDefinitions;
6817
7349
  let collectionPath;
6818
7350
  if (collection) {
@@ -6823,6 +7355,7 @@ var _indexContent = async (database, level, documentPaths, enqueueOps, collectio
6823
7355
  }
6824
7356
  collectionPath = collection.path;
6825
7357
  }
7358
+ const collectionReferences = (_a = await database.getCollectionReferences()) == null ? void 0 : _a[collection == null ? void 0 : collection.name];
6826
7359
  const tinaSchema = await database.getSchema();
6827
7360
  let templateInfo = null;
6828
7361
  if (collection) {
@@ -6843,13 +7376,60 @@ var _indexContent = async (database, level, documentPaths, enqueueOps, collectio
6843
7376
  if (passwordFields == null ? void 0 : passwordFields.length) {
6844
7377
  await hashPasswordValues(aliasedData, passwordFields);
6845
7378
  }
6846
- const normalizedPath = (0, import_schema_tools3.normalizePath)(filepath);
7379
+ const normalizedPath = (0, import_schema_tools4.normalizePath)(filepath);
7380
+ const rootSublevel = level.sublevel(
7381
+ CONTENT_ROOT_PREFIX,
7382
+ SUBLEVEL_OPTIONS
7383
+ );
6847
7384
  const folderKey = folderTreeBuilder.update(
6848
7385
  normalizedPath,
6849
7386
  collectionPath || ""
6850
7387
  );
7388
+ const item = await rootSublevel.get(normalizedPath);
7389
+ if (item) {
7390
+ await database.contentLevel.batch([
7391
+ ...makeRefOpsForDocument(
7392
+ normalizedPath,
7393
+ collection == null ? void 0 : collection.name,
7394
+ collectionReferences,
7395
+ item,
7396
+ "del",
7397
+ level
7398
+ ),
7399
+ ...makeIndexOpsForDocument(
7400
+ normalizedPath,
7401
+ collection.name,
7402
+ collectionIndexDefinitions,
7403
+ item,
7404
+ "del",
7405
+ level
7406
+ ),
7407
+ // folder indices
7408
+ ...makeIndexOpsForDocument(
7409
+ normalizedPath,
7410
+ `${collection.name}_${folderKey}`,
7411
+ collectionIndexDefinitions,
7412
+ item,
7413
+ "del",
7414
+ level
7415
+ ),
7416
+ {
7417
+ type: "del",
7418
+ key: normalizedPath,
7419
+ sublevel: rootSublevel
7420
+ }
7421
+ ]);
7422
+ }
6851
7423
  if (!isGitKeep(filepath, collection)) {
6852
7424
  await enqueueOps([
7425
+ ...makeRefOpsForDocument(
7426
+ normalizedPath,
7427
+ collection == null ? void 0 : collection.name,
7428
+ collectionReferences,
7429
+ aliasedData,
7430
+ "put",
7431
+ level
7432
+ ),
6853
7433
  ...makeIndexOpsForDocument(
6854
7434
  normalizedPath,
6855
7435
  collection == null ? void 0 : collection.name,
@@ -6858,6 +7438,7 @@ var _indexContent = async (database, level, documentPaths, enqueueOps, collectio
6858
7438
  "put",
6859
7439
  level
6860
7440
  ),
7441
+ // folder indexes
6861
7442
  ...makeIndexOpsForDocument(
6862
7443
  normalizedPath,
6863
7444
  `${collection == null ? void 0 : collection.name}_${folderKey}`,
@@ -6899,6 +7480,7 @@ var _indexContent = async (database, level, documentPaths, enqueueOps, collectio
6899
7480
  }
6900
7481
  };
6901
7482
  var _deleteIndexContent = async (database, documentPaths, enqueueOps, collection) => {
7483
+ var _a;
6902
7484
  if (!documentPaths.length) {
6903
7485
  return;
6904
7486
  }
@@ -6912,6 +7494,7 @@ var _deleteIndexContent = async (database, documentPaths, enqueueOps, collection
6912
7494
  throw new Error(`No indexDefinitions for collection ${collection.name}`);
6913
7495
  }
6914
7496
  }
7497
+ const collectionReferences = (_a = await database.getCollectionReferences()) == null ? void 0 : _a[collection == null ? void 0 : collection.name];
6915
7498
  const tinaSchema = await database.getSchema();
6916
7499
  let templateInfo = null;
6917
7500
  if (collection) {
@@ -6923,7 +7506,7 @@ var _deleteIndexContent = async (database, documentPaths, enqueueOps, collection
6923
7506
  );
6924
7507
  const folderTreeBuilder = new FolderTreeBuilder();
6925
7508
  await sequential(documentPaths, async (filepath) => {
6926
- const itemKey = (0, import_schema_tools3.normalizePath)(filepath);
7509
+ const itemKey = (0, import_schema_tools4.normalizePath)(filepath);
6927
7510
  const item = await rootLevel.get(itemKey);
6928
7511
  if (item) {
6929
7512
  const folderKey = folderTreeBuilder.update(
@@ -6935,6 +7518,14 @@ var _deleteIndexContent = async (database, documentPaths, enqueueOps, collection
6935
7518
  item
6936
7519
  ) : item;
6937
7520
  await enqueueOps([
7521
+ ...makeRefOpsForDocument(
7522
+ itemKey,
7523
+ collection == null ? void 0 : collection.name,
7524
+ collectionReferences,
7525
+ aliasedData,
7526
+ "del",
7527
+ database.contentLevel
7528
+ ),
6938
7529
  ...makeIndexOpsForDocument(
6939
7530
  itemKey,
6940
7531
  collection.name,
@@ -6943,6 +7534,7 @@ var _deleteIndexContent = async (database, documentPaths, enqueueOps, collection
6943
7534
  "del",
6944
7535
  database.contentLevel
6945
7536
  ),
7537
+ // folder indexes
6946
7538
  ...makeIndexOpsForDocument(
6947
7539
  itemKey,
6948
7540
  `${collection == null ? void 0 : collection.name}_${folderKey}`,
@@ -7009,14 +7601,14 @@ var getChangedFiles = async ({
7009
7601
  const rootDir = await findGitRoot(dir);
7010
7602
  let pathPrefix = "";
7011
7603
  if (rootDir !== dir) {
7012
- pathPrefix = (0, import_schema_tools3.normalizePath)(dir.substring(rootDir.length + 1));
7604
+ pathPrefix = (0, import_schema_tools4.normalizePath)(dir.substring(rootDir.length + 1));
7013
7605
  }
7014
7606
  await import_isomorphic_git.default.walk({
7015
7607
  fs: fs4,
7016
7608
  dir: rootDir,
7017
7609
  trees: [import_isomorphic_git.default.TREE({ ref: from }), import_isomorphic_git.default.TREE({ ref: to })],
7018
7610
  map: async function(filename, [A, B]) {
7019
- const relativePath = (0, import_schema_tools3.normalizePath)(filename).substring(pathPrefix.length);
7611
+ const relativePath = (0, import_schema_tools4.normalizePath)(filename).substring(pathPrefix.length);
7020
7612
  let matches = false;
7021
7613
  for (const [key, matcher] of Object.entries(pathFilter)) {
7022
7614
  if (relativePath.startsWith(key)) {
@@ -7158,17 +7750,26 @@ var IsomorphicBridge = class {
7158
7750
  getAuthor() {
7159
7751
  return {
7160
7752
  ...this.author,
7161
- timestamp: Math.round(new Date().getTime() / 1e3),
7753
+ timestamp: Math.round((/* @__PURE__ */ new Date()).getTime() / 1e3),
7162
7754
  timezoneOffset: 0
7163
7755
  };
7164
7756
  }
7165
7757
  getCommitter() {
7166
7758
  return {
7167
7759
  ...this.committer,
7168
- timestamp: Math.round(new Date().getTime() / 1e3),
7760
+ timestamp: Math.round((/* @__PURE__ */ new Date()).getTime() / 1e3),
7169
7761
  timezoneOffset: 0
7170
7762
  };
7171
7763
  }
7764
+ /**
7765
+ * Recursively populate paths matching `pattern` for the given `entry`
7766
+ *
7767
+ * @param pattern - pattern to filter paths by
7768
+ * @param entry - TreeEntry to start building list from
7769
+ * @param path - base path
7770
+ * @param results
7771
+ * @private
7772
+ */
7172
7773
  async listEntries({
7173
7774
  pattern,
7174
7775
  entry,
@@ -7201,6 +7802,15 @@ var IsomorphicBridge = class {
7201
7802
  });
7202
7803
  }
7203
7804
  }
7805
+ /**
7806
+ * For the specified path, returns an object with an array containing the parts of the path (pathParts)
7807
+ * and an array containing the WalkerEntry objects for the path parts (pathEntries). Any null elements in the
7808
+ * pathEntries are placeholders for non-existent entries.
7809
+ *
7810
+ * @param path - path being resolved
7811
+ * @param ref - ref to resolve path entries for
7812
+ * @private
7813
+ */
7204
7814
  async resolvePathEntries(path7, ref) {
7205
7815
  let pathParts = path7.split("/");
7206
7816
  const result = await import_isomorphic_git2.default.walk({
@@ -7231,6 +7841,17 @@ var IsomorphicBridge = class {
7231
7841
  }
7232
7842
  return { pathParts, pathEntries };
7233
7843
  }
7844
+ /**
7845
+ * Updates tree entry and associated parent tree entries
7846
+ *
7847
+ * @param existingOid - the existing OID
7848
+ * @param updatedOid - the updated OID
7849
+ * @param path - the path of the entry being updated
7850
+ * @param type - the type of the entry being updated (blob or tree)
7851
+ * @param pathEntries - parent path entries
7852
+ * @param pathParts - parent path parts
7853
+ * @private
7854
+ */
7234
7855
  async updateTreeHierarchy(existingOid, updatedOid, path7, type, pathEntries, pathParts) {
7235
7856
  const lastIdx = pathEntries.length - 1;
7236
7857
  const parentEntry = pathEntries[lastIdx];
@@ -7286,6 +7907,13 @@ var IsomorphicBridge = class {
7286
7907
  );
7287
7908
  }
7288
7909
  }
7910
+ /**
7911
+ * Creates a commit for the specified tree and updates the specified ref to point to the commit
7912
+ *
7913
+ * @param treeSha - sha of the new tree
7914
+ * @param ref - the ref that should be updated
7915
+ * @private
7916
+ */
7289
7917
  async commitTree(treeSha, ref) {
7290
7918
  const commitSha = await import_isomorphic_git2.default.writeCommit({
7291
7919
  ...this.isomorphicConfig,
@@ -7298,6 +7926,7 @@ var IsomorphicBridge = class {
7298
7926
  })
7299
7927
  ],
7300
7928
  message: this.commitMessage,
7929
+ // TODO these should be configurable
7301
7930
  author: this.getAuthor(),
7302
7931
  committer: this.getCommitter()
7303
7932
  }
@@ -7536,5 +8165,5 @@ var buildSchema = async (config, flags) => {
7536
8165
  transformDocument,
7537
8166
  transformDocumentIntoPayload
7538
8167
  });
7539
- //! Replaces _.flattenDeep()
7540
8168
  //! Replaces _.get()
8169
+ //! Replaces _.flattenDeep()