@dotinc/ogre 0.4.0 → 0.5.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 (46) hide show
  1. package/.tap/processinfo/0799a6bd-022f-41d1-8be9-6338667041c0.json +245 -0
  2. package/.tap/processinfo/4cdc23d3-f7ce-4075-922f-722bf0d687fc.json +245 -0
  3. package/.tap/processinfo/6d907291-2f1e-4670-b04c-3a667271c352.json +245 -0
  4. package/.tap/processinfo/7dc6b1af-ac78-47bc-9b62-630e387e8755.json +245 -0
  5. package/.tap/processinfo/8c48e5e9-6eca-4afe-a7b5-04e26b765d29.json +241 -0
  6. package/.tap/processinfo/8ca695ae-d038-441a-b4ab-2a242d22d416.json +245 -0
  7. package/.tap/processinfo/98475c49-5ee5-4c2c-b8e2-85bd2af528c9.json +245 -0
  8. package/.tap/test-results/src/branch.test.ts.tap +40 -0
  9. package/.tap/test-results/src/checkout.test.ts.tap +52 -0
  10. package/.tap/test-results/src/commit.test.ts.tap +105 -0
  11. package/.tap/test-results/src/merge.test.ts.tap +16 -0
  12. package/.tap/test-results/src/repository.test.ts.tap +63 -0
  13. package/.tap/test-results/src/tag.test.ts.tap +19 -0
  14. package/.tap/test-results/src/utils.test.ts.tap +43 -0
  15. package/CHANGELOG.md +34 -1
  16. package/README.md +6 -4
  17. package/lib/commit.d.ts +0 -0
  18. package/lib/commit.js +0 -0
  19. package/lib/git2json.d.ts +0 -0
  20. package/lib/git2json.js +0 -0
  21. package/lib/hash.d.ts +0 -0
  22. package/lib/hash.js +0 -0
  23. package/lib/index.d.ts +0 -0
  24. package/lib/index.js +0 -0
  25. package/lib/interfaces.d.ts +0 -0
  26. package/lib/interfaces.js +0 -0
  27. package/lib/ref.d.ts +0 -0
  28. package/lib/ref.js +0 -0
  29. package/lib/repository.d.ts +7 -0
  30. package/lib/repository.js +32 -0
  31. package/lib/size.d.ts +0 -0
  32. package/lib/size.js +0 -0
  33. package/lib/test.utils.d.ts +9 -9
  34. package/lib/test.utils.js +8 -12
  35. package/lib/utils.d.ts +0 -0
  36. package/lib/utils.js +0 -0
  37. package/package.json +8 -20
  38. package/src/branch.test.ts +17 -17
  39. package/src/checkout.test.ts +29 -26
  40. package/src/commit.test.ts +60 -69
  41. package/src/merge.test.ts +13 -9
  42. package/src/repository.test.ts +160 -82
  43. package/src/repository.ts +63 -10
  44. package/src/tag.test.ts +6 -6
  45. package/src/test.utils.ts +18 -13
  46. package/src/utils.test.ts +21 -14
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # ogre
2
2
 
3
3
  An in-memory git-like repository for objects for when you need to
4
- keep the history around for a bit longer.
4
+ keep the history around for a bit longer. The library uses json-patch RFC6902 for representing diffs.
5
5
 
6
6
  ## Features
7
7
 
@@ -9,9 +9,11 @@ keep the history around for a bit longer.
9
9
  - Branch
10
10
  - Tags
11
11
  - Checkout
12
+ - Reset (soft and hard)
13
+ - Diff
12
14
  - Visualization via `@dotinc/ogre-react`
13
15
  - Merge
14
- - fast-forward
16
+ - fast-forward
15
17
 
16
18
  ## Usage
17
19
 
@@ -49,5 +51,5 @@ repo.checkout(init);
49
51
  ## TODO
50
52
 
51
53
  - [ ] Merge
52
- - [ ] recursive
53
- - [ ] octopus
54
+ - [ ] recursive
55
+ - [ ] octopus
package/lib/commit.d.ts CHANGED
File without changes
package/lib/commit.js CHANGED
File without changes
package/lib/git2json.d.ts CHANGED
File without changes
package/lib/git2json.js CHANGED
File without changes
package/lib/hash.d.ts CHANGED
File without changes
package/lib/hash.js CHANGED
File without changes
package/lib/index.d.ts CHANGED
File without changes
package/lib/index.js CHANGED
File without changes
File without changes
package/lib/interfaces.js CHANGED
File without changes
package/lib/ref.d.ts CHANGED
File without changes
package/lib/ref.js CHANGED
File without changes
@@ -32,6 +32,12 @@ export interface RepositoryObject<T extends {
32
32
  */
33
33
  branch(): string;
34
34
  tag(tag: string): string;
35
+ /**
36
+ * Moves the HEAD and the branch to a specific shaish (commit or tag)
37
+ * @param mode hard - discard changes
38
+ * @param shaish
39
+ */
40
+ reset(mode?: "soft" | "hard", shaish?: string): void;
35
41
  }
36
42
  /**
37
43
  * A repository recording and managing the state transitions of an object
@@ -46,6 +52,7 @@ export declare class Repository<T extends {
46
52
  private readonly refs;
47
53
  private readonly commits;
48
54
  private moveTo;
55
+ reset(mode?: "soft" | "hard" | undefined, shaish?: string | undefined): void;
49
56
  branch(): string;
50
57
  diff(shaishFrom: string, shaishTo?: string): Operation[];
51
58
  checkout(shaish: string, createBranch?: boolean): void;
package/lib/repository.js CHANGED
@@ -30,6 +30,13 @@ class Repository {
30
30
  ],
31
31
  ]);
32
32
  this.commits = (_d = (_c = options.history) === null || _c === void 0 ? void 0 : _c.commits) !== null && _d !== void 0 ? _d : [];
33
+ if (options.history) {
34
+ const commit = this.commitAtHead();
35
+ if (!commit) {
36
+ return;
37
+ }
38
+ this.moveTo(commit);
39
+ }
33
40
  }
34
41
  moveTo(commit) {
35
42
  const targetTree = treeToObject(commit.tree);
@@ -41,6 +48,22 @@ class Repository {
41
48
  patchToTarget.reduce(fast_json_patch_1.applyReducer, this.data);
42
49
  this.observer = (0, fast_json_patch_1.observe)(this.data);
43
50
  }
51
+ reset(mode = "hard", shaish = exports.REFS_HEAD_KEY) {
52
+ if (mode === "hard") {
53
+ (0, fast_json_patch_1.unobserve)(this.data, this.observer);
54
+ }
55
+ const [commit] = shaishToCommit(shaish, this.refs, this.commits);
56
+ this.moveTo(commit);
57
+ const refs = refsAtCommit(this.refs, commit);
58
+ // reset only moves heads and not tags
59
+ const moveableRefs = refs.filter((r) => r.name.startsWith(headsRefPathPrefix));
60
+ for (const ref of moveableRefs) {
61
+ this.moveRef(ref.name, commit);
62
+ }
63
+ if (mode === "hard") {
64
+ this.observer = (0, fast_json_patch_1.observe)(this.data);
65
+ }
66
+ }
44
67
  branch() {
45
68
  const currentHeadRef = this.refs.get(exports.REFS_HEAD_KEY);
46
69
  if (!currentHeadRef) {
@@ -353,6 +376,15 @@ const commitAtRefIn = (ref, references, commitsList) => {
353
376
  }
354
377
  return undefined;
355
378
  };
379
+ const refsAtCommit = (references, commit) => {
380
+ const list = [];
381
+ for (const [name, ref] of references.entries()) {
382
+ if (ref.value === commit.hash) {
383
+ list.push(ref);
384
+ }
385
+ }
386
+ return list;
387
+ };
356
388
  /**
357
389
  * Accepts a shaish expression (e.g. refs (branches, tags), commitSha) and returns
358
390
  * - a commit of type Commit
package/lib/size.d.ts CHANGED
File without changes
package/lib/size.js CHANGED
File without changes
@@ -1,15 +1,15 @@
1
1
  import { RepositoryObject } from "./repository";
2
2
  import { Commit } from "./commit";
3
- export declare class NestedObject {
4
- name: string | undefined;
5
- uuid: string | undefined;
6
- }
7
- export declare class ComplexObject {
8
- uuid: string | undefined;
9
- name: string | undefined;
10
- description: string | undefined;
3
+ export declare type NestedObject = {
4
+ name?: string;
5
+ uuid?: string;
6
+ };
7
+ export declare type ComplexObject = {
8
+ uuid?: string;
9
+ name?: string;
10
+ description?: string;
11
11
  nested: NestedObject[];
12
- }
12
+ };
13
13
  export declare const testAuthor = "User name <name@domain.com>";
14
14
  export declare function getBaseline(): Promise<[
15
15
  RepositoryObject<ComplexObject>,
package/lib/test.utils.js CHANGED
@@ -1,20 +1,16 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.sumChanges = exports.addOneStep = exports.updateHeaderData = exports.getBaseline = exports.testAuthor = exports.ComplexObject = exports.NestedObject = void 0;
3
+ exports.sumChanges = exports.addOneStep = exports.updateHeaderData = exports.getBaseline = exports.testAuthor = void 0;
4
4
  const uuid_1 = require("uuid");
5
5
  const repository_1 = require("./repository");
6
- class NestedObject {
7
- }
8
- exports.NestedObject = NestedObject;
9
- class ComplexObject {
10
- constructor() {
11
- this.nested = [];
12
- }
13
- }
14
- exports.ComplexObject = ComplexObject;
15
6
  exports.testAuthor = "User name <name@domain.com>";
16
7
  async function getBaseline() {
17
- const co = new ComplexObject();
8
+ const co = {
9
+ uuid: undefined,
10
+ name: undefined,
11
+ description: undefined,
12
+ nested: [],
13
+ };
18
14
  const repo = new repository_1.Repository(co, {});
19
15
  return [repo, co];
20
16
  }
@@ -27,7 +23,7 @@ function updateHeaderData(wrapped) {
27
23
  }
28
24
  exports.updateHeaderData = updateHeaderData;
29
25
  function addOneStep(wrapped) {
30
- const pe = new NestedObject();
26
+ const pe = {};
31
27
  pe.uuid = (0, uuid_1.v4)();
32
28
  pe.name = "first name";
33
29
  wrapped.nested.push(pe);
package/lib/utils.d.ts CHANGED
File without changes
package/lib/utils.js CHANGED
File without changes
package/package.json CHANGED
@@ -4,44 +4,32 @@
4
4
  "type": "git",
5
5
  "url": "https://github.com/dotindustries/ogre.git"
6
6
  },
7
- "version": "0.4.0",
7
+ "version": "0.5.0",
8
8
  "description": "Git-like repository for in-memory object versioning",
9
9
  "private": false,
10
10
  "main": "lib/index.js",
11
11
  "types": "lib/index.d.ts",
12
12
  "scripts": {
13
13
  "build": "tsc -p tsconfig.build.json",
14
- "test": "nyc --reporter=lcov ava",
15
- "test.watch": "ava --watch",
14
+ "test": "nyc --reporter=lcov tap --coverage-report=none --allow-incomplete-coverage",
15
+ "test:node": "node --import tsx --test src/**/*.test.ts",
16
16
  "coverage:html": "nyc report --reporter=html"
17
17
  },
18
- "ava": {
19
- "timeout": "60s",
20
- "files": [
21
- "./src/**/*.test.ts"
22
- ],
23
- "extensions": [
24
- "ts"
25
- ],
26
- "require": [
27
- "ts-node/register"
28
- ]
29
- },
30
18
  "author": "János Veres @nadilas",
31
19
  "license": "MIT",
32
20
  "dependencies": {
33
21
  "fast-json-patch": "^3.1.1",
34
22
  "fflate": "^0.8.2",
35
23
  "immutable-json-patch": "^6.0.1",
36
- "tslib": "^2.3.1"
24
+ "tslib": "^2.6.2"
37
25
  },
38
26
  "devDependencies": {
39
- "@ava/typescript": "^3.0.1",
40
- "@types/node": "^17.0.38",
27
+ "@types/node": "^17.0.45",
41
28
  "@types/uuid": "^8.3.4",
42
- "ava": "^4.3.0",
43
29
  "nyc": "^15.1.0",
30
+ "tap": "^18.7.0",
44
31
  "ts-node": "^10.8.1",
32
+ "tsx": "^4.7.1",
45
33
  "typescript": "^4.7.4",
46
34
  "uuid": "^8.3.2"
47
35
  },
@@ -49,5 +37,5 @@
49
37
  "registry": "https://registry.npmjs.org/",
50
38
  "access": "public"
51
39
  },
52
- "gitHead": "f95719f3f9a333c332fed909e82de60715076a4f"
40
+ "gitHead": "c6bad3ae8bf832cd9f9f9186cd3c37cf96420a46"
53
41
  }
@@ -1,10 +1,10 @@
1
- import test from "ava";
1
+ import { test } from "tap";
2
2
  import { getBaseline, sumChanges, testAuthor } from "./test.utils";
3
3
 
4
4
  test("current branch on empty repo is HEAD", async (t) => {
5
5
  const [repo] = await getBaseline();
6
6
 
7
- t.is(repo.branch(), "HEAD", "invalid current branch");
7
+ t.equal(repo.branch(), "HEAD", "invalid current branch");
8
8
  });
9
9
 
10
10
  test("first commit goes onto default 'main' branch", async (t) => {
@@ -12,18 +12,18 @@ test("first commit goes onto default 'main' branch", async (t) => {
12
12
  repo.data.name = "new name";
13
13
  await repo.commit("initial commit", testAuthor);
14
14
 
15
- t.is(repo.branch(), "main", "invalid current branch");
16
- t.is(repo.head(), "refs/heads/main", "invalid HEAD");
15
+ t.equal(repo.branch(), "main", "invalid current branch");
16
+ t.equal(repo.head(), "refs/heads/main", "invalid HEAD");
17
17
  });
18
18
 
19
19
  test("fails to create a branch with empty repo", async (t) => {
20
20
  const [repo] = await getBaseline();
21
21
  let history = repo.getHistory();
22
- t.is(history.commits.length, 0, "incorrect # of commits");
23
- t.is(
22
+ t.equal(history.commits.length, 0, "incorrect # of commits");
23
+ t.equal(
24
24
  sumChanges(history?.commits),
25
25
  0,
26
- "new branch w/ incorrect # of changelog entries"
26
+ "new branch w/ incorrect # of changelog entries",
27
27
  );
28
28
 
29
29
  t.throws(
@@ -31,7 +31,7 @@ test("fails to create a branch with empty repo", async (t) => {
31
31
  // cannot point new branch to nothing on empty repo
32
32
  repo.createBranch("new_feature");
33
33
  },
34
- { message: "fatal: not a valid object name: 'main'" }
34
+ { message: "fatal: not a valid object name: 'main'" },
35
35
  );
36
36
  });
37
37
 
@@ -39,20 +39,20 @@ test("checkout new branch with empty repo", async (t) => {
39
39
  const [repo] = await getBaseline();
40
40
 
41
41
  repo.checkout("new_feature", true);
42
- t.is(
42
+ t.equal(
43
43
  repo.head(),
44
44
  "refs/heads/new_feature",
45
- "HEAD did not move to new branch"
45
+ "HEAD did not move to new branch",
46
46
  );
47
- t.is(
47
+ t.equal(
48
48
  repo.ref("/refs/heads/main"),
49
49
  undefined,
50
- "main should not be pointing to anything"
50
+ "main should not be pointing to anything",
51
51
  );
52
- t.is(
52
+ t.equal(
53
53
  repo.ref("refs/heads/new_feature"),
54
54
  undefined,
55
- "new_feature should not be pointing to anything"
55
+ "new_feature should not be pointing to anything",
56
56
  );
57
57
  });
58
58
 
@@ -61,8 +61,8 @@ test("creating a valid branch on a baseline", async (t) => {
61
61
  repo.data.name = "new name";
62
62
  const commit = await repo.commit("simple change", testAuthor);
63
63
  const ref = repo.createBranch("new_feature");
64
- t.is(ref, "refs/heads/new_feature", "invalid branch ref created");
65
- t.is(repo.ref(ref), commit, "new branch is pointing to wrong commit");
64
+ t.equal(ref, "refs/heads/new_feature", "invalid branch ref created");
65
+ t.equal(repo.ref(ref), commit, "new branch is pointing to wrong commit");
66
66
  });
67
67
 
68
68
  test("cannot create new branch with invalid name", async (t) => {
@@ -73,7 +73,7 @@ test("cannot create new branch with invalid name", async (t) => {
73
73
  () => {
74
74
  repo.createBranch(name);
75
75
  },
76
- { message: "invalid ref name" }
76
+ { message: "invalid ref name" },
77
77
  );
78
78
  }
79
79
  });
@@ -1,4 +1,4 @@
1
- import test from "ava";
1
+ import { test } from "tap";
2
2
  import {
3
3
  addOneStep,
4
4
  ComplexObject,
@@ -21,14 +21,14 @@ test("checkout prev commit", async (t) => {
21
21
  repo.checkout(headerDataHash);
22
22
  const head = repo.head();
23
23
  const history = repo.getHistory();
24
- t.is(sumChanges(history.commits), 3, `incorrect # of changelog entries`);
25
- t.is(history.commits.length, 1, "incorrect # of commits");
26
- t.is(head, headerDataHash, `points to wrong commit`);
27
- t.is(repo.branch(), "HEAD", "repo is not in detached state");
28
- t.deepEqual(
24
+ t.equal(sumChanges(history.commits), 3, `incorrect # of changelog entries`);
25
+ t.equal(history.commits.length, 1, "incorrect # of commits");
26
+ t.equal(head, headerDataHash, `points to wrong commit`);
27
+ t.equal(repo.branch(), "HEAD", "repo is not in detached state");
28
+ t.equal(
29
29
  obj.nested.length,
30
30
  0,
31
- `has a nested object when it shouldn't: ${JSON.stringify(obj)}`
31
+ `has a nested object when it shouldn't: ${JSON.stringify(obj)}`,
32
32
  );
33
33
  });
34
34
 
@@ -39,7 +39,7 @@ test("checkout new branch with simple name", async (t) => {
39
39
 
40
40
  const ref = repo.createBranch("new_feature");
41
41
  repo.checkout("new_feature");
42
- t.is(repo.head(), ref, "HEAD is not moved to target branch");
42
+ t.equal(repo.head(), ref, "HEAD is not moved to target branch");
43
43
  });
44
44
 
45
45
  test("checkout new branch with full ref name", async (t) => {
@@ -49,7 +49,7 @@ test("checkout new branch with full ref name", async (t) => {
49
49
 
50
50
  const ref = repo.createBranch("new_feature");
51
51
  repo.checkout(ref);
52
- t.is(repo.head(), ref, "HEAD is not moved to target branch");
52
+ t.equal(repo.head(), ref, "HEAD is not moved to target branch");
53
53
  });
54
54
 
55
55
  test("checkout commit which has two refs pointing leaves HEAD detached", async (t) => {
@@ -59,14 +59,14 @@ test("checkout commit which has two refs pointing leaves HEAD detached", async (
59
59
 
60
60
  repo.createBranch("new_feature");
61
61
  repo.checkout(commit);
62
- t.is(repo.ref("refs/heads/main"), commit, "main does not point to commit");
63
- t.is(
62
+ t.equal(repo.ref("refs/heads/main"), commit, "main does not point to commit");
63
+ t.equal(
64
64
  repo.ref("refs/heads/new_feature"),
65
65
  commit,
66
- "new_feature does not point to commit"
66
+ "new_feature does not point to commit",
67
67
  );
68
- t.is(repo.branch(), "HEAD", "HEAD is not detached at commit");
69
- t.is(repo.head(), commit, "HEAD is not pointing to commit");
68
+ t.equal(repo.branch(), "HEAD", "HEAD is not detached at commit");
69
+ t.equal(repo.head(), commit, "HEAD is not pointing to commit");
70
70
  });
71
71
 
72
72
  test("checkout new branch moves head to new branch", async (t) => {
@@ -76,19 +76,19 @@ test("checkout new branch moves head to new branch", async (t) => {
76
76
 
77
77
  const ref = repo.createBranch("new_feature");
78
78
  repo.checkout("new_feature");
79
- t.is(repo.head(), ref, "HEAD is not moved to target branch");
79
+ t.equal(repo.head(), ref, "HEAD is not moved to target branch");
80
80
  });
81
81
 
82
82
  test("checkout and create new branch on empty main", async (t) => {
83
83
  const [repo] = await getBaseline();
84
84
 
85
85
  repo.checkout("new_feature", true);
86
- t.is(
86
+ t.equal(
87
87
  repo.head(),
88
88
  "refs/heads/new_feature",
89
- "HEAD should point to empty branch"
89
+ "HEAD should point to empty branch",
90
90
  );
91
- t.is(repo.branch(), "HEAD", "branch still should be empty");
91
+ t.equal(repo.branch(), "HEAD", "branch still should be empty");
92
92
  });
93
93
 
94
94
  test("checkout and create new branch with at least 1 commit", async (t) => {
@@ -97,29 +97,32 @@ test("checkout and create new branch with at least 1 commit", async (t) => {
97
97
  const commit = await repo.commit("simple change", testAuthor);
98
98
 
99
99
  repo.checkout("new_feature", true);
100
- t.is(
100
+ t.equal(
101
101
  repo.head(),
102
102
  "refs/heads/new_feature",
103
- "HEAD should point to new branch"
103
+ "HEAD should point to new branch",
104
104
  );
105
- t.is(
105
+ t.equal(
106
106
  repo.ref("refs/heads/new_feature"),
107
107
  commit,
108
- "branch is not pointing to last HEAD commit"
108
+ "branch is not pointing to last HEAD commit",
109
109
  );
110
110
  });
111
111
 
112
112
  test("replacing default branch on empty master removes main", async (t) => {
113
- const repo = new Repository(new ComplexObject(), {});
113
+ const cx: ComplexObject = {
114
+ nested: [],
115
+ };
116
+ const repo = new Repository(cx, {});
114
117
 
115
118
  // replacing default main branch by moving HEAD to new branch
116
119
  // is OK even on empty repo
117
120
  repo.checkout("new_feature", true);
118
121
  const history = repo.getHistory();
119
- t.is(
122
+ t.equal(
120
123
  sumChanges(history?.commits),
121
124
  0,
122
- "new branch w/ incorrect # of changelog entries"
125
+ "new branch w/ incorrect # of changelog entries",
123
126
  );
124
127
 
125
128
  repo.data.name = "name changed";
@@ -130,6 +133,6 @@ test("replacing default branch on empty master removes main", async (t) => {
130
133
  () => {
131
134
  repo.checkout("main");
132
135
  },
133
- { message: `pathspec 'main' did not match any known refs` }
136
+ { message: `pathspec 'main' did not match any known refs` },
134
137
  );
135
138
  });