Skip to content

Commit

Permalink
Refactor Markdown parsing out into a seperate file for reuse.
Browse files Browse the repository at this point in the history
  • Loading branch information
jmchilton committed Dec 22, 2023
1 parent 1032829 commit 8e84f7c
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 66 deletions.
74 changes: 8 additions & 66 deletions client/src/components/Markdown/Markdown.vue
Original file line number Diff line number Diff line change
Expand Up @@ -75,15 +75,12 @@ import Vue from "vue";
import { useWorkflowStore } from "@/stores/workflowStore";
import { splitMarkdown as splitMarkdownUnrendered } from "./parse";
import MarkdownContainer from "./MarkdownContainer.vue";
import LoadingSpan from "components/LoadingSpan.vue";
import StsDownloadButton from "components/StsDownloadButton.vue";
const FUNCTION_VALUE_REGEX = `\\s*(?:[\\w_\\-]+|\\"[^\\"]+\\"|\\'[^\\']+\\')\\s*`;
const FUNCTION_CALL = `\\s*[\\w\\|]+\\s*=` + FUNCTION_VALUE_REGEX;
const FUNCTION_CALL_LINE = `\\s*(\\w+)\\s*\\(\\s*(?:(${FUNCTION_CALL})(,${FUNCTION_CALL})*)?\\s*\\)\\s*`;
const FUNCTION_CALL_LINE_TEMPLATE = new RegExp(FUNCTION_CALL_LINE, "m");
const mdNewline = markdownItRegexp(/<br>/, () => {
return "<div style='clear:both;'/><br>";
});
Expand Down Expand Up @@ -197,70 +194,15 @@ export default {
}
},
splitMarkdown(markdown) {
const sections = [];
let digest = markdown;
while (digest.length > 0) {
const galaxyStart = digest.indexOf("```galaxy");
if (galaxyStart != -1) {
const galaxyEnd = digest.substr(galaxyStart + 1).indexOf("```");
if (galaxyEnd != -1) {
if (galaxyStart > 0) {
const defaultContent = digest.substr(0, galaxyStart).trim();
if (defaultContent) {
sections.push({
name: "default",
content: md.render(defaultContent),
});
}
}
const galaxyEndIndex = galaxyEnd + 4;
const galaxySection = digest.substr(galaxyStart, galaxyEndIndex);
let args = null;
try {
args = this.getArgs(galaxySection);
sections.push(args);
} catch (e) {
this.markdownErrors.push({
error: "Found an unresolved tag.",
line: galaxySection,
});
}
digest = digest.substr(galaxyStart + galaxyEndIndex);
} else {
digest = digest.substr(galaxyStart + 1);
}
} else {
sections.push({
name: "default",
content: md.render(digest),
});
break;
const { sections, markdownErrors } = splitMarkdownUnrendered(markdown);
markdownErrors.forEach((error) => markdownErrors.push(error));
sections.forEach((section) => {
if (section.name == "default") {
section.content = md.render(section.content);
}
}
});
return sections;
},
getArgs(content) {
const galaxy_function = FUNCTION_CALL_LINE_TEMPLATE.exec(content);
const args = {};
const function_name = galaxy_function[1];
// we need [... ] to return empty string, if regex doesn't match
const function_arguments = [...content.matchAll(new RegExp(FUNCTION_CALL, "g"))];
for (let i = 0; i < function_arguments.length; i++) {
if (function_arguments[i] === undefined) {
continue;
}
const arguments_str = function_arguments[i].toString().replace(/,/g, "").trim();
if (arguments_str) {
const [key, val] = arguments_str.split("=");
args[key.trim()] = val.replace(/['"]+/g, "").trim();
}
}
return {
name: function_name,
args: args,
content: content,
};
},
},
};
</script>
10 changes: 10 additions & 0 deletions client/src/components/Markdown/parse.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { getArgs } from "./parse";

describe("parse.ts", () => {
describe("getArgs", async () => {
it("parses simple directive expression", () => {
const args = getArgs("job_metrics(job_id=THISFAKEID)");
expect(args.name).toBe("job_metrics");
});
});
});
79 changes: 79 additions & 0 deletions client/src/components/Markdown/parse.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
const FUNCTION_VALUE_REGEX = `\\s*(?:[\\w_\\-]+|\\"[^\\"]+\\"|\\'[^\\']+\\')\\s*`;
const FUNCTION_CALL = `\\s*[\\w\\|]+\\s*=` + FUNCTION_VALUE_REGEX;
const FUNCTION_CALL_LINE = `\\s*(\\w+)\\s*\\(\\s*(?:(${FUNCTION_CALL})(,${FUNCTION_CALL})*)?\\s*\\)\\s*`;
const FUNCTION_CALL_LINE_TEMPLATE = new RegExp(FUNCTION_CALL_LINE, "m");

export function splitMarkdown(markdown: string) {
const sections = [];
const markdownErrors = [];
let digest = markdown;
while (digest.length > 0) {
const galaxyStart = digest.indexOf("```galaxy");
if (galaxyStart != -1) {
const galaxyEnd = digest.substr(galaxyStart + 1).indexOf("```");
if (galaxyEnd != -1) {
if (galaxyStart > 0) {
const defaultContent = digest.substr(0, galaxyStart).trim();
if (defaultContent) {
sections.push({
name: "default",
content: defaultContent,
});
}
}
const galaxyEndIndex = galaxyEnd + 4;
const galaxySection = digest.substr(galaxyStart, galaxyEndIndex);
let args = null;
try {
args = getArgs(galaxySection);
sections.push(args);
} catch (e) {
markdownErrors.push({
error: "Found an unresolved tag.",
line: galaxySection,
});
}
digest = digest.substr(galaxyStart + galaxyEndIndex);
} else {
digest = digest.substr(galaxyStart + 1);
}
} else {
sections.push({
name: "default",
content: digest,
});
break;
}
}
return { sections, markdownErrors };
}

export function getArgs(content: string) {
const galaxy_function = FUNCTION_CALL_LINE_TEMPLATE.exec(content);
if (galaxy_function == null) {
throw Error("Failed to parse galaxy directive");
}
type ArgsType = { [key: string]: string };
const args: ArgsType = {};
const function_name = galaxy_function[1];
// we need [... ] to return empty string, if regex doesn't match
const function_arguments = [...content.matchAll(new RegExp(FUNCTION_CALL, "g"))];
for (let i = 0; i < function_arguments.length; i++) {
if (function_arguments[i] === undefined) {
continue;
}
const arguments_str = function_arguments[i]?.toString().replace(/,/g, "").trim();
if (arguments_str) {
const [key, val] = arguments_str.split("=");
if (key == undefined || val == undefined) {
throw Error("Failed to parse galaxy directive");
}
args[key.trim()] = val.replace(/['"]+/g, "").trim();
}
}
return {
name: function_name,
args: args,
content: content,
};
}

0 comments on commit 8e84f7c

Please sign in to comment.