diff --git a/client/src/components/Markdown/parse.test.js b/client/src/components/Markdown/parse.test.js index ae3f929cb052..50b1ae99397d 100644 --- a/client/src/components/Markdown/parse.test.js +++ b/client/src/components/Markdown/parse.test.js @@ -6,6 +6,18 @@ describe("parse.ts", () => { const args = getArgs("job_metrics(job_id=THISFAKEID)"); expect(args.name).toBe("job_metrics"); }); + + it("parses labels spaces at the end with single quotes", () => { + const args = getArgs("job_metrics(step=' fakestepname ')"); + expect(args.name).toBe("job_metrics"); + expect(args.args.step).toBe(" fakestepname "); + }); + + it("parses labels spaces at the end with double quotes", () => { + const args = getArgs('job_metrics(step=" fakestepname ")'); + expect(args.name).toBe("job_metrics"); + expect(args.args.step).toBe(" fakestepname "); + }); }); describe("splitMarkdown", () => { @@ -19,6 +31,12 @@ describe("parse.ts", () => { expect(sections.length).toBe(2); expect(sections[0].content).toBe("\n"); }); + + it("should parse labels with leading spaces", () => { + const { sections } = splitMarkdown("\n```galaxy\njob_metrics(step='THISFAKEID ')\n```", true); + expect(sections.length).toBe(2); + expect(sections[0].content).toBe("\n"); + }); }); describe("replaceLabel", () => { @@ -103,6 +121,15 @@ describe("parse.ts", () => { expect(result).toBe(output); }); + it("should work with single quotes for labels and spaces in the quotes including end", () => { + const input = + "some random\n`markdown content`\n```galaxy\nhistory_dataset_embedded(footer='cow', output='from this ', title=dog)\n```\n"; + const output = + "some random\n`markdown content`\n```galaxy\nhistory_dataset_embedded(footer='cow', output='to thatx ', title=dog)\n```\n"; + const result = replaceLabel(input, "output", "from this ", "to thatx "); + expect(result).toBe(output); + }); + it("should add quotes when refactoring to labels with spaces", () => { const input = "some random\n`markdown content`\n```galaxy\nhistory_dataset_embedded(footer='cow', output=fromthis, title=dog)\n```\n"; @@ -112,6 +139,15 @@ describe("parse.ts", () => { expect(result).toBe(output); }); + it("should add quotes when refactoring to labels with spaces including end space", () => { + const input = + "some random\n`markdown content`\n```galaxy\nhistory_dataset_embedded(footer='cow', output=fromthis, title=dog)\n```\n"; + const output = + "some random\n`markdown content`\n```galaxy\nhistory_dataset_embedded(footer='cow', output='to that ', title=dog)\n```\n"; + const result = replaceLabel(input, "output", "fromthis", "to that "); + expect(result).toBe(output); + }); + it("should leave non-arguments alone", () => { const input = "some random\n`markdown content`\n```galaxy\nhistory_dataset_embedded(title='cow from farm', output=from)\n```\n"; diff --git a/client/src/components/Markdown/parse.ts b/client/src/components/Markdown/parse.ts index 80616faa3c81..2991846bede4 100644 --- a/client/src/components/Markdown/parse.ts +++ b/client/src/components/Markdown/parse.ts @@ -1,4 +1,5 @@ const FUNCTION_ARGUMENT_VALUE_REGEX = `\\s*(?:[\\w_\\-]+|\\"[^\\"]+\\"|\\'[^\\']+\\')\\s*`; +const FUNCTION_ARGUMENT_VALUE_TO_VALUE_REGEX = `\\s*(?:\\"(?[^\\"]+)\\"|\\'(?[^\\']+)\\'|(?[\\w_\\-]+))\\s*`; const FUNCTION_ARGUMENT_REGEX = `\\s*[\\w\\|]+\\s*=` + FUNCTION_ARGUMENT_VALUE_REGEX; const FUNCTION_CALL_LINE = `\\s*(\\w+)\\s*\\(\\s*(?:(${FUNCTION_ARGUMENT_REGEX})(,${FUNCTION_ARGUMENT_REGEX})*)?\\s*\\)\\s*`; const FUNCTION_CALL_LINE_TEMPLATE = new RegExp(FUNCTION_CALL_LINE, "m"); @@ -87,6 +88,7 @@ export function replaceLabel( const match = incomingContent.match(argRexExp); if (match) { const firstMatch = match[0]; + // TODO: handle whitespace more broadly here... if (escapedToLabel.indexOf(" ") >= 0) { const quoteChar = getQuoteChar(firstMatch); escapedToLabel = `${quoteChar}${escapedToLabel}${quoteChar}`; @@ -135,11 +137,20 @@ export function getArgs(content: string): GalaxyDirectiveSection { } const arguments_str = function_arguments[i]?.toString().replace(/,/g, "").trim(); if (arguments_str) { - const [key, val] = arguments_str.split("="); - if (key == undefined || val == undefined) { + const [keyStr, valStr] = arguments_str.split("="); + if (keyStr == undefined || keyStr == undefined) { throw Error("Failed to parse galaxy directive"); } - args[key.trim()] = val.replace(/['"]+/g, "").trim(); + const key = keyStr.trim(); + let val: string = valStr?.trim() ?? ""; + if (val) { + const strippedValueMatch = val.match(FUNCTION_ARGUMENT_VALUE_TO_VALUE_REGEX); + const groups = strippedValueMatch?.groups; + if (groups) { + val = groups.unquoted ?? groups.squoted ?? groups.dquoted ?? val; + } + } + args[key] = val; } } return {