Skip to content

Instantly share code, notes, and snippets.

@elight
Last active May 29, 2022 06:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save elight/357403ea7bf3ad21fb84d487db79602d to your computer and use it in GitHub Desktop.
Save elight/357403ea7bf3ad21fb84d487db79602d to your computer and use it in GitHub Desktop.
DataviewJS for converting multiple tasks with 'project tags' into a mermaid flow chart
/**
"Project tags" just means "any markdown task that that share a tag but separates the tasks
identifier/position in the flow followed by the identifiers of the identifiers/positions of
nodes with edges that point to this node. In this way, the tags allow the tasks to remain
sortable by their flow step identifier thusly:
#project/1 step 1 description
#project/2a/1 step 2a description
#project/2b/1 etc
#project/3/2a/2b etc etc.
Such that we get a flow (top down) that looks like:
1
/ \
2a 2b
\ /
3
*/
// Cribbed from StackOverflow. I am *so* not this good at regex.
function escapeRegex(s) {
return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
}
const SOURCE = '!"Projects/Obsidian"';
const PR_TAG = String(dv.pages('[[]]').pr_tag);
const PATTERN = new RegExp(escapeRegex("#" + PR_TAG + "/"));
let buffer = "";
function span(code) {
buffer = buffer.concat(`${code}\n\n`);
}
span("```mermaid");
span("flowchart TD");
function extra_edges_from(tag) {
var pr_tag = tag.text.split(' ')[0];
//dv.span(`- ${pr_tag}\n`);
// +1 for leading # and +1 for trailing '/'
var edges = pr_tag.substring(PR_TAG.length + 2).split("/");
//dv.span(`- Edges: ${edges}\n`);
return edges;
}
function task_to_description_only(t) {
var desc = "";
// chop off project tag
var parts = t.text.split(' ').slice(1);
//dv.span(`- Desc No PR Tag: ${parts}`);
// excise due, start, and scheduled dates
parts = parts.filter(w => !w.match(/^[📅🛫⏳]\d{4}-\d{2}-\d{2}/));
// excise date
parts = parts.filter(w => !w.match(/\d{4}-\d{2}-\d{2}/));
// excise priority
parts = parts.filter(w => !w.match(/^[⏫🔼🔽]/));
// excise inline annotations
parts = parts.filter(w => !w.match(/^\[.*\]$/));
parts = parts.map(w => {
var m = w.match(/\[(.+)/) || w.match(/(.+)\]\(.+/);
//dv.span(`\n\n${w}\n\n`);
if (m) {
//dv.span(`\n\nm[1]: ${m[1]}\n\n`);
return m[1];
} else {
return w;
}});
desc = '"' + parts.join(' ') + '"';
return desc;
}
function node_to_string(id, desc = "") {
id = `id${id}`;
if (desc.length > 0) {
desc = `[${desc}]`;
}
return `${id}${desc}`;
}
function emit_root(id, desc) {
span(node_to_string(id, desc));
}
function emit_branch(id, desc, src_id) {
span(`${node_to_string(src_id)} --> ${node_to_string(id, desc)}`);
}
let tasks = dv.pages(SOURCE).file.tasks
.where(t => t.text.match(PATTERN))
.map(t => {
//span(t.text);
var edges = extra_edges_from(t);
//span(`- Edges: ${edges}`);
var dest = edges[0];
var src_ids = edges.slice(1);
//span(`- src IDs: ${src_ids}`);
var dest_desc = task_to_description_only(t);
//span(`- desc: ${dest_desc}`);
if (src_ids.length == 0) {
emit_root(dest, dest_desc);
} else {
for(var i = 0; i < src_ids.length; i++) {
emit_branch(dest, dest_desc, src_ids[i]);
}
}
return t;
});
span("```");
dv.span(buffer);
//dv.taskList(tasks, false);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment