aboutsummaryrefslogtreecommitdiff
path: root/src/client/documents/Gitlike.ts
blob: f35f33f65c50573946eb85505e5581f6b612e7b7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
// import { Doc, DocListCast, DocListCastAsync, Field } from "../../fields/Doc";
// import { List } from "../../fields/List";
// import { Cast, DateCast } from "../../fields/Types";
// import { DateField } from "../../fields/DateField";
// import { Id } from "../../fields/FieldSymbols";

// // synchs matching documents on the two branches that are being merged/pulled
// // currently this just synchs the main 'fieldKey' component of the data since
// // we don't have individual timestamps for all fields -- this is a problematic design issue.
// function GitlikeSynchDocs(bd: Doc, md: Doc) {
//     const fieldKey = Doc.LayoutFieldKey(md);
//     const bdate = DateCast(bd[`${fieldKey}_modificationDate`])?.date;
//     const mdate = DateCast(md[`${fieldKey}_modificationDate`])?.date;
//     const bdproto = bd && Doc.GetProto(bd);
//     if (bdate !== mdate && bdate <= mdate) {
//         if (bdproto && md) {
//             bdproto[fieldKey] = Field.Copy(md[fieldKey]);
//             bdproto[`${fieldKey}_modificationDate`] = new DateField();
//         }
//     }
//     const bldate = DateCast(bd._layout_modificationDate)?.date;
//     const mldate = DateCast(md._layout_modificationDate)?.date;
//     if (bldate === mldate || bldate > mldate) return;
//     if (bdproto && md) {
//         bd.x = Field.Copy(md.x);
//         bd.y = Field.Copy(md.y);
//         bd.width = Field.Copy(md.width);
//         bd.height = Field.Copy(md.height);
//         bdproto._layout_modificationDate = new DateField();
//     }
// }

// // pulls documents onto a branch from the branch's master
// // if a document exists on master but not on the branch, it is branched and added
// // NOTE: need to set a timestamp on the branch that is equal to the master's last merge timestamp.
// async function GitlikePullFromMaster(branch: Doc, suffix = "") {
//     const masterMain = Cast(branch.branchOf, Doc, null);
//     // get the set of documents on both the branch and master
//     const masterMainDocs = masterMain && await DocListCastAsync(masterMain[Doc.LayoutFieldKey(masterMain) + suffix]);
//     const branchMainDocs = await DocListCastAsync(branch[Doc.LayoutFieldKey(branch) + suffix]);
//     // get the master documents that correspond to the branch documents
//     const branchMasterMainDocs = branchMainDocs?.map(bd => Cast(bd.branchOf, Doc, null) || bd);
//     const branchMasterMainDocProtos = branchMasterMainDocs?.map(doc => Doc.GetProto(doc));
//     // get documents on master that don't have a corresponding master doc (form a branch doc), and ...
//     const newDocsFromMaster = masterMainDocs?.filter(md => !branchMasterMainDocProtos?.includes(Doc.GetProto(md)));
//     const oldDocsFromMaster = masterMainDocs?.filter(md => branchMasterMainDocProtos?.includes(Doc.GetProto(md)));
//     oldDocsFromMaster?.forEach(md => {
//         const bd = branchMainDocs?.find(bd => (Cast(bd.branchOf, Doc, null) || bd) === md);
//         bd && GitlikeSynchDocs(bd, md);
//     });
//     const cloneMap = new Map<string, Doc>(); cloneMap.set(masterMain[Id], branch);
//     // make branch clones of them, then add them to the branch
//     const newlyBranchedDocs = await Promise.all(newDocsFromMaster?.map(async md => (await Doc.MakeClone(md, false, true, cloneMap)).clone) || []);
//     newlyBranchedDocs.forEach(nd => {
//         Doc.AddDocToList(branch, Doc.LayoutFieldKey(branch) + suffix, nd);
//         nd.embedContainer = branch;
//     });
//     // if a branch doc's corresponding main branch doc doesn't have a embedContainer, then it was deleted.
//     const remDocsFromMaster = branchMainDocs?.filter(bd => Cast(bd.branchOf, Doc, null) && !Cast(bd.branchOf, Doc, null)?.embedContainer);
//     // so then remove all the deleted main docs from this branch.
//     remDocsFromMaster?.forEach(rd => Doc.RemoveDocFromList(branch, Doc.LayoutFieldKey(branch) + suffix, rd));
// }

// // merges all branches from the master branch by first merging the top-level collection of documents,
// // and then merging all the annotations on those documents.
// // TODO: need to add an incrementing timestamp whenever anything merges.  don't allow a branch to merge if it's last pull timestamp isn't equal to the last merge timestamp.
// async function GitlikeMergeWithMaster(master: Doc, suffix = "") {
//     const branches = await DocListCastAsync(master.branches);
//     branches?.map(async branch => {
//         const branchChildren = await DocListCastAsync(branch[Doc.LayoutFieldKey(branch) + suffix]);
//         branchChildren && await Promise.all(branchChildren.map(async bd => {
//             const cloneMap = new Map<string, Doc>(); cloneMap.set(master[Id], branch);
//             // see if the branch's child exists on master.
//             const masterChild = Cast(bd.branchOf, Doc, null) || (await Doc.MakeClone(bd, false, true, cloneMap)).clone;
//             // if the branch's child didn't exist on master, we make a branch clone of the child to add to master.
//             // however, since master is supposed to have the "main" clone, and branches, the "branch" clones, we have to reverse the fields
//             // on the branch child and master clone.
//             if (masterChild.branchOf) {
//                 const branchDocProto = Doc.GetProto(bd);
//                 const masterChildProto = Doc.GetProto(masterChild);
//                 const branchTitle = bd.title;
//                 branchDocProto.title = masterChildProto.title;
//                 masterChildProto.title = branchTitle;
//                 masterChildProto.branchOf = masterChild.branchOf = undefined; // the master child should not be a branch of the branch child, so unset 'branchOf'
//                 masterChildProto.branches = new List<Doc>([bd]); // the master child's branches needs to include the branch child
//                 Doc.RemoveDocFromList(branchDocProto, "branches", masterChildProto);   // the branch child should not have the master child in its branch list.
//                 branchDocProto.branchOf = masterChild;                                 // the branch child is now a branch of the master child
//             }
//             Doc.AddDocToList(master, Doc.LayoutFieldKey(master) + suffix, masterChild); // add the masterChild to master (if it's already there, this is a no-op)
//             masterChild.embedContainer = master;
//             GitlikeSynchDocs(masterChild, bd);//Doc.GetProto(masterChild), bd);
//         }));
//         const masterChildren = await DocListCastAsync(master[Doc.LayoutFieldKey(master) + suffix]);
//         masterChildren?.forEach(mc => {                      // see if any master children
//             if (!branchChildren?.find(bc => bc.branchOf === mc)) { //    are not in the list of children for this branch.
//                 Doc.RemoveDocFromList(master, Doc.LayoutFieldKey(master) + suffix, mc); // if so, delete the master child since the branch has deleted it.
//                 mc.embedContainer = undefined;      // NOTE if we merge a branch that didn't do a pull, it will look like the branch deleted documents -- need edit timestamps that prevent merging if branch isn't up-to-date with last edit timestamp
//             }
//         });
//     });
// }

// // performs a "git"-like task: pull or merge
// //    if pull, then target is a specific branch document that will be updated from its associated master
// //    if merge, then target is the master doc that will merge in all branches associated with it.
// // TODO: parameterize 'merge' to specify which branch(es) should be merged.
// //       extend 'merge' to allow a specific branch to be merge target (not just master);
// //       make pull/merge be recursive (ie, this func currently just operates on the main doc and its children)
// export async function BranchTask(target: Doc, action: "pull" | "merge") {
//     const func = action === "pull" ? GitlikePullFromMaster : GitlikeMergeWithMaster;
//     await func(target, "");
//     await DocListCast(target[Doc.LayoutFieldKey(target)]).forEach(async targetChild => func(targetChild, "_annotations"));
//     await DocListCast(target[Doc.LayoutFieldKey(target)]).forEach(async targetChild => func(targetChild, "_sidebar"));
// }

// export async function BranchCreate(target: Doc) {
//     return (await Doc.MakeClone(target, false, true)).clone;
// }