Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(data-point-tracers): add mermaid support #420

Merged
merged 1 commit into from
Sep 11, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions documentation/examples/mermaid-graph/mermaid-example.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/* eslint-disable */

const path = require("path");

const DataPoint = require("@data-point/core");
const DPModel = require("@data-point/core/model");
const DPIfThenElse = require("@data-point/core/ifThenElse");
const DPMap = require("@data-point/core/map");

const DPMermaidTracer = require("@data-point/tracers/mermaid");

const myModel = DPModel({
name: "myModel",

uid: acc => `${acc.reducer.id}${acc.value.a.b}`,

value: [
"$a.b",
input => input.toUpperCase(),
DPIfThenElse({
if: input => input === "FOO",
then: () => {
// return "yes foo!!";
throw new Error("ohh");
},
else: input => `foo no! got ${input}`
})
],

catch(acc) {
return "its all ok";
}
});

async function main() {
const datapoint = DataPoint();

const input = [
{
a: {
b: "foo"
}
},
{
a: {
b: "bar"
}
},
{
a: {
b: "baz"
}
}
];

const tracer = DPMermaidTracer();

result = await datapoint.resolve(input, DPMap(myModel), {
tracer
});

// save to disk
tracer.report(path.join(__dirname, "datapoint-trace-example.mermaid"));
}

main();
10 changes: 10 additions & 0 deletions documentation/examples/mermaid-graph/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "@data-point/mermaid-example",
"main": "mermaid-example.js",
"private": true,
"version": "1.0.0",
"devDependencies": {
"@data-point/core": "^6.0.0",
"@data-point/tracers": "^1.0.0"
}
}
1 change: 1 addition & 0 deletions packages/data-point-tracers/mermaid/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require("./mermaid").Mermaid.create;
48 changes: 48 additions & 0 deletions packages/data-point-tracers/mermaid/mermaid.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
const fs = require("fs").promises;

function getParent(span) {
return span.root ? "root" : span.parent;
}

function getName(span) {
return span === "root" ? "root" : `${span.name}${span.context.pid}`;
}

function graphTD(spans) {
const nodes = spans.map(span => {
return ` ${getName(getParent(span))}-->${getName(span)}`;
});

return `graph TD;\n${nodes.join("\n")}`;
}

class Mermaid {
constructor() {
this.spans = [];
}

static create() {
return new Mermaid();
}

start(dpSpan) {
this.spans.push(dpSpan);
}

async report(destinationPath) {
const report = graphTD(this.spans);

if (destinationPath) {
await fs.writeFile(destinationPath, report);
}

return report;
}
}

module.exports = {
getParent,
getName,
graphTD,
Mermaid
};
98 changes: 98 additions & 0 deletions packages/data-point-tracers/mermaid/mermaid.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
const fs = require("fs").promises;
const { getParent, getName, graphTD, Mermaid } = require("./mermaid");

function createChildSpan(name, pid, parent) {
return {
name,
parent,
context: {
pid
}
};
}

function createSampleSpans() {
const aa = createChildSpan("aa", 1);
aa.root = true;
const bb = createChildSpan("bb", 2, aa);
const cc = createChildSpan("cc", 3, aa);
const dd = createChildSpan("dd", 4, bb);

const spans = [aa, bb, cc, dd];

return spans;
}

const graphResult = `graph TD;
root-->aa1
aa1-->bb2
aa1-->cc3
bb2-->dd4`;

describe("getParent", () => {
it("should return `root` if root flag is true", () => {
expect(getParent({ root: true })).toEqual("root");
});
it("should return parent if root flag not true", () => {
expect(getParent({ parent: "parent" })).toEqual("parent");
});
});

describe("getName", () => {
it("should return 'root' if span is root", () => {
expect(getName("root")).toEqual("root");
});
it("should return constructed name if span is not root", () => {
const span = createChildSpan("name", 1);
expect(getName(span)).toEqual("name1");
});
});

describe("graphTD", () => {
it("should create graph tree", () => {
const result = graphTD(createSampleSpans());
expect(result).toEqual(graphResult);
});
});

describe("Mermaid", () => {
describe("constructor", () => {
it("should create spans array", () => {
const result = new Mermaid();
expect(result).toHaveProperty("spans", []);
});
});

describe("create", () => {
it("should have static method to create new instance", () => {
const result = Mermaid.create();
expect(result).toBeInstanceOf(Mermaid);
});
});

describe("start", () => {
it("should track spans", () => {
const result = new Mermaid();
result.start("span");
expect(result.spans).toEqual(["span"]);
});
});

describe("report", () => {
it("should create and return mermaid graph", async () => {
const result = new Mermaid();
result.spans = createSampleSpans();
expect(await result.report()).toEqual(graphResult);
});

it("should save to file", async () => {
const result = new Mermaid();
result.spans = createSampleSpans();

const spyWriteFile = jest.spyOn(fs, "writeFile").mockResolvedValue(true);

await result.report("/test.mer");
expect(spyWriteFile).toBeCalledWith("/test.mer", graphResult);
});
});
});