@tinacms/graphql 4.0.0 → 4.0.1
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/database/datalayer.d.ts +2 -2
- package/dist/index.js +280 -186
- package/dist/references/visit.d.ts +25 -0
- package/dist/resolver/index.d.ts +8 -0
- package/package.json +6 -6
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
*/
|
|
4
4
|
import { BatchOp, Level } from './level';
|
|
5
|
-
import type { Collection } from '@tinacms/schema-tools';
|
|
5
|
+
import type { Collection, TinaSchema } from '@tinacms/schema-tools';
|
|
6
6
|
export declare enum OP {
|
|
7
7
|
EQ = "eq",
|
|
8
8
|
GT = "gt",
|
|
@@ -77,7 +77,7 @@ export declare class FolderTreeBuilder {
|
|
|
77
77
|
}
|
|
78
78
|
export declare const makeFolderOpsForCollection: <T extends object>(folderTree: FolderTree, collection: Collection<true>, indexDefinitions: Record<string, IndexDefinition>, opType: "put" | "del", level: Level, escapeStr?: StringEscaper) => BatchOp[];
|
|
79
79
|
export declare const makeIndexOpsForDocument: <T extends object>(filepath: string, collection: string | undefined, indexDefinitions: Record<string, IndexDefinition>, data: T, opType: "put" | "del", level: Level, escapeStr?: StringEscaper) => BatchOp[];
|
|
80
|
-
export declare const makeRefOpsForDocument: <T extends object>(filepath: string,
|
|
80
|
+
export declare const makeRefOpsForDocument: <T extends object>(filepath: string, collectionName: string | undefined, tinaSchema: TinaSchema | undefined, data: T, opType: "put" | "del", level: Level) => BatchOp[];
|
|
81
81
|
export declare const makeStringEscaper: (regex: RegExp, replacement: string) => StringEscaper;
|
|
82
82
|
export declare const stringEscaper: StringEscaper;
|
|
83
83
|
export {};
|
package/dist/index.js
CHANGED
|
@@ -3058,7 +3058,7 @@ var assertCheckboxGroupIsList = (field) => {
|
|
|
3058
3058
|
var package_default = {
|
|
3059
3059
|
name: "@tinacms/graphql",
|
|
3060
3060
|
type: "module",
|
|
3061
|
-
version: "4.0.
|
|
3061
|
+
version: "4.0.1",
|
|
3062
3062
|
main: "dist/index.js",
|
|
3063
3063
|
module: "./dist/index.js",
|
|
3064
3064
|
files: [
|
|
@@ -3101,7 +3101,7 @@ var package_default = {
|
|
|
3101
3101
|
"gray-matter": "catalog:",
|
|
3102
3102
|
"isomorphic-git": "catalog:",
|
|
3103
3103
|
"js-sha1": "catalog:",
|
|
3104
|
-
"js-yaml": "^3.15.
|
|
3104
|
+
"js-yaml": "^3.15.2",
|
|
3105
3105
|
"jsonpath-plus": "catalog:",
|
|
3106
3106
|
"many-level": "catalog:",
|
|
3107
3107
|
micromatch: "catalog:",
|
|
@@ -3355,6 +3355,129 @@ import { JSONPath as JSONPath2 } from "jsonpath-plus";
|
|
|
3355
3355
|
// src/mdx/index.ts
|
|
3356
3356
|
import { parseMDX, serializeMDX } from "@tinacms/mdx";
|
|
3357
3357
|
|
|
3358
|
+
// src/references/visit.ts
|
|
3359
|
+
var MDX_SEGMENT = { mdx: true };
|
|
3360
|
+
var encodeLocator = (locator) => JSON.stringify(locator);
|
|
3361
|
+
var isRecord = (value) => typeof value === "object" && value !== null;
|
|
3362
|
+
var visitReferences = (data, collectable, tinaSchema, visit) => {
|
|
3363
|
+
const visitCollectable = (collectableHere, value, locator) => {
|
|
3364
|
+
if (!isRecord(value)) {
|
|
3365
|
+
return false;
|
|
3366
|
+
}
|
|
3367
|
+
let fields;
|
|
3368
|
+
try {
|
|
3369
|
+
fields = tinaSchema.getTemplateForData({
|
|
3370
|
+
data: value,
|
|
3371
|
+
collection: collectableHere
|
|
3372
|
+
})?.fields;
|
|
3373
|
+
} catch {
|
|
3374
|
+
return false;
|
|
3375
|
+
}
|
|
3376
|
+
let replaced = false;
|
|
3377
|
+
for (const field of fields ?? []) {
|
|
3378
|
+
replaced = visitField(field, value, locator) || replaced;
|
|
3379
|
+
}
|
|
3380
|
+
return replaced;
|
|
3381
|
+
};
|
|
3382
|
+
const visitField = (field, parent, locator) => {
|
|
3383
|
+
const key = field.type === "rich-text" && field.isBody && "$_body" in parent ? "$_body" : field.name;
|
|
3384
|
+
const value = parent[key];
|
|
3385
|
+
if (value === void 0 || value === null) {
|
|
3386
|
+
return false;
|
|
3387
|
+
}
|
|
3388
|
+
const at = [...locator, field.name];
|
|
3389
|
+
let replaced = false;
|
|
3390
|
+
if (field.type === "reference") {
|
|
3391
|
+
if (field.list && Array.isArray(value)) {
|
|
3392
|
+
for (const [index, item] of value.entries()) {
|
|
3393
|
+
if (typeof item !== "string" || item.length === 0) {
|
|
3394
|
+
continue;
|
|
3395
|
+
}
|
|
3396
|
+
visit({
|
|
3397
|
+
value: item,
|
|
3398
|
+
collections: field.collections ?? [],
|
|
3399
|
+
locator: [...at, index],
|
|
3400
|
+
replace: (next) => {
|
|
3401
|
+
value[index] = next;
|
|
3402
|
+
replaced = true;
|
|
3403
|
+
}
|
|
3404
|
+
});
|
|
3405
|
+
}
|
|
3406
|
+
return replaced;
|
|
3407
|
+
} else if (typeof value !== "string" || value.length === 0) {
|
|
3408
|
+
return false;
|
|
3409
|
+
}
|
|
3410
|
+
visit({
|
|
3411
|
+
value,
|
|
3412
|
+
collections: field.collections ?? [],
|
|
3413
|
+
locator: at,
|
|
3414
|
+
replace: (next) => {
|
|
3415
|
+
parent[field.name] = next;
|
|
3416
|
+
replaced = true;
|
|
3417
|
+
}
|
|
3418
|
+
});
|
|
3419
|
+
return replaced;
|
|
3420
|
+
} else if (field.type === "object") {
|
|
3421
|
+
if (field.list && Array.isArray(value)) {
|
|
3422
|
+
for (const [index, item] of value.entries()) {
|
|
3423
|
+
replaced = visitCollectable(field, item, [...at, index]) || replaced;
|
|
3424
|
+
}
|
|
3425
|
+
return replaced;
|
|
3426
|
+
}
|
|
3427
|
+
return visitCollectable(field, value, at);
|
|
3428
|
+
} else if (field.type === "rich-text") {
|
|
3429
|
+
return visitRichText(field, parent, key, at);
|
|
3430
|
+
}
|
|
3431
|
+
return false;
|
|
3432
|
+
};
|
|
3433
|
+
const visitRichText = (field, parent, key, at) => {
|
|
3434
|
+
const stored = parent[key];
|
|
3435
|
+
const storedIsText = typeof stored === "string";
|
|
3436
|
+
if (!storedIsText && !isRecord(stored)) {
|
|
3437
|
+
return false;
|
|
3438
|
+
}
|
|
3439
|
+
let tree;
|
|
3440
|
+
if (storedIsText) {
|
|
3441
|
+
try {
|
|
3442
|
+
tree = parseMDX(stored, field, (value) => value);
|
|
3443
|
+
} catch {
|
|
3444
|
+
return false;
|
|
3445
|
+
}
|
|
3446
|
+
} else {
|
|
3447
|
+
tree = stored;
|
|
3448
|
+
}
|
|
3449
|
+
const replaced = visitNodes2(tree?.children, field, [...at, MDX_SEGMENT]);
|
|
3450
|
+
if (replaced && storedIsText) {
|
|
3451
|
+
parent[key] = serializeMDX(tree, field, (value) => value);
|
|
3452
|
+
}
|
|
3453
|
+
return replaced;
|
|
3454
|
+
};
|
|
3455
|
+
const visitNodes2 = (nodes, field, at) => {
|
|
3456
|
+
if (!Array.isArray(nodes)) {
|
|
3457
|
+
return false;
|
|
3458
|
+
}
|
|
3459
|
+
const templates = field.templates ?? [];
|
|
3460
|
+
let replaced = false;
|
|
3461
|
+
for (const [index, node] of nodes.entries()) {
|
|
3462
|
+
if (!isRecord(node)) {
|
|
3463
|
+
continue;
|
|
3464
|
+
}
|
|
3465
|
+
const here = [...at, index];
|
|
3466
|
+
if (typeof node.name === "string" && (node.type === "mdxJsxFlowElement" || node.type === "mdxJsxTextElement") && isRecord(node.props)) {
|
|
3467
|
+
const template = templates.find(
|
|
3468
|
+
(candidate) => lastItem(candidate.namespace) === node.name
|
|
3469
|
+
);
|
|
3470
|
+
for (const templateField of template?.fields ?? []) {
|
|
3471
|
+
replaced = visitField(templateField, node.props, [...here, "props"]) || replaced;
|
|
3472
|
+
}
|
|
3473
|
+
}
|
|
3474
|
+
replaced = visitNodes2(node.children, field, [...here, "children"]) || replaced;
|
|
3475
|
+
}
|
|
3476
|
+
return replaced;
|
|
3477
|
+
};
|
|
3478
|
+
return visitCollectable(collectable, data, []);
|
|
3479
|
+
};
|
|
3480
|
+
|
|
3358
3481
|
// src/resolver/index.ts
|
|
3359
3482
|
import {
|
|
3360
3483
|
ERR_ALREADY_EXISTS,
|
|
@@ -4431,54 +4554,41 @@ var makeIndexOpsForDocument = (filepath, collection, indexDefinitions, data, opT
|
|
|
4431
4554
|
}
|
|
4432
4555
|
return result;
|
|
4433
4556
|
};
|
|
4434
|
-
var makeRefOpsForDocument = (filepath,
|
|
4557
|
+
var makeRefOpsForDocument = (filepath, collectionName, tinaSchema, data, opType, level) => {
|
|
4435
4558
|
const result = [];
|
|
4436
|
-
if (
|
|
4437
|
-
|
|
4438
|
-
|
|
4439
|
-
|
|
4440
|
-
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
|
|
4448
|
-
|
|
4449
|
-
|
|
4450
|
-
|
|
4451
|
-
|
|
4452
|
-
|
|
4453
|
-
|
|
4454
|
-
|
|
4455
|
-
|
|
4456
|
-
}
|
|
4457
|
-
if (references2[r]) {
|
|
4458
|
-
references2[r].push(path9);
|
|
4459
|
-
} else {
|
|
4460
|
-
references2[r] = [path9];
|
|
4461
|
-
}
|
|
4462
|
-
}
|
|
4463
|
-
} else {
|
|
4464
|
-
if (references2[ref]) {
|
|
4465
|
-
references2[ref].push(path9);
|
|
4466
|
-
} else {
|
|
4467
|
-
references2[ref] = [path9];
|
|
4468
|
-
}
|
|
4469
|
-
}
|
|
4470
|
-
}
|
|
4471
|
-
for (const ref of Object.keys(references2)) {
|
|
4472
|
-
for (const path9 of references2[ref]) {
|
|
4473
|
-
result.push({
|
|
4474
|
-
type: opType,
|
|
4475
|
-
key: `${ref}${INDEX_KEY_FIELD_SEPARATOR}${path9}${INDEX_KEY_FIELD_SEPARATOR}${filepath}`,
|
|
4476
|
-
sublevel: refSublevel,
|
|
4477
|
-
value: opType === "put" ? {} : void 0
|
|
4478
|
-
});
|
|
4479
|
-
}
|
|
4559
|
+
if (!collectionName || !tinaSchema) {
|
|
4560
|
+
return result;
|
|
4561
|
+
}
|
|
4562
|
+
let collection;
|
|
4563
|
+
try {
|
|
4564
|
+
collection = tinaSchema.getCollection(collectionName);
|
|
4565
|
+
} catch {
|
|
4566
|
+
return result;
|
|
4567
|
+
}
|
|
4568
|
+
const byCollection = /* @__PURE__ */ new Map();
|
|
4569
|
+
visitReferences(
|
|
4570
|
+
data,
|
|
4571
|
+
collection,
|
|
4572
|
+
tinaSchema,
|
|
4573
|
+
({ value, collections, locator }) => {
|
|
4574
|
+
const encoded = encodeLocator(locator);
|
|
4575
|
+
for (const target of collections) {
|
|
4576
|
+
const entries = byCollection.get(target) ?? [];
|
|
4577
|
+
entries.push({ ref: value, locator: encoded });
|
|
4578
|
+
byCollection.set(target, entries);
|
|
4480
4579
|
}
|
|
4481
4580
|
}
|
|
4581
|
+
);
|
|
4582
|
+
for (const [target, entries] of byCollection) {
|
|
4583
|
+
const refSublevel = level.sublevel(target, SUBLEVEL_OPTIONS).sublevel(REFS_COLLECTIONS_SORT_KEY, SUBLEVEL_OPTIONS);
|
|
4584
|
+
for (const { ref, locator } of entries) {
|
|
4585
|
+
result.push({
|
|
4586
|
+
type: opType,
|
|
4587
|
+
key: `${ref}${INDEX_KEY_FIELD_SEPARATOR}${locator}${INDEX_KEY_FIELD_SEPARATOR}${filepath}`,
|
|
4588
|
+
sublevel: refSublevel,
|
|
4589
|
+
value: opType === "put" ? {} : void 0
|
|
4590
|
+
});
|
|
4591
|
+
}
|
|
4482
4592
|
}
|
|
4483
4593
|
return result;
|
|
4484
4594
|
};
|
|
@@ -5130,34 +5240,6 @@ var transformDocumentIntoPayload = async (fullPath, rawData, tinaSchema, config,
|
|
|
5130
5240
|
throw e;
|
|
5131
5241
|
}
|
|
5132
5242
|
};
|
|
5133
|
-
var updateObjectWithJsonPath = (obj, path9, oldValue, newValue) => {
|
|
5134
|
-
let updated = false;
|
|
5135
|
-
if (!path9.includes(".") && !path9.includes("[")) {
|
|
5136
|
-
if (path9 in obj && obj[path9] === oldValue) {
|
|
5137
|
-
obj[path9] = newValue;
|
|
5138
|
-
updated = true;
|
|
5139
|
-
}
|
|
5140
|
-
return { object: obj, updated };
|
|
5141
|
-
}
|
|
5142
|
-
const parentPath = path9.replace(/\.[^.\[\]]+$/, "");
|
|
5143
|
-
const keyToUpdate = path9.match(/[^.\[\]]+$/)[0];
|
|
5144
|
-
const parents = JSONPath2({
|
|
5145
|
-
path: parentPath,
|
|
5146
|
-
json: obj,
|
|
5147
|
-
resultType: "value"
|
|
5148
|
-
});
|
|
5149
|
-
if (parents.length > 0) {
|
|
5150
|
-
parents.forEach((parent) => {
|
|
5151
|
-
if (parent && typeof parent === "object" && keyToUpdate in parent) {
|
|
5152
|
-
if (parent[keyToUpdate] === oldValue) {
|
|
5153
|
-
parent[keyToUpdate] = newValue;
|
|
5154
|
-
updated = true;
|
|
5155
|
-
}
|
|
5156
|
-
}
|
|
5157
|
-
});
|
|
5158
|
-
}
|
|
5159
|
-
return { object: obj, updated };
|
|
5160
|
-
};
|
|
5161
5243
|
var Resolver = class _Resolver {
|
|
5162
5244
|
constructor(init) {
|
|
5163
5245
|
this.init = init;
|
|
@@ -5725,42 +5807,12 @@ var Resolver = class _Resolver {
|
|
|
5725
5807
|
await this.assertReferenceUpdates(realPath, collection);
|
|
5726
5808
|
await this.database.put(newRealPath, doc._rawData, collection.name);
|
|
5727
5809
|
await this.deleteDocument(realPath);
|
|
5728
|
-
|
|
5729
|
-
|
|
5730
|
-
|
|
5731
|
-
|
|
5732
|
-
|
|
5733
|
-
|
|
5734
|
-
const rewriteReferences = async () => {
|
|
5735
|
-
let docWithRef = await this.getRaw(pathToDocWithRef);
|
|
5736
|
-
let hasUpdate = false;
|
|
5737
|
-
for (const path9 of referencePaths) {
|
|
5738
|
-
const { object: object2, updated } = updateObjectWithJsonPath(
|
|
5739
|
-
docWithRef,
|
|
5740
|
-
path9,
|
|
5741
|
-
realPath,
|
|
5742
|
-
newRealPath
|
|
5743
|
-
);
|
|
5744
|
-
docWithRef = object2;
|
|
5745
|
-
hasUpdate = updated || hasUpdate;
|
|
5746
|
-
}
|
|
5747
|
-
if (hasUpdate) {
|
|
5748
|
-
const collectionWithRef = this.tinaSchema.getCollectionByFullPath(pathToDocWithRef);
|
|
5749
|
-
if (!collectionWithRef) {
|
|
5750
|
-
throw new Error(
|
|
5751
|
-
`Unable to find collection for ${pathToDocWithRef}`
|
|
5752
|
-
);
|
|
5753
|
-
}
|
|
5754
|
-
await this.database.put(
|
|
5755
|
-
pathToDocWithRef,
|
|
5756
|
-
docWithRef,
|
|
5757
|
-
collectionWithRef.name
|
|
5758
|
-
);
|
|
5759
|
-
}
|
|
5760
|
-
};
|
|
5761
|
-
await (holdsLock ? rewriteReferences() : this.withAuthCollectionLock(pathToDocWithRef, rewriteReferences));
|
|
5762
|
-
}
|
|
5763
|
-
}
|
|
5810
|
+
await this.rewriteReferences(
|
|
5811
|
+
realPath,
|
|
5812
|
+
newRealPath,
|
|
5813
|
+
collection,
|
|
5814
|
+
this.isAuthCollectionPath(realPath)
|
|
5815
|
+
);
|
|
5764
5816
|
return this.getDocument(newRealPath);
|
|
5765
5817
|
}
|
|
5766
5818
|
if (!newBody) {
|
|
@@ -5824,40 +5876,7 @@ var Resolver = class _Resolver {
|
|
|
5824
5876
|
const doc = await this.getDocument(realPath);
|
|
5825
5877
|
await this.deleteDocument(realPath);
|
|
5826
5878
|
if (hasReferences) {
|
|
5827
|
-
|
|
5828
|
-
for (const [_collection, docsWithRefs] of Object.entries(collRefs)) {
|
|
5829
|
-
for (const [pathToDocWithRef, referencePaths] of Object.entries(
|
|
5830
|
-
docsWithRefs
|
|
5831
|
-
)) {
|
|
5832
|
-
await this.withAuthCollectionLock(pathToDocWithRef, async () => {
|
|
5833
|
-
let refDoc = await this.getRaw(pathToDocWithRef);
|
|
5834
|
-
let hasUpdate = false;
|
|
5835
|
-
for (const path9 of referencePaths) {
|
|
5836
|
-
const { object: object2, updated } = updateObjectWithJsonPath(
|
|
5837
|
-
refDoc,
|
|
5838
|
-
path9,
|
|
5839
|
-
realPath,
|
|
5840
|
-
null
|
|
5841
|
-
);
|
|
5842
|
-
refDoc = object2;
|
|
5843
|
-
hasUpdate = updated || hasUpdate;
|
|
5844
|
-
}
|
|
5845
|
-
if (hasUpdate) {
|
|
5846
|
-
const collectionWithRef = this.tinaSchema.getCollectionByFullPath(pathToDocWithRef);
|
|
5847
|
-
if (!collectionWithRef) {
|
|
5848
|
-
throw new Error(
|
|
5849
|
-
`Unable to find collection for ${pathToDocWithRef}`
|
|
5850
|
-
);
|
|
5851
|
-
}
|
|
5852
|
-
await this.database.put(
|
|
5853
|
-
pathToDocWithRef,
|
|
5854
|
-
refDoc,
|
|
5855
|
-
collectionWithRef.name
|
|
5856
|
-
);
|
|
5857
|
-
}
|
|
5858
|
-
});
|
|
5859
|
-
}
|
|
5860
|
-
}
|
|
5879
|
+
await this.rewriteReferences(realPath, null, collection, false);
|
|
5861
5880
|
}
|
|
5862
5881
|
return doc;
|
|
5863
5882
|
};
|
|
@@ -6215,6 +6234,47 @@ var Resolver = class _Resolver {
|
|
|
6215
6234
|
}
|
|
6216
6235
|
};
|
|
6217
6236
|
};
|
|
6237
|
+
/**
|
|
6238
|
+
* Repoints every reference to `from` at `to`, or clears it when `to` is null.
|
|
6239
|
+
*
|
|
6240
|
+
* Each referring document is re-walked rather than addressed by the locators the index stored,
|
|
6241
|
+
* since a stored path cannot address a reference inside rich text. Only a document the walk
|
|
6242
|
+
* changed is written back.
|
|
6243
|
+
*/
|
|
6244
|
+
rewriteReferences = async (from, to, collection, holdsLock) => {
|
|
6245
|
+
const collRefs = await this.findReferences(from, collection);
|
|
6246
|
+
for (const docsWithRefs of Object.values(collRefs)) {
|
|
6247
|
+
for (const pathToDocWithRef of Object.keys(docsWithRefs)) {
|
|
6248
|
+
const rewrite = async () => {
|
|
6249
|
+
const collectionWithRef = this.tinaSchema.getCollectionByFullPath(pathToDocWithRef);
|
|
6250
|
+
if (!collectionWithRef) {
|
|
6251
|
+
throw new Error(
|
|
6252
|
+
`Unable to find collection for ${pathToDocWithRef}`
|
|
6253
|
+
);
|
|
6254
|
+
}
|
|
6255
|
+
const docWithRef = await this.getRaw(pathToDocWithRef);
|
|
6256
|
+
const changed = visitReferences(
|
|
6257
|
+
docWithRef,
|
|
6258
|
+
collectionWithRef,
|
|
6259
|
+
this.tinaSchema,
|
|
6260
|
+
(reference) => {
|
|
6261
|
+
if (reference.value === from) {
|
|
6262
|
+
reference.replace(to);
|
|
6263
|
+
}
|
|
6264
|
+
}
|
|
6265
|
+
);
|
|
6266
|
+
if (changed) {
|
|
6267
|
+
await this.database.put(
|
|
6268
|
+
pathToDocWithRef,
|
|
6269
|
+
docWithRef,
|
|
6270
|
+
collectionWithRef.name
|
|
6271
|
+
);
|
|
6272
|
+
}
|
|
6273
|
+
};
|
|
6274
|
+
await (holdsLock ? rewrite() : this.withAuthCollectionLock(pathToDocWithRef, rewrite));
|
|
6275
|
+
}
|
|
6276
|
+
}
|
|
6277
|
+
};
|
|
6218
6278
|
/**
|
|
6219
6279
|
* Checks if a document has references to it
|
|
6220
6280
|
* @param id The id of the document to check for references
|
|
@@ -6225,6 +6285,8 @@ var Resolver = class _Resolver {
|
|
|
6225
6285
|
let count = 0;
|
|
6226
6286
|
await this.database.query(
|
|
6227
6287
|
{
|
|
6288
|
+
// One key answers a boolean; the default page is 50.
|
|
6289
|
+
first: 1,
|
|
6228
6290
|
collection: c.name,
|
|
6229
6291
|
filterChain: makeFilterChain({
|
|
6230
6292
|
conditions: [
|
|
@@ -6260,6 +6322,9 @@ var Resolver = class _Resolver {
|
|
|
6260
6322
|
const references = {};
|
|
6261
6323
|
await this.database.query(
|
|
6262
6324
|
{
|
|
6325
|
+
// Every reference, not the default page of 50, which otherwise caps how many a rename or
|
|
6326
|
+
// delete updates.
|
|
6327
|
+
first: -1,
|
|
6263
6328
|
collection: c.name,
|
|
6264
6329
|
filterChain: makeFilterChain({
|
|
6265
6330
|
conditions: [
|
|
@@ -6856,6 +6921,8 @@ var handleCollectionField = (info, args, resolver) => {
|
|
|
6856
6921
|
import { ManyLevelGuest } from "many-level";
|
|
6857
6922
|
import { pipeline } from "readable-stream";
|
|
6858
6923
|
import { connect } from "net";
|
|
6924
|
+
var CONNECT_RETRIES = 50;
|
|
6925
|
+
var CONNECT_RETRY_DELAY_MS = 100;
|
|
6859
6926
|
var TinaLevelClient = class extends ManyLevelGuest {
|
|
6860
6927
|
port;
|
|
6861
6928
|
_connected = false;
|
|
@@ -6865,10 +6932,30 @@ var TinaLevelClient = class extends ManyLevelGuest {
|
|
|
6865
6932
|
}
|
|
6866
6933
|
openConnection() {
|
|
6867
6934
|
if (this._connected) return;
|
|
6868
|
-
const
|
|
6869
|
-
|
|
6870
|
-
|
|
6871
|
-
|
|
6935
|
+
const rpcStream = this.createRpcStream();
|
|
6936
|
+
const tryConnect = (attempt) => {
|
|
6937
|
+
const socket = connect(this.port);
|
|
6938
|
+
const onConnectError = (err) => {
|
|
6939
|
+
socket.destroy();
|
|
6940
|
+
if (attempt < CONNECT_RETRIES) {
|
|
6941
|
+
setTimeout(() => tryConnect(attempt + 1), CONNECT_RETRY_DELAY_MS);
|
|
6942
|
+
} else {
|
|
6943
|
+
console.error(
|
|
6944
|
+
`TinaLevelClient: could not connect to the datalayer server on port ${this.port} after ${attempt + 1} attempts (${err.message}).`
|
|
6945
|
+
);
|
|
6946
|
+
rpcStream.destroy(err);
|
|
6947
|
+
this._connected = false;
|
|
6948
|
+
}
|
|
6949
|
+
};
|
|
6950
|
+
socket.once("error", onConnectError);
|
|
6951
|
+
socket.once("connect", () => {
|
|
6952
|
+
socket.removeListener("error", onConnectError);
|
|
6953
|
+
pipeline(socket, rpcStream, socket, () => {
|
|
6954
|
+
this._connected = false;
|
|
6955
|
+
});
|
|
6956
|
+
});
|
|
6957
|
+
};
|
|
6958
|
+
tryConnect(0);
|
|
6872
6959
|
this._connected = true;
|
|
6873
6960
|
}
|
|
6874
6961
|
};
|
|
@@ -7088,7 +7175,7 @@ var Database = class {
|
|
|
7088
7175
|
);
|
|
7089
7176
|
const indexDefinitions = await this.getIndexDefinitions(this.contentLevel);
|
|
7090
7177
|
const collectionIndexDefinitions = indexDefinitions?.[collection.name];
|
|
7091
|
-
const
|
|
7178
|
+
const referenceSchema = await this.getSchema();
|
|
7092
7179
|
const normalizedPath = normalizePath(filepath);
|
|
7093
7180
|
if (!collection?.isDetached) {
|
|
7094
7181
|
if (this.bridge) {
|
|
@@ -7120,7 +7207,7 @@ var Database = class {
|
|
|
7120
7207
|
...makeRefOpsForDocument(
|
|
7121
7208
|
normalizedPath,
|
|
7122
7209
|
collection?.name,
|
|
7123
|
-
|
|
7210
|
+
referenceSchema,
|
|
7124
7211
|
dataFields,
|
|
7125
7212
|
"put",
|
|
7126
7213
|
level
|
|
@@ -7151,7 +7238,7 @@ var Database = class {
|
|
|
7151
7238
|
...makeRefOpsForDocument(
|
|
7152
7239
|
normalizedPath,
|
|
7153
7240
|
collection?.name,
|
|
7154
|
-
|
|
7241
|
+
referenceSchema,
|
|
7155
7242
|
existingItem,
|
|
7156
7243
|
"del",
|
|
7157
7244
|
level
|
|
@@ -7203,7 +7290,7 @@ var Database = class {
|
|
|
7203
7290
|
);
|
|
7204
7291
|
collectionIndexDefinitions = indexDefinitions?.[collectionName];
|
|
7205
7292
|
}
|
|
7206
|
-
const
|
|
7293
|
+
const referenceSchema = await this.getSchema();
|
|
7207
7294
|
const normalizedPath = normalizePath(filepath);
|
|
7208
7295
|
const dataFields = await this.formatBodyOnPayload(filepath, data);
|
|
7209
7296
|
const collection = await this.collectionForPath(filepath);
|
|
@@ -7257,7 +7344,7 @@ var Database = class {
|
|
|
7257
7344
|
...makeRefOpsForDocument(
|
|
7258
7345
|
normalizedPath,
|
|
7259
7346
|
collectionName,
|
|
7260
|
-
|
|
7347
|
+
referenceSchema,
|
|
7261
7348
|
dataFields,
|
|
7262
7349
|
"put",
|
|
7263
7350
|
level
|
|
@@ -7288,7 +7375,7 @@ var Database = class {
|
|
|
7288
7375
|
...makeRefOpsForDocument(
|
|
7289
7376
|
normalizedPath,
|
|
7290
7377
|
collectionName,
|
|
7291
|
-
|
|
7378
|
+
referenceSchema,
|
|
7292
7379
|
existingItem,
|
|
7293
7380
|
"del",
|
|
7294
7381
|
level
|
|
@@ -7714,32 +7801,41 @@ var Database = class {
|
|
|
7714
7801
|
endKey = key || "";
|
|
7715
7802
|
edges = [...edges, { cursor: key, path: filepath, value: itemRecord }];
|
|
7716
7803
|
}
|
|
7717
|
-
|
|
7718
|
-
edges
|
|
7719
|
-
|
|
7720
|
-
|
|
7721
|
-
|
|
7722
|
-
|
|
7723
|
-
|
|
7724
|
-
|
|
7725
|
-
|
|
7726
|
-
|
|
7727
|
-
|
|
7728
|
-
|
|
7729
|
-
|
|
7730
|
-
|
|
7731
|
-
|
|
7732
|
-
console.
|
|
7733
|
-
|
|
7734
|
-
|
|
7735
|
-
|
|
7736
|
-
file: path9,
|
|
7737
|
-
collection: collection.name
|
|
7738
|
-
});
|
|
7739
|
-
}
|
|
7740
|
-
throw error;
|
|
7804
|
+
const hydratedEdges = await sequential(
|
|
7805
|
+
edges,
|
|
7806
|
+
async ({
|
|
7807
|
+
cursor,
|
|
7808
|
+
path: path9,
|
|
7809
|
+
value
|
|
7810
|
+
}) => {
|
|
7811
|
+
try {
|
|
7812
|
+
const node = await hydrator(path9, value);
|
|
7813
|
+
return {
|
|
7814
|
+
node,
|
|
7815
|
+
cursor: btoa(cursor)
|
|
7816
|
+
};
|
|
7817
|
+
} catch (error) {
|
|
7818
|
+
if (error instanceof NotFoundError) {
|
|
7819
|
+
console.warn(
|
|
7820
|
+
`Skipping ${path9} in collection ${collection.name}: its index entry has no record. Reindex to remove it.`
|
|
7821
|
+
);
|
|
7822
|
+
return null;
|
|
7741
7823
|
}
|
|
7824
|
+
console.log(error);
|
|
7825
|
+
if (error instanceof Error && (!path9.includes(".tina/__generated__/_graphql.json") || !path9.includes("tina/__generated__/_graphql.json"))) {
|
|
7826
|
+
throw new TinaQueryError({
|
|
7827
|
+
originalError: error,
|
|
7828
|
+
file: path9,
|
|
7829
|
+
collection: collection.name
|
|
7830
|
+
});
|
|
7831
|
+
}
|
|
7832
|
+
throw error;
|
|
7742
7833
|
}
|
|
7834
|
+
}
|
|
7835
|
+
);
|
|
7836
|
+
return {
|
|
7837
|
+
edges: hydratedEdges.filter(
|
|
7838
|
+
(edge) => edge !== null
|
|
7743
7839
|
),
|
|
7744
7840
|
pageInfo: {
|
|
7745
7841
|
hasPreviousPage,
|
|
@@ -7905,7 +8001,7 @@ var Database = class {
|
|
|
7905
8001
|
throw new Error(`No collection found for path: ${filepath}`);
|
|
7906
8002
|
}
|
|
7907
8003
|
const indexDefinitions = await this.getIndexDefinitions(this.contentLevel);
|
|
7908
|
-
const
|
|
8004
|
+
const referenceSchema = await this.getSchema();
|
|
7909
8005
|
const collectionIndexDefinitions = indexDefinitions?.[collection.name];
|
|
7910
8006
|
let level = this.contentLevel;
|
|
7911
8007
|
if (collection?.isDetached) {
|
|
@@ -7927,7 +8023,7 @@ var Database = class {
|
|
|
7927
8023
|
...makeRefOpsForDocument(
|
|
7928
8024
|
normalizedPath,
|
|
7929
8025
|
collection.name,
|
|
7930
|
-
|
|
8026
|
+
referenceSchema,
|
|
7931
8027
|
item,
|
|
7932
8028
|
"del",
|
|
7933
8029
|
level
|
|
@@ -8074,7 +8170,6 @@ var _indexContent = async ({
|
|
|
8074
8170
|
}
|
|
8075
8171
|
collectionPath = collection.path;
|
|
8076
8172
|
}
|
|
8077
|
-
const collectionReferences = (await database.getCollectionReferences())?.[collection?.name];
|
|
8078
8173
|
const tinaSchema = await database.getSchema();
|
|
8079
8174
|
let templateInfo = null;
|
|
8080
8175
|
if (collection) {
|
|
@@ -8111,7 +8206,7 @@ var _indexContent = async ({
|
|
|
8111
8206
|
...makeRefOpsForDocument(
|
|
8112
8207
|
normalizedPath,
|
|
8113
8208
|
collection?.name,
|
|
8114
|
-
|
|
8209
|
+
tinaSchema,
|
|
8115
8210
|
item,
|
|
8116
8211
|
"del",
|
|
8117
8212
|
level
|
|
@@ -8147,7 +8242,7 @@ var _indexContent = async ({
|
|
|
8147
8242
|
...makeRefOpsForDocument(
|
|
8148
8243
|
normalizedPath,
|
|
8149
8244
|
collection?.name,
|
|
8150
|
-
|
|
8245
|
+
tinaSchema,
|
|
8151
8246
|
aliasedData,
|
|
8152
8247
|
"put",
|
|
8153
8248
|
level
|
|
@@ -8217,7 +8312,6 @@ var _deleteIndexContent = async (database, documentPaths, enqueueOps, collection
|
|
|
8217
8312
|
throw new Error(`No indexDefinitions for collection ${collection.name}`);
|
|
8218
8313
|
}
|
|
8219
8314
|
}
|
|
8220
|
-
const collectionReferences = (await database.getCollectionReferences())?.[collection?.name];
|
|
8221
8315
|
const tinaSchema = await database.getSchema();
|
|
8222
8316
|
let templateInfo = null;
|
|
8223
8317
|
if (collection) {
|
|
@@ -8244,7 +8338,7 @@ var _deleteIndexContent = async (database, documentPaths, enqueueOps, collection
|
|
|
8244
8338
|
...makeRefOpsForDocument(
|
|
8245
8339
|
itemKey,
|
|
8246
8340
|
collection?.name,
|
|
8247
|
-
|
|
8341
|
+
tinaSchema,
|
|
8248
8342
|
aliasedData,
|
|
8249
8343
|
"del",
|
|
8250
8344
|
database.contentLevel
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Collectable, TinaSchema } from '@tinacms/schema-tools';
|
|
2
|
+
/** Marks where a rich-text field was parsed: later segments address tree nodes, not stored keys. */
|
|
3
|
+
export declare const MDX_SEGMENT: {
|
|
4
|
+
readonly mdx: true;
|
|
5
|
+
};
|
|
6
|
+
export type LocatorSegment = string | number | typeof MDX_SEGMENT;
|
|
7
|
+
export type ReferenceVisit = {
|
|
8
|
+
/** The stored value: the path of the document being referenced. */
|
|
9
|
+
value: string;
|
|
10
|
+
/** The collections the field may point at. The index records it under each. */
|
|
11
|
+
collections: string[];
|
|
12
|
+
/** The path to it, as keys and list indices from the document root. */
|
|
13
|
+
locator: LocatorSegment[];
|
|
14
|
+
/** Replaces the value in the document being walked. */
|
|
15
|
+
replace: (next: string | null) => void;
|
|
16
|
+
};
|
|
17
|
+
export declare const encodeLocator: (locator: LocatorSegment[]) => string;
|
|
18
|
+
/**
|
|
19
|
+
* Walks a stored document alongside its schema, visiting every reference it holds, and returns
|
|
20
|
+
* whether any `replace` was called.
|
|
21
|
+
*
|
|
22
|
+
* The index build and the rename and delete rewrites all use this traversal, so they resolve the
|
|
23
|
+
* same references.
|
|
24
|
+
*/
|
|
25
|
+
export declare const visitReferences: (data: Record<string, unknown>, collectable: Collectable, tinaSchema: TinaSchema, visit: (reference: ReferenceVisit) => void) => boolean;
|
package/dist/resolver/index.d.ts
CHANGED
|
@@ -593,6 +593,14 @@ export declare class Resolver {
|
|
|
593
593
|
endCursor: string;
|
|
594
594
|
};
|
|
595
595
|
}>;
|
|
596
|
+
/**
|
|
597
|
+
* Repoints every reference to `from` at `to`, or clears it when `to` is null.
|
|
598
|
+
*
|
|
599
|
+
* Each referring document is re-walked rather than addressed by the locators the index stored,
|
|
600
|
+
* since a stored path cannot address a reference inside rich text. Only a document the walk
|
|
601
|
+
* changed is written back.
|
|
602
|
+
*/
|
|
603
|
+
private rewriteReferences;
|
|
596
604
|
/**
|
|
597
605
|
* Checks if a document has references to it
|
|
598
606
|
* @param id The id of the document to check for references
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tinacms/graphql",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "4.0.
|
|
4
|
+
"version": "4.0.1",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "./dist/index.js",
|
|
7
7
|
"files": [
|
|
@@ -36,15 +36,15 @@
|
|
|
36
36
|
"gray-matter": "^4.0.3",
|
|
37
37
|
"isomorphic-git": "^1.29.0",
|
|
38
38
|
"js-sha1": "^0.6.0",
|
|
39
|
-
"js-yaml": "^3.15.
|
|
39
|
+
"js-yaml": "^3.15.2",
|
|
40
40
|
"jsonpath-plus": "^10.3.0",
|
|
41
41
|
"many-level": "^2.0.0",
|
|
42
42
|
"micromatch": "4.0.8",
|
|
43
43
|
"normalize-path": "^3.0.0",
|
|
44
44
|
"readable-stream": "^4.7.0",
|
|
45
45
|
"yup": "^1.6.1",
|
|
46
|
-
"@tinacms/
|
|
47
|
-
"@tinacms/
|
|
46
|
+
"@tinacms/mdx": "^2.4.0",
|
|
47
|
+
"@tinacms/schema-tools": "^2.11.0"
|
|
48
48
|
},
|
|
49
49
|
"publishConfig": {
|
|
50
50
|
"registry": "https://registry.npmjs.org"
|
|
@@ -72,8 +72,8 @@
|
|
|
72
72
|
"vite": "^4.5.9",
|
|
73
73
|
"vitest": "^0.32.4",
|
|
74
74
|
"zod": "^3.24.2",
|
|
75
|
-
"@tinacms/
|
|
76
|
-
"@tinacms/
|
|
75
|
+
"@tinacms/scripts": "1.6.4",
|
|
76
|
+
"@tinacms/schema-tools": "2.11.0"
|
|
77
77
|
},
|
|
78
78
|
"scripts": {
|
|
79
79
|
"types": "pnpm tsc",
|