Skip to content

Commit daceb5a

Browse files
committed
feat(data-point-tracers): add mermaid support
closes ViacomInc#419
1 parent e8065cd commit daceb5a

File tree

5 files changed

+223
-0
lines changed

5 files changed

+223
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/* eslint-disable */
2+
3+
const path = require("path");
4+
5+
const DataPoint = require("@data-point/core");
6+
const DPModel = require("@data-point/core/model");
7+
const DPIfThenElse = require("@data-point/core/ifThenElse");
8+
const DPMap = require("@data-point/core/map");
9+
10+
const DPMermaidTracer = require("@data-point/tracers/mermaid");
11+
12+
const myModel = DPModel({
13+
name: "myModel",
14+
15+
uid: acc => `${acc.reducer.id}${acc.value.a.b}`,
16+
17+
value: [
18+
"$a.b",
19+
input => input.toUpperCase(),
20+
DPIfThenElse({
21+
if: input => input === "FOO",
22+
then: () => {
23+
// return "yes foo!!";
24+
throw new Error("ohh");
25+
},
26+
else: input => `foo no! got ${input}`
27+
})
28+
],
29+
30+
catch(acc) {
31+
return "its all ok";
32+
}
33+
});
34+
35+
async function main() {
36+
const datapoint = DataPoint();
37+
38+
const input = [
39+
{
40+
a: {
41+
b: "foo"
42+
}
43+
},
44+
{
45+
a: {
46+
b: "bar"
47+
}
48+
},
49+
{
50+
a: {
51+
b: "baz"
52+
}
53+
}
54+
];
55+
56+
const tracer = DPMermaidTracer();
57+
58+
result = await datapoint.resolve(input, DPMap(myModel), {
59+
tracer
60+
});
61+
62+
// save to disk
63+
tracer.report(path.join(__dirname, "datapoint-trace-example.mermaid"));
64+
}
65+
66+
main();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"name": "@data-point/mermaid-example",
3+
"main": "mermaid-example.js",
4+
"private": true,
5+
"version": "1.0.0",
6+
"devDependencies": {
7+
"@data-point/core": "^6.0.0",
8+
"@data-point/tracers": "^1.0.0"
9+
}
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = require("./mermaid").Mermaid.create;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
const fs = require("fs").promises;
2+
3+
function getParent(span) {
4+
return span.root ? "root" : span.parent;
5+
}
6+
7+
function getName(span) {
8+
return span === "root" ? "root" : `${span.name}${span.context.pid}`;
9+
}
10+
11+
function graphTD(spans) {
12+
const nodes = spans.map(span => {
13+
return ` ${getName(getParent(span))}-->${getName(span)}`;
14+
});
15+
16+
return `graph TD;\n${nodes.join("\n")}`;
17+
}
18+
19+
class Mermaid {
20+
constructor() {
21+
this.spans = [];
22+
}
23+
24+
static create() {
25+
return new Mermaid();
26+
}
27+
28+
start(dpSpan) {
29+
this.spans.push(dpSpan);
30+
}
31+
32+
async report(destinationPath) {
33+
const report = graphTD(this.spans);
34+
35+
if (destinationPath) {
36+
await fs.writeFile(destinationPath, report);
37+
}
38+
39+
return report;
40+
}
41+
}
42+
43+
module.exports = {
44+
getParent,
45+
getName,
46+
graphTD,
47+
Mermaid
48+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
const fs = require("fs").promises;
2+
const { getParent, getName, graphTD, Mermaid } = require("./mermaid");
3+
4+
function createChildSpan(name, pid, parent) {
5+
return {
6+
name,
7+
parent,
8+
context: {
9+
pid
10+
}
11+
};
12+
}
13+
14+
function createSampleSpans() {
15+
const aa = createChildSpan("aa", 1);
16+
aa.root = true;
17+
const bb = createChildSpan("bb", 2, aa);
18+
const cc = createChildSpan("cc", 3, aa);
19+
const dd = createChildSpan("dd", 4, bb);
20+
21+
const spans = [aa, bb, cc, dd];
22+
23+
return spans;
24+
}
25+
26+
const graphResult = `graph TD;
27+
root-->aa1
28+
aa1-->bb2
29+
aa1-->cc3
30+
bb2-->dd4`;
31+
32+
describe("getParent", () => {
33+
it("should return `root` if root flag is true", () => {
34+
expect(getParent({ root: true })).toEqual("root");
35+
});
36+
it("should return parent if root flag not true", () => {
37+
expect(getParent({ parent: "parent" })).toEqual("parent");
38+
});
39+
});
40+
41+
describe("getName", () => {
42+
it("should return 'root' if span is root", () => {
43+
expect(getName("root")).toEqual("root");
44+
});
45+
it("should return constructed name if span is not root", () => {
46+
const span = createChildSpan("name", 1);
47+
expect(getName(span)).toEqual("name1");
48+
});
49+
});
50+
51+
describe("graphTD", () => {
52+
it("should create graph tree", () => {
53+
const result = graphTD(createSampleSpans());
54+
expect(result).toEqual(graphResult);
55+
});
56+
});
57+
58+
describe("Mermaid", () => {
59+
describe("constructor", () => {
60+
it("should create spans array", () => {
61+
const result = new Mermaid();
62+
expect(result).toHaveProperty("spans", []);
63+
});
64+
});
65+
66+
describe("create", () => {
67+
it("should have static method to create new instance", () => {
68+
const result = Mermaid.create();
69+
expect(result).toBeInstanceOf(Mermaid);
70+
});
71+
});
72+
73+
describe("start", () => {
74+
it("should track spans", () => {
75+
const result = new Mermaid();
76+
result.start("span");
77+
expect(result.spans).toEqual(["span"]);
78+
});
79+
});
80+
81+
describe("report", () => {
82+
it("should create and return mermaid graph", async () => {
83+
const result = new Mermaid();
84+
result.spans = createSampleSpans();
85+
expect(await result.report()).toEqual(graphResult);
86+
});
87+
88+
it("should save to file", async () => {
89+
const result = new Mermaid();
90+
result.spans = createSampleSpans();
91+
92+
const spyWriteFile = jest.spyOn(fs, "writeFile").mockResolvedValue(true);
93+
94+
await result.report("/test.mer");
95+
expect(spyWriteFile).toBeCalledWith("/test.mer", graphResult);
96+
});
97+
});
98+
});

0 commit comments

Comments
 (0)