Remove git adresses for trees, blobs, and entries (#877)
In #873 I removed the data types for trees, blobs, and entries, but neglected to remove the address related code. This commit corrects that mistake. Some test cases in other modules have been removed because the failure is now structurally impossible, e.g. it is not possible that we would provide a non-commit address to the GitHub plugin, because non-commit addresses do not exist. Test plan: `yarn test --full` passes.
This commit is contained in:
parent
1dd8b7bcb7
commit
5348fe68bf
|
@ -1,64 +1,5 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`plugins/git/edges createEdge works for "becomes" 1`] = `
|
||||
Object {
|
||||
"addressParts": Array [
|
||||
"sourcecred",
|
||||
"git",
|
||||
"BECOMES",
|
||||
"3",
|
||||
"TREE_ENTRY",
|
||||
"de07d6d2b2977734cf39d2b9aff4135eefce3eb7",
|
||||
"old_science.txt",
|
||||
"3",
|
||||
"TREE_ENTRY",
|
||||
"7be3ecfee5314ffa9b2d93fc4377792b2d6d70ed",
|
||||
"science.txt",
|
||||
],
|
||||
"dstParts": Array [
|
||||
"sourcecred",
|
||||
"git",
|
||||
"TREE_ENTRY",
|
||||
"7be3ecfee5314ffa9b2d93fc4377792b2d6d70ed",
|
||||
"science.txt",
|
||||
],
|
||||
"srcParts": Array [
|
||||
"sourcecred",
|
||||
"git",
|
||||
"TREE_ENTRY",
|
||||
"de07d6d2b2977734cf39d2b9aff4135eefce3eb7",
|
||||
"old_science.txt",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`plugins/git/edges createEdge works for "hasContents" 1`] = `
|
||||
Object {
|
||||
"addressParts": Array [
|
||||
"sourcecred",
|
||||
"git",
|
||||
"HAS_CONTENTS",
|
||||
"3",
|
||||
"TREE_ENTRY",
|
||||
"7be3ecfee5314ffa9b2d93fc4377792b2d6d70ed",
|
||||
"science.txt",
|
||||
],
|
||||
"dstParts": Array [
|
||||
"sourcecred",
|
||||
"git",
|
||||
"BLOB",
|
||||
"f1f2514ca6d7a6a1a0511957021b1995bf9ace1c",
|
||||
],
|
||||
"srcParts": Array [
|
||||
"sourcecred",
|
||||
"git",
|
||||
"TREE_ENTRY",
|
||||
"7be3ecfee5314ffa9b2d93fc4377792b2d6d70ed",
|
||||
"science.txt",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`plugins/git/edges createEdge works for "hasParent" 1`] = `
|
||||
Object {
|
||||
"addressParts": Array [
|
||||
|
@ -86,55 +27,3 @@ Object {
|
|||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`plugins/git/edges createEdge works for "hasTree" 1`] = `
|
||||
Object {
|
||||
"addressParts": Array [
|
||||
"sourcecred",
|
||||
"git",
|
||||
"HAS_TREE",
|
||||
"2",
|
||||
"COMMIT",
|
||||
"3715ddfb8d4c4fd2a6f6af75488c82f84c92ec2f",
|
||||
],
|
||||
"dstParts": Array [
|
||||
"sourcecred",
|
||||
"git",
|
||||
"TREE",
|
||||
"7be3ecfee5314ffa9b2d93fc4377792b2d6d70ed",
|
||||
],
|
||||
"srcParts": Array [
|
||||
"sourcecred",
|
||||
"git",
|
||||
"COMMIT",
|
||||
"3715ddfb8d4c4fd2a6f6af75488c82f84c92ec2f",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`plugins/git/edges createEdge works for "includes" 1`] = `
|
||||
Object {
|
||||
"addressParts": Array [
|
||||
"sourcecred",
|
||||
"git",
|
||||
"INCLUDES",
|
||||
"3",
|
||||
"TREE_ENTRY",
|
||||
"7be3ecfee5314ffa9b2d93fc4377792b2d6d70ed",
|
||||
"science.txt",
|
||||
],
|
||||
"dstParts": Array [
|
||||
"sourcecred",
|
||||
"git",
|
||||
"TREE_ENTRY",
|
||||
"7be3ecfee5314ffa9b2d93fc4377792b2d6d70ed",
|
||||
"science.txt",
|
||||
],
|
||||
"srcParts": Array [
|
||||
"sourcecred",
|
||||
"git",
|
||||
"TREE",
|
||||
"7be3ecfee5314ffa9b2d93fc4377792b2d6d70ed",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
|
|
@ -1,20 +1,5 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`plugins/git/nodes snapshots as expected: blob 1`] = `
|
||||
Object {
|
||||
"address": Array [
|
||||
"sourcecred",
|
||||
"git",
|
||||
"BLOB",
|
||||
"f1f2514ca6d7a6a1a0511957021b1995bf9ace1c",
|
||||
],
|
||||
"structured": Object {
|
||||
"hash": "f1f2514ca6d7a6a1a0511957021b1995bf9ace1c",
|
||||
"type": "BLOB",
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`plugins/git/nodes snapshots as expected: commit 1`] = `
|
||||
Object {
|
||||
"address": Array [
|
||||
|
@ -29,35 +14,3 @@ Object {
|
|||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`plugins/git/nodes snapshots as expected: tree 1`] = `
|
||||
Object {
|
||||
"address": Array [
|
||||
"sourcecred",
|
||||
"git",
|
||||
"TREE",
|
||||
"7be3ecfee5314ffa9b2d93fc4377792b2d6d70ed",
|
||||
],
|
||||
"structured": Object {
|
||||
"hash": "7be3ecfee5314ffa9b2d93fc4377792b2d6d70ed",
|
||||
"type": "TREE",
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`plugins/git/nodes snapshots as expected: treeEntry 1`] = `
|
||||
Object {
|
||||
"address": Array [
|
||||
"sourcecred",
|
||||
"git",
|
||||
"TREE_ENTRY",
|
||||
"7be3ecfee5314ffa9b2d93fc4377792b2d6d70ed",
|
||||
"science.txt",
|
||||
],
|
||||
"structured": Object {
|
||||
"name": "science.txt",
|
||||
"treeHash": "7be3ecfee5314ffa9b2d93fc4377792b2d6d70ed",
|
||||
"type": "TREE_ENTRY",
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
|
|
@ -1,9 +1,3 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`plugins/git/render blob snapshots as expected 1`] = `"blob f1f2514ca6d7a6a1a0511957021b1995bf9ace1c"`;
|
||||
|
||||
exports[`plugins/git/render commit snapshots as expected 1`] = `"commit 3715ddfb8d4c4fd2a6f6af75488c82f84c92ec2f"`;
|
||||
|
||||
exports[`plugins/git/render tree snapshots as expected 1`] = `"tree 7be3ecfee5314ffa9b2d93fc4377792b2d6d70ed"`;
|
||||
|
||||
exports[`plugins/git/render treeEntry snapshots as expected 1`] = `"entry \\"science.txt\\" in tree 7be3ecfee5314ffa9b2d93fc4377792b2d6d70ed"`;
|
||||
|
|
|
@ -23,52 +23,18 @@ function gitEdgeAddress(...parts: string[]): RawAddress {
|
|||
|
||||
export const Prefix = Object.freeze({
|
||||
base: GIT_PREFIX,
|
||||
hasTree: gitEdgeAddress(HAS_TREE_TYPE),
|
||||
hasParent: gitEdgeAddress(HAS_PARENT_TYPE),
|
||||
includes: gitEdgeAddress(INCLUDES_TYPE),
|
||||
becomes: gitEdgeAddress(BECOMES_TYPE),
|
||||
hasContents: gitEdgeAddress(HAS_CONTENTS_TYPE),
|
||||
});
|
||||
|
||||
export type HasTreeAddress = {|
|
||||
type: typeof HAS_TREE_TYPE,
|
||||
commit: GitNode.CommitAddress,
|
||||
|};
|
||||
export type HasParentAddress = {|
|
||||
type: typeof HAS_PARENT_TYPE,
|
||||
child: GitNode.CommitAddress,
|
||||
parent: GitNode.CommitAddress,
|
||||
|};
|
||||
export type IncludesAddress = {|
|
||||
type: typeof INCLUDES_TYPE,
|
||||
treeEntry: GitNode.TreeEntryAddress,
|
||||
|};
|
||||
export type BecomesAddress = {|
|
||||
type: typeof BECOMES_TYPE,
|
||||
was: GitNode.TreeEntryAddress,
|
||||
becomes: GitNode.TreeEntryAddress,
|
||||
|};
|
||||
export type HasContentsAddress = {|
|
||||
type: typeof HAS_CONTENTS_TYPE,
|
||||
treeEntry: GitNode.TreeEntryAddress,
|
||||
|};
|
||||
|
||||
export type StructuredAddress =
|
||||
| HasTreeAddress
|
||||
| HasParentAddress
|
||||
| IncludesAddress
|
||||
| BecomesAddress
|
||||
| HasContentsAddress;
|
||||
export type StructuredAddress = HasParentAddress;
|
||||
|
||||
export const createEdge = Object.freeze({
|
||||
hasTree: (
|
||||
commit: GitNode.CommitAddress,
|
||||
tree: GitNode.TreeAddress
|
||||
): Edge => ({
|
||||
address: toRaw({type: HAS_TREE_TYPE, commit}),
|
||||
src: GitNode.toRaw(commit),
|
||||
dst: GitNode.toRaw(tree),
|
||||
}),
|
||||
hasParent: (
|
||||
child: GitNode.CommitAddress,
|
||||
parent: GitNode.CommitAddress
|
||||
|
@ -77,30 +43,6 @@ export const createEdge = Object.freeze({
|
|||
src: GitNode.toRaw(child),
|
||||
dst: GitNode.toRaw(parent),
|
||||
}),
|
||||
includes: (
|
||||
tree: GitNode.TreeAddress,
|
||||
treeEntry: GitNode.TreeEntryAddress
|
||||
): Edge => ({
|
||||
address: toRaw({type: INCLUDES_TYPE, treeEntry}),
|
||||
src: GitNode.toRaw(tree),
|
||||
dst: GitNode.toRaw(treeEntry),
|
||||
}),
|
||||
becomes: (
|
||||
was: GitNode.TreeEntryAddress,
|
||||
becomes: GitNode.TreeEntryAddress
|
||||
): Edge => ({
|
||||
address: toRaw({type: BECOMES_TYPE, was, becomes}),
|
||||
src: GitNode.toRaw(was),
|
||||
dst: GitNode.toRaw(becomes),
|
||||
}),
|
||||
hasContents: (
|
||||
treeEntry: GitNode.TreeEntryAddress,
|
||||
contents: GitNode.TreeEntryContentsAddress
|
||||
): Edge => ({
|
||||
address: toRaw({type: HAS_CONTENTS_TYPE, treeEntry}),
|
||||
src: GitNode.toRaw(treeEntry),
|
||||
dst: GitNode.toRaw(contents),
|
||||
}),
|
||||
});
|
||||
|
||||
const NODE_PREFIX_LENGTH = NodeAddress.toParts(GitNode._gitAddress()).length;
|
||||
|
@ -149,15 +91,6 @@ export function fromRaw(x: RawAddress): StructuredAddress {
|
|||
const [_unused_sc, _unused_git, _type, ...rest] = EdgeAddress.toParts(x);
|
||||
const type: $ElementType<StructuredAddress, "type"> = (_type: any);
|
||||
switch (type) {
|
||||
case "HAS_TREE": {
|
||||
const parts = multiLengthDecode(rest, fail);
|
||||
if (parts.length !== 1) throw fail();
|
||||
const [commitParts] = parts;
|
||||
const commit: GitNode.CommitAddress = (GitNode.fromRaw(
|
||||
GitNode._gitAddress(...commitParts)
|
||||
): any);
|
||||
return {type: HAS_TREE_TYPE, commit};
|
||||
}
|
||||
case "HAS_PARENT": {
|
||||
const parts = multiLengthDecode(rest, fail);
|
||||
if (parts.length !== 2) throw fail();
|
||||
|
@ -170,36 +103,6 @@ export function fromRaw(x: RawAddress): StructuredAddress {
|
|||
): any);
|
||||
return {type: HAS_PARENT_TYPE, child, parent};
|
||||
}
|
||||
case "INCLUDES": {
|
||||
const parts = multiLengthDecode(rest, fail);
|
||||
if (parts.length !== 1) throw fail();
|
||||
const [treeEntryParts] = parts;
|
||||
const treeEntry: GitNode.TreeEntryAddress = (GitNode.fromRaw(
|
||||
GitNode._gitAddress(...treeEntryParts)
|
||||
): any);
|
||||
return {type: INCLUDES_TYPE, treeEntry};
|
||||
}
|
||||
case "BECOMES": {
|
||||
const parts = multiLengthDecode(rest, fail);
|
||||
if (parts.length !== 2) throw fail();
|
||||
const [wasParts, becomesParts] = parts;
|
||||
const was: GitNode.TreeEntryAddress = (GitNode.fromRaw(
|
||||
GitNode._gitAddress(...wasParts)
|
||||
): any);
|
||||
const becomes: GitNode.TreeEntryAddress = (GitNode.fromRaw(
|
||||
GitNode._gitAddress(...becomesParts)
|
||||
): any);
|
||||
return {type: BECOMES_TYPE, was, becomes};
|
||||
}
|
||||
case "HAS_CONTENTS": {
|
||||
const parts = multiLengthDecode(rest, fail);
|
||||
if (parts.length !== 1) throw fail();
|
||||
const [treeEntryParts] = parts;
|
||||
const treeEntry: GitNode.TreeEntryAddress = (GitNode.fromRaw(
|
||||
GitNode._gitAddress(...treeEntryParts)
|
||||
): any);
|
||||
return {type: HAS_CONTENTS_TYPE, treeEntry};
|
||||
}
|
||||
default:
|
||||
// eslint-disable-next-line no-unused-expressions
|
||||
(type: empty);
|
||||
|
@ -209,33 +112,12 @@ export function fromRaw(x: RawAddress): StructuredAddress {
|
|||
|
||||
export function toRaw(x: StructuredAddress): RawAddress {
|
||||
switch (x.type) {
|
||||
case HAS_TREE_TYPE:
|
||||
return EdgeAddress.append(
|
||||
Prefix.hasTree,
|
||||
...lengthEncode(GitNode.toRaw(x.commit))
|
||||
);
|
||||
case HAS_PARENT_TYPE:
|
||||
return EdgeAddress.append(
|
||||
Prefix.hasParent,
|
||||
...lengthEncode(GitNode.toRaw(x.child)),
|
||||
...lengthEncode(GitNode.toRaw(x.parent))
|
||||
);
|
||||
case INCLUDES_TYPE:
|
||||
return EdgeAddress.append(
|
||||
Prefix.includes,
|
||||
...lengthEncode(GitNode.toRaw(x.treeEntry))
|
||||
);
|
||||
case BECOMES_TYPE:
|
||||
return EdgeAddress.append(
|
||||
Prefix.becomes,
|
||||
...lengthEncode(GitNode.toRaw(x.was)),
|
||||
...lengthEncode(GitNode.toRaw(x.becomes))
|
||||
);
|
||||
case HAS_CONTENTS_TYPE:
|
||||
return EdgeAddress.append(
|
||||
Prefix.hasContents,
|
||||
...lengthEncode(GitNode.toRaw(x.treeEntry))
|
||||
);
|
||||
default:
|
||||
throw new Error((x.type: empty));
|
||||
}
|
||||
|
|
|
@ -7,10 +7,6 @@ import * as GN from "./nodes";
|
|||
|
||||
describe("plugins/git/edges", () => {
|
||||
const nodeExamples = {
|
||||
blob: (): GN.BlobAddress => ({
|
||||
type: GN.BLOB_TYPE,
|
||||
hash: "f1f2514ca6d7a6a1a0511957021b1995bf9ace1c",
|
||||
}),
|
||||
commit: (): GN.CommitAddress => ({
|
||||
type: GN.COMMIT_TYPE,
|
||||
hash: "3715ddfb8d4c4fd2a6f6af75488c82f84c92ec2f",
|
||||
|
@ -19,33 +15,11 @@ describe("plugins/git/edges", () => {
|
|||
type: GN.COMMIT_TYPE,
|
||||
hash: "69c5aad50eec8f2a0a07c988c3b283a6490eb45b",
|
||||
}),
|
||||
tree: (): GN.TreeAddress => ({
|
||||
type: GN.TREE_TYPE,
|
||||
hash: "7be3ecfee5314ffa9b2d93fc4377792b2d6d70ed",
|
||||
}),
|
||||
treeEntry: (): GN.TreeEntryAddress => ({
|
||||
type: GN.TREE_ENTRY_TYPE,
|
||||
treeHash: "7be3ecfee5314ffa9b2d93fc4377792b2d6d70ed",
|
||||
name: "science.txt",
|
||||
}),
|
||||
oldTreeEntry: (): GN.TreeEntryAddress => ({
|
||||
type: GN.TREE_ENTRY_TYPE,
|
||||
treeHash: "de07d6d2b2977734cf39d2b9aff4135eefce3eb7",
|
||||
name: "old_science.txt",
|
||||
}),
|
||||
};
|
||||
|
||||
const edgeExamples = {
|
||||
hasTree: () =>
|
||||
createEdge.hasTree(nodeExamples.commit(), nodeExamples.tree()),
|
||||
hasParent: () =>
|
||||
createEdge.hasParent(nodeExamples.commit(), nodeExamples.parentCommit()),
|
||||
includes: () =>
|
||||
createEdge.includes(nodeExamples.tree(), nodeExamples.treeEntry()),
|
||||
becomes: () =>
|
||||
createEdge.becomes(nodeExamples.oldTreeEntry(), nodeExamples.treeEntry()),
|
||||
hasContents: () =>
|
||||
createEdge.hasContents(nodeExamples.treeEntry(), nodeExamples.blob()),
|
||||
};
|
||||
|
||||
describe("createEdge", () => {
|
||||
|
|
|
@ -60,18 +60,6 @@ export class GraphView {
|
|||
this._maybeCheckInvariants();
|
||||
}
|
||||
|
||||
tree(commit: GN.CommitAddress): GN.TreeAddress {
|
||||
const result: GN.TreeAddress = Array.from(
|
||||
this._neighbors(commit, {
|
||||
direction: Direction.OUT,
|
||||
nodePrefix: GN.Prefix.tree,
|
||||
edgePrefix: GE.Prefix.hasTree,
|
||||
})
|
||||
)[0];
|
||||
this._maybeCheckInvariants();
|
||||
return result;
|
||||
}
|
||||
|
||||
parents(commit: GN.CommitAddress): Iterator<GN.CommitAddress> {
|
||||
const result: Iterator<GN.CommitAddress> = this._neighbors(commit, {
|
||||
direction: Direction.OUT,
|
||||
|
@ -82,49 +70,6 @@ export class GraphView {
|
|||
return result;
|
||||
}
|
||||
|
||||
entries(tree: GN.TreeAddress): Iterator<GN.TreeEntryAddress> {
|
||||
const result: Iterator<GN.TreeEntryAddress> = this._neighbors(tree, {
|
||||
direction: Direction.OUT,
|
||||
nodePrefix: GN.Prefix.treeEntry,
|
||||
edgePrefix: GE.Prefix.includes,
|
||||
});
|
||||
this._maybeCheckInvariants();
|
||||
return result;
|
||||
}
|
||||
|
||||
contents(entry: GN.TreeEntryAddress): Iterator<GN.TreeEntryContentsAddress> {
|
||||
const result: Iterator<GN.TreeEntryContentsAddress> = this._neighbors(
|
||||
entry,
|
||||
{
|
||||
direction: Direction.OUT,
|
||||
nodePrefix: GN.Prefix.base, // multiple kinds
|
||||
edgePrefix: GE.Prefix.hasContents,
|
||||
}
|
||||
);
|
||||
this._maybeCheckInvariants();
|
||||
return result;
|
||||
}
|
||||
|
||||
evolvesTo(entry: GN.TreeEntryAddress): Iterator<GN.TreeEntryAddress> {
|
||||
const result: Iterator<GN.TreeEntryAddress> = this._neighbors(entry, {
|
||||
direction: Direction.OUT,
|
||||
nodePrefix: GN.Prefix.treeEntry,
|
||||
edgePrefix: GE.Prefix.becomes,
|
||||
});
|
||||
this._maybeCheckInvariants();
|
||||
return result;
|
||||
}
|
||||
|
||||
evolvesFrom(entry: GN.TreeEntryAddress): Iterator<GN.TreeEntryAddress> {
|
||||
const result: Iterator<GN.TreeEntryAddress> = this._neighbors(entry, {
|
||||
direction: Direction.IN,
|
||||
nodePrefix: GN.Prefix.treeEntry,
|
||||
edgePrefix: GE.Prefix.becomes,
|
||||
});
|
||||
this._maybeCheckInvariants();
|
||||
return result;
|
||||
}
|
||||
|
||||
_maybeCheckInvariants() {
|
||||
if (process.env.NODE_ENV === "test") {
|
||||
// TODO(perf): If this method becomes really slow, we can disable
|
||||
|
@ -149,32 +94,10 @@ export class GraphView {
|
|||
|}>,
|
||||
|};
|
||||
const edgeInvariants = {
|
||||
[GE.HAS_TREE_TYPE]: {
|
||||
prefix: GE.Prefix.hasTree,
|
||||
homs: [{srcPrefix: GN.Prefix.commit, dstPrefix: GN.Prefix.tree}],
|
||||
},
|
||||
[GE.HAS_PARENT_TYPE]: {
|
||||
prefix: GE.Prefix.hasParent,
|
||||
homs: [{srcPrefix: GN.Prefix.commit, dstPrefix: GN.Prefix.commit}],
|
||||
},
|
||||
[GE.INCLUDES_TYPE]: {
|
||||
prefix: GE.Prefix.includes,
|
||||
homs: [{srcPrefix: GN.Prefix.tree, dstPrefix: GN.Prefix.treeEntry}],
|
||||
},
|
||||
[GE.BECOMES_TYPE]: {
|
||||
prefix: GE.Prefix.becomes,
|
||||
homs: [
|
||||
{srcPrefix: GN.Prefix.treeEntry, dstPrefix: GN.Prefix.treeEntry},
|
||||
],
|
||||
},
|
||||
[GE.HAS_CONTENTS_TYPE]: {
|
||||
prefix: GE.Prefix.hasContents,
|
||||
homs: [
|
||||
{srcPrefix: GN.Prefix.treeEntry, dstPrefix: GN.Prefix.blob},
|
||||
{srcPrefix: GN.Prefix.treeEntry, dstPrefix: GN.Prefix.tree},
|
||||
{srcPrefix: GN.Prefix.treeEntry, dstPrefix: GN.Prefix.commit},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
for (const edge of this._graph.edges({
|
||||
|
@ -202,30 +125,6 @@ export class GraphView {
|
|||
}
|
||||
}
|
||||
|
||||
// Any HAS_TREE edge to a commit must be properly named. This
|
||||
// implies that a commit has at most one such edge. (Normal commits
|
||||
// should have trees, but submodule commits might not.)
|
||||
for (const rawNode of this._graph.nodes({prefix: GN.Prefix.commit})) {
|
||||
for (const neighbor of this._graph.neighbors(rawNode, {
|
||||
direction: Direction.OUT,
|
||||
nodePrefix: NodeAddress.empty,
|
||||
edgePrefix: GE.Prefix.hasTree,
|
||||
})) {
|
||||
const rawEdge = neighbor.edge;
|
||||
const edge: GE.HasTreeAddress = (GE.fromRaw(
|
||||
(((rawEdge.address: EdgeAddressT): any): GE.RawAddress)
|
||||
): any);
|
||||
const node: GN.CommitAddress = ((GN.fromRaw(
|
||||
(((rawNode: NodeAddressT): any): GN.RawAddress)
|
||||
): GN.StructuredAddress): any);
|
||||
if (node.hash !== edge.commit.hash) {
|
||||
throw new Error(
|
||||
`invariant violation: bad HAS_TREE edge: ${edgeToString(rawEdge)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// All HAS_PARENT edges must map between between the correct commits.
|
||||
for (const edge of this._graph.edges({
|
||||
addressPrefix: GE.Prefix.hasParent,
|
||||
|
@ -245,75 +144,5 @@ export class GraphView {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Each tree entry must have a unique and properly named INCLUDES edge.
|
||||
for (const rawNode of this._graph.nodes({prefix: GN.Prefix.treeEntry})) {
|
||||
const treeNeighbors = Array.from(
|
||||
this._graph.neighbors(rawNode, {
|
||||
direction: Direction.IN,
|
||||
nodePrefix: NodeAddress.empty,
|
||||
edgePrefix: GE.Prefix.includes,
|
||||
})
|
||||
);
|
||||
if (treeNeighbors.length !== 1) {
|
||||
throw new Error(
|
||||
"invariant violation: tree entry should have 1 inclusion, " +
|
||||
`but has ${treeNeighbors.length}: ${NodeAddress.toString(rawNode)}`
|
||||
);
|
||||
}
|
||||
const edge = treeNeighbors[0].edge;
|
||||
const tree: GN.TreeAddress = ((GN.fromRaw(
|
||||
(((edge.src: NodeAddressT): any): GN.RawAddress)
|
||||
): GN.StructuredAddress): any);
|
||||
const treeEntry: GN.TreeEntryAddress = ((GN.fromRaw(
|
||||
(((edge.dst: NodeAddressT): any): GN.RawAddress)
|
||||
): GN.StructuredAddress): any);
|
||||
const expectedEdge = GE.createEdge.includes(tree, treeEntry);
|
||||
if (edge.address !== expectedEdge.address) {
|
||||
throw new Error(
|
||||
`invariant violation: bad INCLUDES edge: ${edgeToString(edge)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// All BECOMES edges must map between between the correct tree entries.
|
||||
for (const edge of this._graph.edges({
|
||||
addressPrefix: GE.Prefix.becomes,
|
||||
srcPrefix: NodeAddress.empty,
|
||||
dstPrefix: NodeAddress.empty,
|
||||
})) {
|
||||
const src: GN.TreeEntryAddress = ((GN.fromRaw(
|
||||
(((edge.src: NodeAddressT): any): GN.RawAddress)
|
||||
): GN.StructuredAddress): any);
|
||||
const dst: GN.TreeEntryAddress = ((GN.fromRaw(
|
||||
(((edge.dst: NodeAddressT): any): GN.RawAddress)
|
||||
): GN.StructuredAddress): any);
|
||||
const expectedEdge = GE.createEdge.becomes(src, dst);
|
||||
if (edge.address !== expectedEdge.address) {
|
||||
throw new Error(
|
||||
`invariant violation: bad BECOMES edge: ${edgeToString(edge)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// All HAS_CONTENTS edges must be properly named.
|
||||
for (const edge of this._graph.edges({
|
||||
addressPrefix: GE.Prefix.hasContents,
|
||||
srcPrefix: NodeAddress.empty,
|
||||
dstPrefix: NodeAddress.empty,
|
||||
})) {
|
||||
const src: GN.TreeEntryAddress = ((GN.fromRaw(
|
||||
(((edge.src: NodeAddressT): any): GN.RawAddress)
|
||||
): GN.StructuredAddress): any);
|
||||
const dst: GN.TreeEntryContentsAddress = ((GN.fromRaw(
|
||||
(((edge.dst: NodeAddressT): any): GN.RawAddress)
|
||||
): GN.StructuredAddress): any);
|
||||
const expectedEdge = GE.createEdge.hasContents(src, dst);
|
||||
if (edge.address !== expectedEdge.address) {
|
||||
throw new Error(
|
||||
`invariant violation: bad HAS_CONTENTS edge: ${edgeToString(edge)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,18 +78,13 @@ describe("plugins/git/graphView", () => {
|
|||
const c3: GN.CommitAddress = {type: GN.COMMIT_TYPE, hash: "c3"};
|
||||
const e2 = GE.createEdge.hasParent(c1, c2);
|
||||
const e3 = GE.createEdge.hasParent(c1, c3);
|
||||
const tree: GN.TreeAddress = {type: GN.TREE_TYPE, hash: "t1"};
|
||||
const foreignNode = NodeAddress.fromParts(["who", "are", "you"]);
|
||||
const baseGraph = () =>
|
||||
new Graph()
|
||||
.addNode(foreignNode)
|
||||
.addNode(GN.toRaw(c1))
|
||||
.addNode(GN.toRaw(c2))
|
||||
.addNode(GN.toRaw(c3))
|
||||
.addNode(GN.toRaw(tree))
|
||||
.addEdge(GE.createEdge.hasTree(c1, tree))
|
||||
.addEdge(GE.createEdge.hasTree(c2, tree))
|
||||
.addEdge(GE.createEdge.hasTree(c3, tree));
|
||||
.addNode(GN.toRaw(c3));
|
||||
it("for proper src", () => {
|
||||
const badEdge = {...e2, src: foreignNode};
|
||||
const g = baseGraph().addEdge(badEdge);
|
||||
|
|
|
@ -10,49 +10,19 @@ export function _gitAddress(...parts: string[]): RawAddress {
|
|||
return NodeAddress.append(GIT_PREFIX, ...parts);
|
||||
}
|
||||
|
||||
export const BLOB_TYPE: "BLOB" = "BLOB";
|
||||
export const COMMIT_TYPE: "COMMIT" = "COMMIT";
|
||||
export const TREE_TYPE: "TREE" = "TREE";
|
||||
export const TREE_ENTRY_TYPE: "TREE_ENTRY" = "TREE_ENTRY";
|
||||
|
||||
export const Prefix = Object.freeze({
|
||||
base: GIT_PREFIX,
|
||||
blob: _gitAddress(BLOB_TYPE),
|
||||
commit: _gitAddress(COMMIT_TYPE),
|
||||
tree: _gitAddress(TREE_TYPE),
|
||||
treeEntry: _gitAddress(TREE_ENTRY_TYPE),
|
||||
});
|
||||
|
||||
export type BlobAddress = {|
|
||||
+type: typeof BLOB_TYPE,
|
||||
+hash: Hash,
|
||||
|};
|
||||
export type CommitAddress = {|
|
||||
+type: typeof COMMIT_TYPE,
|
||||
+hash: Hash,
|
||||
|};
|
||||
export type TreeAddress = {|
|
||||
+type: typeof TREE_TYPE,
|
||||
+hash: Hash,
|
||||
|};
|
||||
export type TreeEntryAddress = {|
|
||||
+type: typeof TREE_ENTRY_TYPE,
|
||||
+treeHash: Hash,
|
||||
+name: string,
|
||||
|};
|
||||
|
||||
// A tree entry has contents with one of the following types of
|
||||
// addresses.
|
||||
export type TreeEntryContentsAddress =
|
||||
| BlobAddress
|
||||
| CommitAddress
|
||||
| TreeAddress;
|
||||
|
||||
export type StructuredAddress =
|
||||
| BlobAddress
|
||||
| CommitAddress
|
||||
| TreeAddress
|
||||
| TreeEntryAddress;
|
||||
export type StructuredAddress = CommitAddress;
|
||||
|
||||
export function fromRaw(x: RawAddress): StructuredAddress {
|
||||
function fail() {
|
||||
|
@ -64,26 +34,11 @@ export function fromRaw(x: RawAddress): StructuredAddress {
|
|||
const [_unused_sc, _unused_git, _type, ...rest] = NodeAddress.toParts(x);
|
||||
const type: $ElementType<StructuredAddress, "type"> = (_type: any);
|
||||
switch (type) {
|
||||
case "BLOB": {
|
||||
if (rest.length !== 1) throw fail();
|
||||
const [hash] = rest;
|
||||
return {type: BLOB_TYPE, hash};
|
||||
}
|
||||
case "COMMIT": {
|
||||
if (rest.length !== 1) throw fail();
|
||||
const [hash] = rest;
|
||||
return {type: COMMIT_TYPE, hash};
|
||||
}
|
||||
case "TREE": {
|
||||
if (rest.length !== 1) throw fail();
|
||||
const [hash] = rest;
|
||||
return {type: TREE_TYPE, hash};
|
||||
}
|
||||
case "TREE_ENTRY": {
|
||||
if (rest.length !== 2) throw fail();
|
||||
const [treeHash, name] = rest;
|
||||
return {type: TREE_ENTRY_TYPE, treeHash, name};
|
||||
}
|
||||
default:
|
||||
// eslint-disable-next-line no-unused-expressions
|
||||
(type: empty);
|
||||
|
@ -93,14 +48,8 @@ export function fromRaw(x: RawAddress): StructuredAddress {
|
|||
|
||||
export function toRaw(x: StructuredAddress): RawAddress {
|
||||
switch (x.type) {
|
||||
case BLOB_TYPE:
|
||||
return NodeAddress.append(Prefix.blob, x.hash);
|
||||
case COMMIT_TYPE:
|
||||
return NodeAddress.append(Prefix.commit, x.hash);
|
||||
case TREE_TYPE:
|
||||
return NodeAddress.append(Prefix.tree, x.hash);
|
||||
case TREE_ENTRY_TYPE:
|
||||
return NodeAddress.append(Prefix.treeEntry, x.treeHash, x.name);
|
||||
default:
|
||||
throw new Error(`Unexpected type ${(x.type: empty)}`);
|
||||
}
|
||||
|
|
|
@ -6,36 +6,18 @@ import {fromRaw, toRaw} from "./nodes";
|
|||
|
||||
describe("plugins/git/nodes", () => {
|
||||
const examples = {
|
||||
blob: (): GN.BlobAddress => ({
|
||||
type: GN.BLOB_TYPE,
|
||||
hash: "f1f2514ca6d7a6a1a0511957021b1995bf9ace1c",
|
||||
}),
|
||||
commit: (): GN.CommitAddress => ({
|
||||
type: GN.COMMIT_TYPE,
|
||||
hash: "3715ddfb8d4c4fd2a6f6af75488c82f84c92ec2f",
|
||||
}),
|
||||
tree: (): GN.TreeAddress => ({
|
||||
type: GN.TREE_TYPE,
|
||||
hash: "7be3ecfee5314ffa9b2d93fc4377792b2d6d70ed",
|
||||
}),
|
||||
treeEntry: (): GN.TreeEntryAddress => ({
|
||||
type: GN.TREE_ENTRY_TYPE,
|
||||
treeHash: "7be3ecfee5314ffa9b2d93fc4377792b2d6d70ed",
|
||||
name: "science.txt",
|
||||
}),
|
||||
};
|
||||
|
||||
// Incorrect types should be caught statically, either due to being
|
||||
// totally invalid...
|
||||
// Incorrect types should be caught statically
|
||||
// $ExpectFlowError
|
||||
const _unused_badTree: GN.RepoAddress = {
|
||||
type: "TREEEEE",
|
||||
hash: "browns",
|
||||
};
|
||||
// ...or due to being annotated with the type of a distinct structured
|
||||
// address:
|
||||
// $ExpectFlowError
|
||||
const _unused_badCommit: GN.CommitAddress = {...examples.tree()};
|
||||
|
||||
describe("`fromRaw` after `toRaw` is identity", () => {
|
||||
Object.keys(examples).forEach((example) => {
|
||||
|
@ -92,38 +74,12 @@ describe("plugins/git/nodes", () => {
|
|||
expectBadAddress("no type", []);
|
||||
expectBadAddress("bad type", ["wat"]);
|
||||
|
||||
expectBadAddress("blob with no hash", [GN.BLOB_TYPE]);
|
||||
expectBadAddress("blob with extra field", [
|
||||
GN.BLOB_TYPE,
|
||||
examples.blob().hash,
|
||||
examples.blob().hash,
|
||||
]);
|
||||
|
||||
expectBadAddress("commit with no hash", [GN.COMMIT_TYPE]);
|
||||
expectBadAddress("commit with extra field", [
|
||||
GN.COMMIT_TYPE,
|
||||
examples.commit().hash,
|
||||
examples.commit().hash,
|
||||
]);
|
||||
|
||||
expectBadAddress("tree with no hash", [GN.TREE_TYPE]);
|
||||
expectBadAddress("tree with extra field", [
|
||||
GN.TREE_TYPE,
|
||||
examples.tree().hash,
|
||||
examples.tree().hash,
|
||||
]);
|
||||
|
||||
expectBadAddress("tree entry with no fields", [GN.TREE_ENTRY_TYPE]);
|
||||
expectBadAddress("tree entry with only tree hash", [
|
||||
GN.TREE_ENTRY_TYPE,
|
||||
examples.treeEntry().treeHash,
|
||||
]);
|
||||
expectBadAddress("tree entry with extra field", [
|
||||
GN.TREE_ENTRY_TYPE,
|
||||
examples.treeEntry().treeHash,
|
||||
examples.treeEntry().name,
|
||||
"wat",
|
||||
]);
|
||||
});
|
||||
|
||||
describe("toRaw(...) with", () => {
|
||||
|
|
|
@ -5,34 +5,12 @@ import {description} from "./render";
|
|||
|
||||
describe("plugins/git/render", () => {
|
||||
const examples = {
|
||||
blob: (): GN.BlobAddress => ({
|
||||
type: GN.BLOB_TYPE,
|
||||
hash: "f1f2514ca6d7a6a1a0511957021b1995bf9ace1c",
|
||||
}),
|
||||
commit: (): GN.CommitAddress => ({
|
||||
type: GN.COMMIT_TYPE,
|
||||
hash: "3715ddfb8d4c4fd2a6f6af75488c82f84c92ec2f",
|
||||
}),
|
||||
tree: (): GN.TreeAddress => ({
|
||||
type: GN.TREE_TYPE,
|
||||
hash: "7be3ecfee5314ffa9b2d93fc4377792b2d6d70ed",
|
||||
}),
|
||||
treeEntry: (): GN.TreeEntryAddress => ({
|
||||
type: GN.TREE_ENTRY_TYPE,
|
||||
treeHash: "7be3ecfee5314ffa9b2d93fc4377792b2d6d70ed",
|
||||
name: "science.txt",
|
||||
}),
|
||||
};
|
||||
it("blob snapshots as expected", () => {
|
||||
expect(description(examples.blob())).toMatchSnapshot();
|
||||
});
|
||||
it("commit snapshots as expected", () => {
|
||||
expect(description(examples.commit())).toMatchSnapshot();
|
||||
});
|
||||
it("tree snapshots as expected", () => {
|
||||
expect(description(examples.tree())).toMatchSnapshot();
|
||||
});
|
||||
it("treeEntry snapshots as expected", () => {
|
||||
expect(description(examples.treeEntry())).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -4,7 +4,7 @@ import {Graph, type Edge, EdgeAddress} from "../../core/graph";
|
|||
import {GraphView} from "./graphView";
|
||||
import * as GE from "./edges";
|
||||
import * as GN from "./nodes";
|
||||
import {COMMIT_TYPE, toRaw as gitToRaw, TREE_TYPE} from "../git/nodes";
|
||||
import {COMMIT_TYPE, toRaw as gitToRaw} from "../git/nodes";
|
||||
import {exampleGraph} from "./example/example";
|
||||
|
||||
function exampleView() {
|
||||
|
@ -265,12 +265,6 @@ describe("plugins/github/graphView", () => {
|
|||
const badEdge = GE.createEdge.mergedAs(issue, commit);
|
||||
failsForEdge(badEdge);
|
||||
});
|
||||
it("dst must be commit address", () => {
|
||||
const tree = {type: TREE_TYPE, hash: "hash"};
|
||||
// $ExpectFlowError
|
||||
const badEdge = GE.createEdge.mergedAs(pull, tree);
|
||||
failsForEdge(badEdge);
|
||||
});
|
||||
it("src must be pull in edge address", () => {
|
||||
const otherPull = {type: "PULL", repo, number: "143"};
|
||||
const mergedAs = GE.createEdge.mergedAs(otherPull, commit);
|
||||
|
|
|
@ -50,10 +50,6 @@ describe("plugins/github/nodes", () => {
|
|||
type: GitNode.COMMIT_TYPE,
|
||||
hash: "0000000000000000000000000000000000000000",
|
||||
});
|
||||
const tree = (): GitNode.TreeAddress => ({
|
||||
type: GitNode.TREE_TYPE,
|
||||
hash: "0000000000000000000000000000000000000000",
|
||||
});
|
||||
|
||||
const examples = {
|
||||
repo,
|
||||
|
@ -150,10 +146,6 @@ describe("plugins/github/nodes", () => {
|
|||
);
|
||||
});
|
||||
expectBadAddress("no kind", []);
|
||||
expectBadAddress(
|
||||
"Git node that isn't a commit",
|
||||
NodeAddress.toParts(GitNode.toRaw(tree()))
|
||||
);
|
||||
describe("repository with", () => {
|
||||
checkBadCases([
|
||||
{name: "no owner", parts: [GN.REPO_TYPE]},
|
||||
|
@ -250,12 +242,6 @@ describe("plugins/github/nodes", () => {
|
|||
toRaw({type: "COMMENT", parent: {type: "ICE_CREAM"}});
|
||||
}).toThrow("Bad comment parent type");
|
||||
});
|
||||
it("a git address that isn't a commit", () => {
|
||||
expect(() => {
|
||||
// $ExpectFlowError
|
||||
toRaw(tree());
|
||||
}).toThrow("Unexpected type");
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue