@dotinc/ogre 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/.tap/processinfo/{6d907291-2f1e-4670-b04c-3a667271c352.json → 31ca0767-30d5-4c1b-aab3-1a456fd51558.json} +6 -6
  2. package/.tap/processinfo/{4cdc23d3-f7ce-4075-922f-722bf0d687fc.json → 52683acc-91e1-4d54-9715-1cbaf91964a7.json} +6 -6
  3. package/.tap/processinfo/{8c48e5e9-6eca-4afe-a7b5-04e26b765d29.json → 65d66b6b-127f-4a35-b64a-5b0ac1df524c.json} +22 -22
  4. package/.tap/processinfo/{7dc6b1af-ac78-47bc-9b62-630e387e8755.json → 77376985-2ddf-4b47-9631-c637b0ecbcdd.json} +6 -6
  5. package/.tap/processinfo/{0799a6bd-022f-41d1-8be9-6338667041c0.json → 86009ac9-5819-45bf-b53f-0448d4b7ef56.json} +6 -6
  6. package/.tap/processinfo/{8ca695ae-d038-441a-b4ab-2a242d22d416.json → 9e67801c-9248-4793-994c-a9b4f59ebc4f.json} +6 -6
  7. package/.tap/processinfo/{98475c49-5ee5-4c2c-b8e2-85bd2af528c9.json → f9080426-4139-4a9a-a59f-ccbfa4cadf7d.json} +13 -13
  8. package/.tap/test-results/src/branch.test.ts.tap +6 -6
  9. package/.tap/test-results/src/checkout.test.ts.tap +9 -9
  10. package/.tap/test-results/src/commit.test.ts.tap +24 -16
  11. package/.tap/test-results/src/merge.test.ts.tap +2 -2
  12. package/.tap/test-results/src/repository.test.ts.tap +86 -12
  13. package/.tap/test-results/src/tag.test.ts.tap +3 -3
  14. package/.tap/test-results/src/utils.test.ts.tap +7 -7
  15. package/CHANGELOG.md +13 -0
  16. package/lib/index.d.ts +1 -0
  17. package/lib/index.js +5 -0
  18. package/lib/repository.d.ts +13 -1
  19. package/lib/repository.js +34 -20
  20. package/lib/test.utils.d.ts +1 -4
  21. package/lib/test.utils.js +2 -1
  22. package/package.json +2 -2
  23. package/src/commit.test.ts +18 -0
  24. package/src/index.ts +2 -0
  25. package/src/repository.test.ts +146 -1
  26. package/src/repository.ts +51 -21
  27. package/src/test.utils.ts +4 -3
@@ -1,9 +1,9 @@
1
1
  TAP version 14
2
2
  # Subtest: diff is ok
3
3
  ok 1 - main is pointing at wrong commit
4
- ok 2 - invalid \# of change entries: [{"op":"add","path":"/nested/0","value":{"uuid":"054a46dd-f3dd-4f56-a7ed-1d17a38a687d","name":"new name"}},{"op":"add","path":"/nested/1","value":{"uuid":"ff2346f8-0d88-4d12-848b-1b35f63e8b38","name":"first name"}}]
4
+ ok 2 - invalid \# of change entries: [{"op":"add","path":"/nested/0","value":{"uuid":"aa929d75-cfce-4798-9f2d-7ff07a2ae610","name":"new name"}},{"op":"add","path":"/nested/1","value":{"uuid":"154ef374-8162-4d02-a72a-af0c6181535c","name":"first name"}}]
5
5
  1..2
6
- ok 1 - diff is ok # time=88.992ms
6
+ ok 1 - diff is ok # time=59.877ms
7
7
 
8
8
  # Subtest: restore
9
9
  # Subtest: history check
@@ -13,7 +13,7 @@ ok 1 - diff is ok # time=88.992ms
13
13
  ok 4 - incorrect \# of commits
14
14
  ok 5 - incorrect \# of changelog entries
15
15
  1..5
16
- ok 1 - history check # time=116.216ms
16
+ ok 1 - history check # time=85.095ms
17
17
 
18
18
  # Subtest: reconstruct with 2 commits
19
19
  ok 1 - main is pointing at wrong commit
@@ -22,10 +22,10 @@ ok 1 - diff is ok # time=88.992ms
22
22
  ok 4 - incorrect \# of commits
23
23
  ok 5 - incorrect \# of changelog entries
24
24
  1..5
25
- ok 2 - reconstruct with 2 commits # time=8.342ms
25
+ ok 2 - reconstruct with 2 commits # time=6.821ms
26
26
 
27
27
  1..2
28
- ok 2 - restore # time=167.323ms
28
+ ok 2 - restore # time=140.616ms
29
29
 
30
30
  # Subtest: history
31
31
  # Subtest: history contains HEAD ref
@@ -34,15 +34,15 @@ ok 2 - restore # time=167.323ms
34
34
  ok 3 - should be equal
35
35
  ok 4 - should be equal
36
36
  1..4
37
- ok 1 - history contains HEAD ref # time=105.224ms
37
+ ok 1 - history contains HEAD ref # time=62.587ms
38
38
 
39
39
  # Subtest: empty history unreachable HEAD
40
40
  ok 1 - expected to throw
41
41
  1..1
42
- ok 2 - empty history unreachable HEAD # time=2.508ms
42
+ ok 2 - empty history unreachable HEAD # time=2.454ms
43
43
 
44
44
  1..2
45
- ok 3 - history # time=187.749ms
45
+ ok 3 - history # time=172.026ms
46
46
 
47
47
  # Subtest: reset
48
48
  # Subtest: reset hard
@@ -50,14 +50,88 @@ ok 3 - history # time=187.749ms
50
50
  ok 2 - wrong \# of changes in diff
51
51
  ok 3 - failed to reset
52
52
  1..3
53
- ok 1 - reset hard # time=3.467ms
53
+ ok 1 - reset hard # time=2.495ms
54
54
 
55
55
  1..1
56
- ok 4 - reset # time=73.017ms
56
+ ok 4 - reset # time=65.322ms
57
+
58
+ # Subtest: status
59
+ # Subtest: clean repo no change
60
+ ok 1 - Shouldn't have pending changes
61
+ 1..1
62
+ ok 1 - clean repo no change # time=383.866ms
63
+
64
+ # Subtest: clean repo pending change
65
+ ok 1 - Status doesn't contain changes
66
+ 1..1
67
+ ok 2 - clean repo pending change # time=0.618ms
68
+
69
+ # Subtest: reading status doesn't clean observer
70
+ ok 1 - Status doesn't contain changes
71
+ ok 2 - Status doesn't contain changes
72
+ ok 3 - different pending changes??
73
+ 1..3
74
+ ok 3 - reading status doesn't clean observer # time=0.99ms
75
+
76
+ # Subtest: after commit no change
77
+ ok 1 - Shouldn't have pending changes
78
+ 1..1
79
+ ok 4 - after commit no change # time=1.194ms
80
+
81
+ # Subtest: after commit pending change
82
+ ok 1 - Shouldn't have pending changes
83
+ ok 2 - Status doesn't contain changes
84
+ 1..2
85
+ ok 5 - after commit pending change # time=1.322ms
86
+
87
+ # Subtest: after commit pending change for rewrite array
88
+ ok 1 - Shouldn't have pending changes
89
+ ok 2 - Status doesn't contain changes
90
+ 1..2
91
+ ok 6 - after commit pending change for rewrite array # time=1.325ms
92
+
93
+ # Subtest: change of nested array element prop
94
+ ok 1 - Shouldn't have pending changes
95
+ ok 2 - Status doesn't contain changes
96
+ 1..2
97
+ ok 7 - change of nested array element prop # time=1.704ms
98
+
99
+ 1..7
100
+ ok 5 - status # time=447.711ms
101
+
102
+ # Subtest: apply
103
+ # Subtest: single patch
104
+ ok 1 - Shouldn't have pending changes
105
+ ok 2 - Failed to apply patch
106
+ ok 3 - The final state does not match up
107
+ ok 4 - Status doesn't contain changes
108
+ ok 5 - It should have the right changes
109
+ 1..5
110
+ ok 1 - single patch # time=116.271ms
111
+
112
+ # Subtest: patch for undefined props doesn't work as expected https://github.com/Starcounter-Jack/JSON-Patch/issues/280
113
+ ok 1 - Shouldn't have pending changes
114
+ ok 2 - Failed to apply patch
115
+ ok 3 - The final state shoould not match up, because patch failed
116
+ ok 4 - Status doesn't contain changes
117
+ 1..4
118
+ ok 2 - patch for undefined props doesn't work as expected https://github.com/Starcounter-Jack/JSON-Patch/issues/280 # time=3.777ms
119
+
120
+ # Subtest: multiple patches
121
+ ok 1 - Shouldn't have pending changes
122
+ ok 2 - Failed to apply patch
123
+ ok 3 - Status doesn't contain changes
124
+ ok 4 - It should have the right changes
125
+ ok 5 - The final state does not match up
126
+ 1..5
127
+ ok 3 - multiple patches # time=1.47ms
128
+
129
+ 1..3
130
+ ok 6 - apply # time=174.216ms
57
131
 
58
132
  # Subtest: restoring from history
59
133
  ok 1 - restored object does not equal last version.
60
134
  1..1
61
- ok 5 - restoring from history # time=16.296ms
135
+ ok 7 - restoring from history # time=3.033ms
62
136
 
63
- 1..5
137
+ 1..7
@@ -2,18 +2,18 @@ TAP version 14
2
2
  # Subtest: cannot tag on an empty repo
3
3
  ok 1 - expected to throw
4
4
  1..1
5
- ok 1 - cannot tag on an empty repo # time=26.547ms
5
+ ok 1 - cannot tag on an empty repo # time=15.405ms
6
6
 
7
7
  # Subtest: can create simple tag pointing to HEAD
8
8
  ok 1 - should be equal
9
9
  ok 2 - tag is not pointing to expected commit
10
10
  ok 3 - reference was not present in history
11
11
  1..3
12
- ok 2 - can create simple tag pointing to HEAD # time=7.579ms
12
+ ok 2 - can create simple tag pointing to HEAD # time=8.818ms
13
13
 
14
14
  # Subtest: cannot create tag with whitespace
15
15
  ok 1 - expected to throw
16
16
  1..1
17
- ok 3 - cannot create tag with whitespace # time=2.772ms
17
+ ok 3 - cannot create tag with whitespace # time=2.471ms
18
18
 
19
19
  1..3
@@ -3,41 +3,41 @@ TAP version 14
3
3
  ok 1 - should be equal
4
4
  ok 2 - should be equal
5
5
  1..2
6
- ok 1 - author <email@domain.info> # time=3.979ms
6
+ ok 1 - author <email@domain.info> # time=3.986ms
7
7
 
8
8
  # Subtest: author with space <email@domain.info>
9
9
  ok 1 - should be equal
10
10
  ok 2 - should be equal
11
11
  1..2
12
- ok 2 - author with space <email@domain.info> # time=0.662ms
12
+ ok 2 - author with space <email@domain.info> # time=0.849ms
13
13
 
14
14
  # Subtest: author @handle
15
15
  ok 1 - should be equal
16
16
  ok 2 - should be equal
17
17
  1..2
18
- ok 3 - author @handle # time=0.455ms
18
+ ok 3 - author @handle # time=0.609ms
19
19
 
20
20
  # Subtest: author with space @handle
21
21
  ok 1 - should be equal
22
22
  ok 2 - should be equal
23
23
  1..2
24
- ok 4 - author with space @handle # time=0.419ms
24
+ ok 4 - author with space @handle # time=0.553ms
25
25
 
26
26
  # Subtest: email@domain.info
27
27
  ok 1 - should be equal
28
28
  ok 2 - should be equal
29
29
  1..2
30
- ok 5 - email@domain.info # time=0.61ms
30
+ ok 5 - email@domain.info # time=0.726ms
31
31
 
32
32
  # Subtest: @handle
33
33
  ok 1 - should be equal
34
34
  ok 2 - should be equal
35
35
  1..2
36
- ok 6 - @handle # time=0.591ms
36
+ ok 6 - @handle # time=0.699ms
37
37
 
38
38
  # Subtest: empty author
39
39
  ok 1 - expected to throw
40
40
  1..1
41
- ok 7 - empty author # time=2.247ms
41
+ ok 7 - empty author # time=2.326ms
42
42
 
43
43
  1..7
package/CHANGELOG.md CHANGED
@@ -1,3 +1,16 @@
1
+ # v0.6.0 (Sat Mar 02 2024)
2
+
3
+ #### 🚀 Enhancement
4
+
5
+ - feat: status and apply [#156](https://github.com/dotindustries/ogre/pull/156) ([@nadilas](https://github.com/nadilas))
6
+ - feat: status and apply ([@nadilas](https://github.com/nadilas))
7
+
8
+ #### Authors: 1
9
+
10
+ - [@nadilas](https://github.com/nadilas)
11
+
12
+ ---
13
+
1
14
  # v0.5.0 (Sat Feb 24 2024)
2
15
 
3
16
  #### 🚀 Enhancement
package/lib/index.d.ts CHANGED
@@ -5,3 +5,4 @@ export * from "./ref";
5
5
  export * from "./size";
6
6
  export * from "./utils";
7
7
  export * from "./git2json";
8
+ export { compare, deepClone, Operation, JsonPatchError } from "fast-json-patch";
package/lib/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.JsonPatchError = exports.deepClone = exports.compare = void 0;
3
4
  const tslib_1 = require("tslib");
4
5
  tslib_1.__exportStar(require("./interfaces"), exports);
5
6
  tslib_1.__exportStar(require("./repository"), exports);
@@ -7,3 +8,7 @@ tslib_1.__exportStar(require("./ref"), exports);
7
8
  tslib_1.__exportStar(require("./size"), exports);
8
9
  tslib_1.__exportStar(require("./utils"), exports);
9
10
  tslib_1.__exportStar(require("./git2json"), exports);
11
+ var fast_json_patch_1 = require("fast-json-patch");
12
+ Object.defineProperty(exports, "compare", { enumerable: true, get: function () { return fast_json_patch_1.compare; } });
13
+ Object.defineProperty(exports, "deepClone", { enumerable: true, get: function () { return fast_json_patch_1.deepClone; } });
14
+ Object.defineProperty(exports, "JsonPatchError", { enumerable: true, get: function () { return fast_json_patch_1.JsonPatchError; } });
@@ -1,4 +1,4 @@
1
- import { Operation } from "fast-json-patch";
1
+ import { Operation, JsonPatchError } from "fast-json-patch";
2
2
  import { Commit } from "./commit";
3
3
  import { History } from "./interfaces";
4
4
  export declare const REFS_HEAD_KEY = "HEAD";
@@ -20,6 +20,15 @@ export interface RepositoryObject<T extends {
20
20
  * @param shaishTo expression (e.g. refs (branches, tags), commitSha)
21
21
  */
22
22
  diff(shaishFrom: string, shaishTo?: string): Operation[];
23
+ /**
24
+ * Returns pending changes.
25
+ */
26
+ status(): Operation[];
27
+ /**
28
+ * Applies a patch to the repository's HEAD
29
+ * @param patch
30
+ */
31
+ apply(patch: Operation[]): void;
23
32
  head(): string;
24
33
  ref(reference: string): string | undefined;
25
34
  commit(message: string, author: string, amend?: boolean): Promise<string>;
@@ -52,8 +61,10 @@ export declare class Repository<T extends {
52
61
  private readonly refs;
53
62
  private readonly commits;
54
63
  private moveTo;
64
+ apply(patch: Operation[]): JsonPatchError | undefined;
55
65
  reset(mode?: "soft" | "hard" | undefined, shaish?: string | undefined): void;
56
66
  branch(): string;
67
+ status(): Operation[];
57
68
  diff(shaishFrom: string, shaishTo?: string): Operation[];
58
69
  checkout(shaish: string, createBranch?: boolean): void;
59
70
  commit(message: string, author: string, amend?: boolean): Promise<string>;
@@ -84,3 +95,4 @@ export declare const validateRef: (name: string, oneLevel?: boolean) => void;
84
95
  export declare const printChangeLog: <T extends {
85
96
  [k: string]: any;
86
97
  }>(repository: RepositoryObject<T>) => void;
98
+ export declare const printChange: (chg: Operation) => void;
package/lib/repository.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.printChangeLog = exports.validateRef = exports.validateBranchName = exports.tagToRef = exports.brancheNameToRef = exports.cleanRefValue = exports.isTagRef = exports.createHeadRefValue = exports.Repository = exports.REFS_MAIN_KEY = exports.REFS_HEAD_KEY = void 0;
3
+ exports.printChange = exports.printChangeLog = exports.validateRef = exports.validateBranchName = exports.tagToRef = exports.brancheNameToRef = exports.cleanRefValue = exports.isTagRef = exports.createHeadRefValue = exports.Repository = exports.REFS_MAIN_KEY = exports.REFS_HEAD_KEY = void 0;
4
4
  const fast_json_patch_1 = require("fast-json-patch");
5
5
  const commit_1 = require("./commit");
6
6
  const ref_1 = require("./ref");
@@ -44,10 +44,18 @@ class Repository {
44
44
  if (!patchToTarget || patchToTarget.length < 1) {
45
45
  return;
46
46
  }
47
- (0, fast_json_patch_1.unobserve)(this.data, this.observer);
47
+ this.observer.unobserve();
48
48
  patchToTarget.reduce(fast_json_patch_1.applyReducer, this.data);
49
49
  this.observer = (0, fast_json_patch_1.observe)(this.data);
50
50
  }
51
+ apply(patch) {
52
+ const err = (0, fast_json_patch_1.validate)(patch, this.data);
53
+ if (err) {
54
+ return err;
55
+ }
56
+ (0, fast_json_patch_1.applyPatch)(this.data, patch);
57
+ // const changed = patch.reduce(applyReducer, this.data);
58
+ }
51
59
  reset(mode = "hard", shaish = exports.REFS_HEAD_KEY) {
52
60
  if (mode === "hard") {
53
61
  (0, fast_json_patch_1.unobserve)(this.data, this.observer);
@@ -76,6 +84,14 @@ class Repository {
76
84
  }
77
85
  return exports.REFS_HEAD_KEY; // detached state
78
86
  }
87
+ status() {
88
+ const commit = this.commitAtHead();
89
+ if (!commit) {
90
+ // on root repo return the pending changes
91
+ return (0, fast_json_patch_1.compare)(this.original, this.data); // this.observer.patches is empty?? :(
92
+ }
93
+ return this.diff(commit.hash);
94
+ }
79
95
  diff(shaishFrom, shaishTo) {
80
96
  const [cFrom] = shaishToCommit(shaishFrom, this.refs, this.commits);
81
97
  let target;
@@ -321,20 +337,6 @@ const treeToObject = (tree) => {
321
337
  return JSON.parse((0, fflate_1.strFromU8)((0, fflate_1.decompressSync)(Buffer.from(tree, "base64"))));
322
338
  };
323
339
  const getLastItem = (thePath) => thePath.substring(thePath.lastIndexOf("/") + 1);
324
- /**
325
- * Traverses the commit tree backwards and reassembles the changelog
326
- * @param commit
327
- * @param commitsList
328
- */
329
- const traverseAndCollectChangelog = (commit, commitsList) => {
330
- let c = commit;
331
- let clog = [];
332
- while (c !== undefined) {
333
- clog = [...commit.changes, ...clog];
334
- c = commitsList.find((parent) => parent.hash === (c === null || c === void 0 ? void 0 : c.parent));
335
- }
336
- return clog;
337
- };
338
340
  const mapPath = (from, to, commits) => {
339
341
  let c = to;
340
342
  while (c !== undefined) {
@@ -458,16 +460,28 @@ exports.validateRef = validateRef;
458
460
  */
459
461
  const printChangeLog = (repository) => {
460
462
  console.log("----------------------------------------------------------");
461
- console.log(`Changelog at ${repository.head()}`);
463
+ console.log("Changelog");
464
+ console.log("----------------------------------------------------------");
462
465
  const history = repository.getHistory();
463
466
  const head = commitAtRefIn(repository.head(), history.refs, history.commits);
464
467
  if (!head) {
465
468
  throw new Error(`fatal: HEAD is not defined`);
466
469
  }
467
- const changeLog = traverseAndCollectChangelog(head, history.commits);
468
- for (const [, chg] of changeLog.entries()) {
469
- console.log(` ${JSON.stringify(chg)}`);
470
+ let c = head;
471
+ while (c) {
472
+ console.log(`${c.hash} ${refsAtCommit(history.refs, c)
473
+ .map((r) => r.name)
474
+ .join(" ")}`);
475
+ for (const chg of c.changes) {
476
+ (0, exports.printChange)(chg);
477
+ }
478
+ c = history.commits.find((parent) => parent.hash === (c === null || c === void 0 ? void 0 : c.parent));
470
479
  }
480
+ console.log("End of changelog");
471
481
  console.log("----------------------------------------------------------");
472
482
  };
473
483
  exports.printChangeLog = printChangeLog;
484
+ const printChange = (chg) => {
485
+ console.log(` ${JSON.stringify(chg)}`);
486
+ };
487
+ exports.printChange = printChange;
@@ -11,10 +11,7 @@ export declare type ComplexObject = {
11
11
  nested: NestedObject[];
12
12
  };
13
13
  export declare const testAuthor = "User name <name@domain.com>";
14
- export declare function getBaseline(): Promise<[
15
- RepositoryObject<ComplexObject>,
16
- ComplexObject
17
- ]>;
14
+ export declare function getBaseline(obj?: Partial<ComplexObject>): Promise<[RepositoryObject<ComplexObject>, ComplexObject]>;
18
15
  export declare function updateHeaderData(wrapped: ComplexObject): number;
19
16
  export declare function addOneStep(wrapped: ComplexObject): number;
20
17
  export declare function sumChanges(commits: Commit[] | undefined): number | undefined;
package/lib/test.utils.js CHANGED
@@ -4,12 +4,13 @@ exports.sumChanges = exports.addOneStep = exports.updateHeaderData = exports.get
4
4
  const uuid_1 = require("uuid");
5
5
  const repository_1 = require("./repository");
6
6
  exports.testAuthor = "User name <name@domain.com>";
7
- async function getBaseline() {
7
+ async function getBaseline(obj) {
8
8
  const co = {
9
9
  uuid: undefined,
10
10
  name: undefined,
11
11
  description: undefined,
12
12
  nested: [],
13
+ ...obj,
13
14
  };
14
15
  const repo = new repository_1.Repository(co, {});
15
16
  return [repo, co];
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "type": "git",
5
5
  "url": "https://github.com/dotindustries/ogre.git"
6
6
  },
7
- "version": "0.5.0",
7
+ "version": "0.6.0",
8
8
  "description": "Git-like repository for in-memory object versioning",
9
9
  "private": false,
10
10
  "main": "lib/index.js",
@@ -37,5 +37,5 @@
37
37
  "registry": "https://registry.npmjs.org/",
38
38
  "access": "public"
39
39
  },
40
- "gitHead": "c6bad3ae8bf832cd9f9f9186cd3c37cf96420a46"
40
+ "gitHead": "38430801d71ee222edd396ddffa4f23263c9ad1c"
41
41
  }
@@ -7,6 +7,7 @@ import {
7
7
  testAuthor,
8
8
  updateHeaderData,
9
9
  } from "./test.utils";
10
+ import { printChangeLog } from "./repository";
10
11
 
11
12
  test("baseline with 1 commit and zero changelog entries", async (t) => {
12
13
  const [repo] = await getBaseline();
@@ -40,6 +41,23 @@ test("no commit without changes after recent commit", async (t) => {
40
41
  });
41
42
  });
42
43
 
44
+ test("overwrite nested array changes are recognized", async (t) => {
45
+ const [repo] = await getBaseline();
46
+ repo.data.name = "new name";
47
+ await repo.commit("baseline", testAuthor);
48
+ repo.data.nested = [{ name: "new item", uuid: "asdf" }];
49
+ await repo.commit("overwrite nested array", testAuthor);
50
+ });
51
+
52
+ test("change of nested array element is recognized", async (t) => {
53
+ const [repo] = await getBaseline();
54
+ repo.data.name = "new name";
55
+ addOneStep(repo.data);
56
+ await repo.commit("baseline", testAuthor);
57
+ repo.data.nested[0].name = "another name which is different";
58
+ await repo.commit("changed nested array object", testAuthor);
59
+ });
60
+
43
61
  test("treeHash of commit is matching content", async (t) => {
44
62
  const [repo] = await getBaseline();
45
63
  repo.data.name = "new name";
package/src/index.ts CHANGED
@@ -5,3 +5,5 @@ export * from "./ref";
5
5
  export * from "./size";
6
6
  export * from "./utils";
7
7
  export * from "./git2json";
8
+
9
+ export { compare, deepClone, Operation, JsonPatchError } from "fast-json-patch";
@@ -1,7 +1,8 @@
1
1
  import { test } from "tap";
2
2
 
3
- import { Repository } from "./repository";
3
+ import { printChange, printChangeLog, Repository } from "./repository";
4
4
  import {
5
+ addOneStep,
5
6
  addOneStep as addOneNested,
6
7
  ComplexObject,
7
8
  getBaseline,
@@ -10,6 +11,7 @@ import {
10
11
  updateHeaderData,
11
12
  } from "./test.utils";
12
13
  import { History, Reference } from "./interfaces";
14
+ import { compare, Operation } from "fast-json-patch";
13
15
 
14
16
  test("diff is ok", async (t) => {
15
17
  const [repo, obj] = await getBaseline();
@@ -188,3 +190,146 @@ test("reset", async (t) => {
188
190
  t.equal(diff2.length, 0, "failed to reset");
189
191
  });
190
192
  });
193
+
194
+ test("status", async (t) => {
195
+ t.test("clean repo no change", async (t) => {
196
+ const [repo] = await getBaseline();
197
+ const cleanState = repo.status();
198
+ t.match(cleanState, [], "Shouldn't have pending changes");
199
+ });
200
+ t.test("clean repo pending change", async (t) => {
201
+ const [repo] = await getBaseline({ name: "base name" });
202
+ repo.data.name = "changed name";
203
+ const dirtyState = repo.status();
204
+ t.equal(dirtyState.length, 1, "Status doesn't contain changes");
205
+ });
206
+ t.test("reading status doesn't clean observer", async (t) => {
207
+ const [repo] = await getBaseline({ name: "base name" });
208
+ repo.data.name = "changed name";
209
+ const dirtyState = repo.status();
210
+ t.equal(dirtyState.length, 1, "Status doesn't contain changes");
211
+
212
+ const dirtyState2 = repo.status();
213
+ t.equal(dirtyState2.length, 1, "Status doesn't contain changes");
214
+ t.match(dirtyState2, dirtyState2, "different pending changes??");
215
+ });
216
+ t.test("after commit no change", async (t) => {
217
+ const [repo] = await getBaseline();
218
+ repo.data.name = "new name";
219
+ await repo.commit("baseline", testAuthor);
220
+ const cleanState = repo.status();
221
+ t.match(cleanState, [], "Shouldn't have pending changes");
222
+ });
223
+ t.test("after commit pending change", async (t) => {
224
+ const [repo] = await getBaseline();
225
+ repo.data.name = "new name";
226
+ await repo.commit("baseline", testAuthor);
227
+ const cleanState = repo.status();
228
+ t.match(cleanState, [], "Shouldn't have pending changes");
229
+ repo.data.name = "changed name";
230
+ const dirtyState = repo.status();
231
+ t.equal(dirtyState.length, 1, "Status doesn't contain changes");
232
+ });
233
+ t.test("after commit pending change for rewrite array", async (t) => {
234
+ const [repo] = await getBaseline();
235
+ repo.data.name = "new name";
236
+ await repo.commit("baseline", testAuthor);
237
+ const cleanState = repo.status();
238
+ t.match(cleanState, [], "Shouldn't have pending changes");
239
+ repo.data.nested = [{ name: "new item", uuid: "asdf" }];
240
+ const dirtyState = repo.status();
241
+ t.equal(dirtyState.length, 1, "Status doesn't contain changes");
242
+ });
243
+ t.test("change of nested array element prop", async (t) => {
244
+ const [repo] = await getBaseline();
245
+ repo.data.name = "new name";
246
+ addOneStep(repo.data);
247
+ await repo.commit("baseline", testAuthor);
248
+ const cleanState = repo.status();
249
+ t.match(cleanState, [], "Shouldn't have pending changes");
250
+ repo.data.nested[0].name = "another name which is different";
251
+ const dirtyState = repo.status();
252
+ t.equal(dirtyState?.length, 1, "Status doesn't contain changes");
253
+ });
254
+ });
255
+
256
+ test("apply", async (t) => {
257
+ t.test("single patch", async (t) => {
258
+ const [repo] = await getBaseline({ name: "base name" });
259
+ const cleanState = repo.status();
260
+ t.match(cleanState, [], "Shouldn't have pending changes");
261
+
262
+ const targetState = {
263
+ uuid: undefined,
264
+ name: "a name",
265
+ description: undefined,
266
+ nested: [{ name: "new item", uuid: "asdf" }],
267
+ };
268
+ const patches = compare(repo.data, targetState);
269
+ // this should record changes on the observer
270
+ const err = repo.apply(patches);
271
+ t.match(err, undefined, "Failed to apply patch");
272
+ t.match(repo.data, targetState, "The final state does not match up");
273
+ const dirtyState = repo.status();
274
+ t.equal(dirtyState.length, 2, "Status doesn't contain changes");
275
+ t.match(dirtyState, patches, "It should have the right changes");
276
+ });
277
+
278
+ t.test(
279
+ "patch for undefined props doesn't work as expected https://github.com/Starcounter-Jack/JSON-Patch/issues/280",
280
+ async (t) => {
281
+ const [repo] = await getBaseline();
282
+ const cleanState = repo.status();
283
+ t.match(cleanState, [], "Shouldn't have pending changes");
284
+
285
+ const targetState: ComplexObject = {
286
+ uuid: undefined,
287
+ description: undefined,
288
+ name: "a name",
289
+ nested: [],
290
+ };
291
+ const patches = compare(repo.data, targetState);
292
+ // this should record changes on the observer
293
+ const err = repo.apply(patches);
294
+ t.match(
295
+ err,
296
+ {
297
+ name: "OPERATION_PATH_UNRESOLVABLE",
298
+ operation: {
299
+ op: "replace",
300
+ path: "/name",
301
+ value: "a name",
302
+ },
303
+ },
304
+ "Failed to apply patch",
305
+ );
306
+ t.notMatch(
307
+ repo.data,
308
+ targetState,
309
+ "The final state shoould not match up, because patch failed",
310
+ );
311
+ const dirtyState = repo.status();
312
+ t.equal(dirtyState.length, 0, "Status doesn't contain changes");
313
+ },
314
+ );
315
+
316
+ t.test("multiple patches", async (t) => {
317
+ const [repo] = await getBaseline({ name: "base name" });
318
+
319
+ const cleanState = repo.status();
320
+ t.match(cleanState, [], "Shouldn't have pending changes");
321
+ const targetState = {
322
+ uuid: undefined,
323
+ name: "a name",
324
+ description: undefined,
325
+ nested: [{ name: "new item", uuid: "asdf" }],
326
+ };
327
+ const patches = compare(repo.data, targetState);
328
+ const err = repo.apply(patches);
329
+ t.equal(err, undefined, "Failed to apply patch");
330
+ const dirtyState = repo.status();
331
+ t.equal(dirtyState?.length, 2, "Status doesn't contain changes");
332
+ t.match(dirtyState, patches, "It should have the right changes");
333
+ t.match(repo.data, targetState, "The final state does not match up");
334
+ });
335
+ });