@dotinc/ogre 0.7.0 → 0.8.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 (26) hide show
  1. package/.tap/processinfo/{21e0110c-397c-4c38-a84a-89c55de41e7e.json → 12fba5c1-f3d6-4b95-865b-9251ded2f6e3.json} +7 -6
  2. package/.tap/processinfo/{51b87298-fd44-42a9-b0f8-d4533e58fd1c.json → 38a3e28a-f045-4a32-bfc3-ca756e9457eb.json} +35 -34
  3. package/.tap/processinfo/{d1b618cb-a921-4f1c-ae4a-6bca359b5909.json → 594c45a4-6863-423e-9759-b092527c8ac4.json} +23 -22
  4. package/.tap/processinfo/{36da4059-ca5e-4b70-a993-7f99f94f7588.json → 671766c2-87ab-40cf-8051-2b74d41d0bc5.json} +7 -6
  5. package/.tap/processinfo/{75459f57-2341-476b-8576-587b93699d8b.json → a2952f0b-bb22-4fd6-a729-f9c500431030.json} +7 -6
  6. package/.tap/processinfo/{4aa37d99-4038-4033-9d38-beea00272892.json → cfca41ce-a29e-4cef-9564-b1f52749806b.json} +7 -6
  7. package/.tap/processinfo/{9656a0a0-72ab-4ea7-abb7-7415cd3842b4.json → d116ec0f-f197-434d-8a14-1f09a4b274ea.json} +23 -22
  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 +18 -18
  11. package/.tap/test-results/src/merge.test.ts.tap +2 -2
  12. package/.tap/test-results/src/repository.test.ts.tap +23 -23
  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/git2json.js +3 -4
  17. package/lib/repository.d.ts +1 -18
  18. package/lib/repository.js +39 -196
  19. package/lib/utils.d.ts +55 -0
  20. package/lib/utils.js +183 -2
  21. package/package.json +2 -2
  22. package/src/commit.test.ts +2 -1
  23. package/src/git2json.ts +6 -2
  24. package/src/repository.test.ts +2 -1
  25. package/src/repository.ts +28 -195
  26. package/src/utils.ts +194 -0
@@ -1,6 +1,6 @@
1
1
  import { test } from "tap";
2
2
 
3
- import { printChange, printChangeLog, Repository } from "./repository";
3
+ import { Repository } from "./repository";
4
4
  import {
5
5
  addOneStep,
6
6
  addOneStep as addOneNested,
@@ -12,6 +12,7 @@ import {
12
12
  } from "./test.utils";
13
13
  import { History, Reference } from "./interfaces";
14
14
  import { compare, Operation } from "fast-json-patch";
15
+ import { printChange, printChangeLog } from "./utils";
15
16
 
16
17
  test("diff is ok", async (t) => {
17
18
  const [repo, obj] = await getBaseline();
package/src/repository.ts CHANGED
@@ -1,27 +1,37 @@
1
1
  import {
2
- observe,
3
- unobserve,
4
- compare,
2
+ applyPatch,
5
3
  applyReducer,
4
+ compare,
6
5
  deepClone,
7
6
  generate,
7
+ JsonPatchError,
8
+ observe,
8
9
  Observer,
9
10
  Operation,
11
+ unobserve,
10
12
  validate,
11
- applyPatch,
12
- JsonPatchError,
13
13
  } from "fast-json-patch";
14
14
  import { calculateCommitHash, Commit } from "./commit";
15
15
  import { History, Reference } from "./interfaces";
16
- import { validBranch, validRef } from "./ref";
17
- import { compressSync, decompressSync, strFromU8, strToU8 } from "fflate";
18
-
19
- const tagRefPathPrefix = "refs/tags/";
20
- const headsRefPathPrefix = "refs/heads/";
21
- const headValueRefPrefix = "ref: ";
22
-
23
- export const REFS_HEAD_KEY = "HEAD";
24
- export const REFS_MAIN_KEY = `${headsRefPathPrefix}main`;
16
+ import { compressSync, strToU8 } from "fflate";
17
+ import {
18
+ brancheNameToRef,
19
+ cleanRefValue,
20
+ commitAtRefIn,
21
+ createHeadRefValue,
22
+ getLastRefPathElement,
23
+ headValueRefPrefix,
24
+ localHeadPathPrefix,
25
+ mapPath,
26
+ REFS_HEAD_KEY,
27
+ REFS_MAIN_KEY,
28
+ refsAtCommit,
29
+ shaishToCommit,
30
+ tagToRef,
31
+ treeToObject,
32
+ validateBranchName,
33
+ validateRef,
34
+ } from "./utils";
25
35
 
26
36
  export interface RepositoryOptions<T extends { [k: string]: any }> {
27
37
  history?: History;
@@ -196,7 +206,7 @@ export class Repository<T extends { [k: PropertyKey]: any }>
196
206
  const refs = refsAtCommit(this.refs, commit);
197
207
  // reset only moves heads and not tags
198
208
  const moveableRefs = refs.filter((r) =>
199
- r.name.startsWith(headsRefPathPrefix),
209
+ r.name.startsWith(localHeadPathPrefix()),
200
210
  );
201
211
 
202
212
  for (const ref of moveableRefs) {
@@ -216,7 +226,7 @@ export class Repository<T extends { [k: PropertyKey]: any }>
216
226
 
217
227
  if (currentHeadRef.value.includes(headValueRefPrefix)) {
218
228
  const refName = cleanRefValue(currentHeadRef.value);
219
- if (this.refs.has(refName)) return getLastItem(refName);
229
+ if (this.refs.has(refName)) return getLastRefPathElement(refName);
220
230
  }
221
231
 
222
232
  return REFS_HEAD_KEY; // detached state
@@ -471,7 +481,7 @@ export class Repository<T extends { [k: PropertyKey]: any }>
471
481
  const val =
472
482
  typeof value === "string" ? createHeadRefValue(value) : value.hash;
473
483
  if (!ref) {
474
- ref = { name: getLastItem(refName), value: val };
484
+ ref = { name: getLastRefPathElement(refName), value: val };
475
485
  } else {
476
486
  ref.value = val;
477
487
  }
@@ -486,7 +496,7 @@ export class Repository<T extends { [k: PropertyKey]: any }>
486
496
  throw new Error(`unreachable: HEAD not present`);
487
497
  }
488
498
  throw new Error(
489
- `fatal: not a valid object name: '${getLastItem(headRef)}'`,
499
+ `fatal: not a valid object name: '${getLastRefPathElement(headRef)}'`,
490
500
  );
491
501
  }
492
502
  this.refs.set(refKey, { name: name, value: headCommit.hash });
@@ -516,180 +526,3 @@ export class Repository<T extends { [k: PropertyKey]: any }>
516
526
  return tagRef;
517
527
  }
518
528
  }
519
-
520
- const treeToObject = <T = any>(tree: string): T => {
521
- return JSON.parse(strFromU8(decompressSync(Buffer.from(tree, "base64"))));
522
- };
523
-
524
- const getLastItem = (thePath: string) =>
525
- thePath.substring(thePath.lastIndexOf("/") + 1);
526
-
527
- const mapPath = (
528
- from: Commit,
529
- to: Commit,
530
- commits: Commit[],
531
- ): [isAncestor: boolean] => {
532
- let c: Commit | undefined = to;
533
- while (c !== undefined) {
534
- c = commits.find((parent) => parent.hash === c?.parent);
535
- if (c?.hash === from.hash) {
536
- return [true];
537
- }
538
- }
539
- return [false];
540
- };
541
-
542
- /**
543
- * Returns the commit to which the provided ref is pointing
544
- * @param ref - needs to be in key format, e.g. refs/heads/... or refs/tags/...
545
- * @param references
546
- * @param commitsList
547
- */
548
- const commitAtRefIn = (
549
- ref: string,
550
- references: Map<string, Reference>,
551
- commitsList: Commit[],
552
- ) => {
553
- const reference = references.get(ref);
554
- if (!reference) {
555
- throw new Error(`unreachable: '${ref}' is not present`);
556
- }
557
- let commitHash;
558
- if (reference.value.includes(headValueRefPrefix)) {
559
- const refKey = cleanRefValue(reference.value);
560
- const targetRef = references.get(refKey);
561
- if (!targetRef) {
562
- // target branch may not have been saved yet
563
- return undefined;
564
- }
565
- commitHash = targetRef.value;
566
- } else {
567
- commitHash = reference.value;
568
- }
569
- for (const c of commitsList) {
570
- if (c.hash === commitHash) {
571
- return c;
572
- }
573
- }
574
- return undefined;
575
- };
576
-
577
- const refsAtCommit = (references: Map<string, Reference>, commit: Commit) => {
578
- const list: Array<Reference> = [];
579
- for (const [name, ref] of references.entries()) {
580
- if (ref.value === commit.hash) {
581
- list.push(ref);
582
- }
583
- }
584
- return list;
585
- };
586
-
587
- /**
588
- * Accepts a shaish expression (e.g. refs (branches, tags), commitSha) and returns
589
- * - a commit of type Commit
590
- * - isRef boolean whether it is a direct reference
591
- * - ref the key of the reference
592
- */
593
- const shaishToCommit = (
594
- shaish: string,
595
- references: Map<string, Reference>,
596
- commitsList: Commit[],
597
- ): [commit: Commit, isRef: boolean, ref: string | undefined] => {
598
- let sha = shaish;
599
- let isRef = false;
600
- let refKey: string | undefined = undefined;
601
-
602
- // check for refs
603
- for (const [name, ref] of references.entries()) {
604
- // match on
605
- if (ref.name === shaish || name === shaish) {
606
- isRef = true;
607
- refKey = name;
608
- sha = ref.value;
609
- if (sha.includes(headValueRefPrefix)) {
610
- const cleanedRef = cleanRefValue(sha);
611
- const c = commitAtRefIn(cleanedRef, references, commitsList);
612
- if (!c) {
613
- throw new Error(`${cleanedRef} points to non-existing commit`);
614
- }
615
- return [c, isRef, refKey];
616
- }
617
- break;
618
- }
619
- }
620
- // check for partial sha matches
621
- const found = commitsList.filter((c) => c.hash.indexOf(sha) > -1);
622
- if (found.length === 0) {
623
- throw new Error(`pathspec '${shaish}' did not match any known refs`);
624
- }
625
- // but sha should be specific enough to resolve to 1 commit
626
- if (found.length > 1) {
627
- throw new Error(`commit `);
628
- }
629
- return [found[0], isRef, refKey];
630
- };
631
-
632
- export const createHeadRefValue = (refKey: string) => {
633
- return `${headValueRefPrefix}${refKey}`;
634
- };
635
-
636
- export const isTagRef = (refKey: string) =>
637
- refKey.indexOf(tagRefPathPrefix) > -1;
638
-
639
- export const cleanRefValue = (ref: string) =>
640
- ref.replace(headValueRefPrefix, "");
641
-
642
- export const brancheNameToRef = (name: string) => {
643
- return `${headsRefPathPrefix}${name}`;
644
- };
645
-
646
- export const tagToRef = (tag: string) => {
647
- return `${tagRefPathPrefix}${tag}`;
648
- };
649
-
650
- export const validateBranchName = (name: string) => {
651
- if (!validBranch(name)) {
652
- throw new Error(`invalid ref name`);
653
- }
654
- };
655
-
656
- export const validateRef = (name: string, oneLevel: boolean = true) => {
657
- if (!validRef(name, oneLevel)) {
658
- throw new Error(`invalid ref name`);
659
- }
660
- };
661
-
662
- /**
663
- * Prints the underlying changelog of a repository
664
- * @param repository
665
- */
666
- export const printChangeLog = <T extends { [k: string]: any }>(
667
- repository: RepositoryObject<T>,
668
- ) => {
669
- console.log("----------------------------------------------------------");
670
- console.log("Changelog");
671
- console.log("----------------------------------------------------------");
672
- const history = repository.getHistory();
673
- const head = commitAtRefIn(repository.head(), history.refs, history.commits);
674
- if (!head) {
675
- throw new Error(`fatal: HEAD is not defined`);
676
- }
677
- let c: Commit | undefined = head;
678
- while (c) {
679
- console.log(
680
- `${c.hash} ${refsAtCommit(history.refs, c)
681
- .map((r) => r.name)
682
- .join(" ")}`,
683
- );
684
- for (const chg of c.changes) {
685
- printChange(chg);
686
- }
687
- c = history.commits.find((parent) => parent.hash === c?.parent);
688
- }
689
- console.log("End of changelog");
690
- console.log("----------------------------------------------------------");
691
- };
692
-
693
- export const printChange = (chg: Operation) => {
694
- console.log(` ${JSON.stringify(chg)}`);
695
- };
package/src/utils.ts CHANGED
@@ -1,4 +1,11 @@
1
1
  // [RFC5322](https://www.ietf.org/rfc/rfc5322.txt)
2
+ import { Commit } from "./commit";
3
+ import { Reference } from "./interfaces";
4
+ import { decompressSync, strFromU8 } from "fflate";
5
+ import { validBranch, validRef } from "./ref";
6
+ import { Operation } from "fast-json-patch";
7
+ import { RepositoryObject } from "./repository";
8
+
2
9
  const emailRegex =
3
10
  /(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])/;
4
11
 
@@ -23,3 +30,190 @@ export const cleanAuthor = (author: string): [name: string, email: string] => {
23
30
  // unrecognized format
24
31
  return [author, ""];
25
32
  };
33
+
34
+ export const localRefPrefix = `refs/`;
35
+ export const remoteRefPrefix = `refs/remotes/origin/`;
36
+ export const tagRefPathPrefix = "tags/";
37
+ export const headsRefPathPrefix = "heads/";
38
+ export const headValueRefPrefix = "ref: ";
39
+ export const localHeadPathPrefix = () =>
40
+ `${localRefPrefix}${headsRefPathPrefix}`;
41
+ export const remoteHeadPathPrefix = () =>
42
+ `${remoteRefPrefix}${headsRefPathPrefix}`;
43
+ export const localTagPathPrefix = () => `${localRefPrefix}${tagRefPathPrefix}`;
44
+ export const remoteTagPathPrefix = () =>
45
+ `${remoteRefPrefix}${tagRefPathPrefix}`;
46
+ export const REFS_HEAD_KEY = "HEAD";
47
+ /**
48
+ * Should only be used in local context
49
+ */
50
+ export const REFS_MAIN_KEY = `${localHeadPathPrefix()}main`;
51
+ export const treeToObject = <T = any>(tree: string): T => {
52
+ return JSON.parse(strFromU8(decompressSync(Buffer.from(tree, "base64"))));
53
+ };
54
+ export const mapPath = (
55
+ from: Commit,
56
+ to: Commit,
57
+ commits: Commit[],
58
+ ): [isAncestor: boolean] => {
59
+ let c: Commit | undefined = to;
60
+ while (c !== undefined) {
61
+ c = commits.find((parent) => parent.hash === c?.parent);
62
+ if (c?.hash === from.hash) {
63
+ return [true];
64
+ }
65
+ }
66
+ return [false];
67
+ };
68
+ /**
69
+ * Returns the commit to which the provided ref is pointing
70
+ * @param ref - needs to be in key format, e.g. refs/heads/... or refs/tags/...
71
+ * @param references
72
+ * @param commitsList
73
+ */
74
+ export const commitAtRefIn = (
75
+ ref: string,
76
+ references: Map<string, Reference>,
77
+ commitsList: Commit[],
78
+ ) => {
79
+ const reference = references.get(ref);
80
+ if (!reference) {
81
+ throw new Error(`unreachable: '${ref}' is not present`);
82
+ }
83
+ let commitHash;
84
+ if (reference.value.includes(headValueRefPrefix)) {
85
+ const refKey = cleanRefValue(reference.value);
86
+ const targetRef = references.get(refKey);
87
+ if (!targetRef) {
88
+ // target branch may not have been saved yet
89
+ return undefined;
90
+ }
91
+ commitHash = targetRef.value;
92
+ } else {
93
+ commitHash = reference.value;
94
+ }
95
+ for (const c of commitsList) {
96
+ if (c.hash === commitHash) {
97
+ return c;
98
+ }
99
+ }
100
+ return undefined;
101
+ };
102
+ export const refsAtCommit = (
103
+ references: Map<string, Reference>,
104
+ commit: Commit,
105
+ ) => {
106
+ const list: Array<Reference> = [];
107
+ for (const [name, ref] of references.entries()) {
108
+ if (ref.value === commit.hash) {
109
+ list.push(ref);
110
+ }
111
+ }
112
+ return list;
113
+ };
114
+ /**
115
+ * Accepts a shaish expression (e.g. refs (branches, tags), commitSha) and returns
116
+ * - a commit of type Commit
117
+ * - isRef boolean whether it is a direct reference
118
+ * - ref the key of the reference
119
+ */
120
+ export const shaishToCommit = (
121
+ shaish: string,
122
+ references: Map<string, Reference>,
123
+ commitsList: Commit[],
124
+ ): [commit: Commit, isRef: boolean, ref: string | undefined] => {
125
+ let sha = shaish;
126
+ let isRef = false;
127
+ let refKey: string | undefined = undefined;
128
+
129
+ // check for refs
130
+ for (const [name, ref] of references.entries()) {
131
+ // match on
132
+ if (ref.name === shaish || name === shaish) {
133
+ isRef = true;
134
+ refKey = name;
135
+ sha = ref.value;
136
+ if (sha.includes(headValueRefPrefix)) {
137
+ const cleanedRef = cleanRefValue(sha);
138
+ const c = commitAtRefIn(cleanedRef, references, commitsList);
139
+ if (!c) {
140
+ throw new Error(`${cleanedRef} points to non-existing commit`);
141
+ }
142
+ return [c, isRef, refKey];
143
+ }
144
+ break;
145
+ }
146
+ }
147
+ // check for partial sha matches
148
+ const found = commitsList.filter((c) => c.hash.indexOf(sha) > -1);
149
+ if (found.length === 0) {
150
+ throw new Error(`pathspec '${shaish}' did not match any known refs`);
151
+ }
152
+ // but sha should be specific enough to resolve to 1 commit
153
+ if (found.length > 1) {
154
+ throw new Error(`commit `);
155
+ }
156
+ return [found[0], isRef, refKey];
157
+ };
158
+ export const createHeadRefValue = (refKey: string) => {
159
+ return `${headValueRefPrefix}${refKey}`;
160
+ };
161
+ export const isTagRef = (refKey: string) =>
162
+ refKey.indexOf(localTagPathPrefix()) > -1;
163
+ export const cleanRefValue = (ref: string) =>
164
+ ref.replace(headValueRefPrefix, "");
165
+ export const brancheNameToRef = (name: string) => {
166
+ return `${localHeadPathPrefix()}${name}`;
167
+ };
168
+ export const tagToRef = (tag: string) => {
169
+ return `${localTagPathPrefix()}${tag}`;
170
+ };
171
+ export const validateBranchName = (name: string) => {
172
+ if (!validBranch(name)) {
173
+ throw new Error(`invalid ref name`);
174
+ }
175
+ };
176
+ export const validateRef = (name: string, oneLevel: boolean = true) => {
177
+ if (!validRef(name, oneLevel)) {
178
+ throw new Error(`invalid ref name`);
179
+ }
180
+ };
181
+ /**
182
+ * Prints the underlying changelog of a repository
183
+ * @param repository
184
+ */
185
+ export const printChangeLog = <T extends { [k: string]: any }>(
186
+ repository: RepositoryObject<T>,
187
+ ) => {
188
+ console.log("----------------------------------------------------------");
189
+ console.log("Changelog");
190
+ console.log("----------------------------------------------------------");
191
+ const history = repository.getHistory();
192
+ const head = commitAtRefIn(repository.head(), history.refs, history.commits);
193
+ if (!head) {
194
+ throw new Error(`fatal: HEAD is not defined`);
195
+ }
196
+ let c: Commit | undefined = head;
197
+ while (c) {
198
+ console.log(
199
+ `${c.hash} ${refsAtCommit(history.refs, c)
200
+ .map((r) => r.name)
201
+ .join(" ")}`,
202
+ );
203
+ for (const chg of c.changes) {
204
+ printChange(chg);
205
+ }
206
+ c = history.commits.find((parent) => parent.hash === c?.parent);
207
+ }
208
+ console.log("End of changelog");
209
+ console.log("----------------------------------------------------------");
210
+ };
211
+ export const printChange = (chg: Operation) => {
212
+ console.log(` ${JSON.stringify(chg)}`);
213
+ };
214
+ /**
215
+ * Should be called with a `/` delimited ref path. E.g. refs/heads/main
216
+ * @param thePath
217
+ */
218
+ export const getLastRefPathElement = (thePath: string) =>
219
+ thePath.substring(thePath.lastIndexOf("/") + 1);