Skip to content

Commit

Permalink
pass tests, but still not complete
Browse files Browse the repository at this point in the history
  • Loading branch information
mbostock committed Sep 8, 2023
1 parent 55b4dce commit 850dd7d
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 27 deletions.
27 changes: 18 additions & 9 deletions src/transforms/tree.js
Original file line number Diff line number Diff line change
Expand Up @@ -169,20 +169,29 @@ function nodeData(field) {
function normalizer(delimiter = "/") {
return `${delimiter}` === "/"
? (P) => P // paths are already slash-separated
: (P) => P.map(slashEscape).map(replaceAll(delimiter, "/")); // TODO string.replaceAll when supported
: (P) => P.map(slashDelimiter(delimiter));
}

function slashEscape(string) {
return string.replace(/\//g, "\\/");
function slashDelimiter(delimiter) {
const search = new RegExp(`(\\\\*)(${regexEscape(delimiter)}|/)`, "g");
return (value) =>
value == null
? null
: value.replace(
search,
(match, a, b) =>
b === delimiter
? a.length & 1
? `${a.slice(1)}${delimiter}` // drop one backslash
: `${a}/` // replace delimiter with slash
: a.length & 1
? `${a}\\\\/` // add two backslashes to escape backslash
: `${a}\\/` // add one backslash to escape slash
);
}

function slashUnescape(string) {
return string.replace(/\\\//g, "/");
}

function replaceAll(search, replace) {
search = new RegExp(regexEscape(search), "g");
return (value) => (value == null ? null : `${value}`.replace(search, replace));
return string.replace(/\\\//g, "/").replace(/\\\\/g, "\\"); // TODO count backslashes properly
}

function regexEscape(string) {
Expand Down
40 changes: 22 additions & 18 deletions test/plots/tree-delimiter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,22 @@ import * as Plot from "@observablehq/plot";
export async function treeDelimiter() {
return Plot.plot({
axis: null,
height: 120,
height: 150,
margin: 10,
marginLeft: 40,
marginRight: 190,
marks: [
Plot.tree(
[
"foo;bar;https://example.com",
"foo;bar;https://example.com/posts/1",
"foo;baz;https://example.com/posts/2",
"foo;bar\\;baz;https://example2.com", // “bar;baz” should be a single node
"foo;bar/baz;https://example4.com", // "bar/baz" should be a single node, distinct from “bar;baz”
"foo;bar\\/baz;https://example3.com" // “bar\/baz” should be a single node
"foo;a;//example", // foo → a → //example
"foo;a;//example/1", // foo → a → //example/1
"foo;b;//example/2", // foo → b → //example/2
"foo;c\\;c;//example2", // foo → c;c → //example2
"foo;d\\\\;d;//example2", // foo → d\ → d → //example3
"foo;d\\\\;\\d;//example2", // foo → d\ → \d → //example3
"foo;e\\\\\\;e;//example2", // foo → e\;e → //example3
"foo;f/f;//example4", // foo → f/f → //example4
"foo;g\\/g;//example3" // foo → g\/g → //example3
],
{delimiter: ";"}
)
Expand All @@ -26,21 +29,22 @@ export async function treeDelimiter() {
export async function treeDelimiter2() {
return Plot.plot({
axis: null,
height: 120,
height: 150,
margin: 10,
marginLeft: 40,
marginRight: 190,
marks: [
Plot.tree(
[
"foo/bar/https:\\/\\/example.com",
"foo/bar/https:\\/\\/example.com\\/posts\\/1",
"foo/baz/https:\\/\\/example.com\\/posts\\/2",
"foo/bar;baz/https:\\/\\/example2.com", // “bar;baz” should be a single node
"foo/bar\\/baz/https:\\/\\/example4.com", // "bar/baz" should be a single node, distinct from “bar;baz”
"foo/bar\\\\\\/baz/https:\\/\\/example3.com" // “bar\/baz” should be a single node
]
)
Plot.tree([
"foo/a/\\/\\/example", // foo → a → //example
"foo/a/\\/\\/example\\/1", // foo → a → //example/1
"foo/b/\\/\\/example\\/2", // foo → b → //example/2
"foo/c;c/\\/\\/example2", // foo → c;c → //example2
"foo/d\\\\/d/\\/\\/example2", // foo → d\ → d → //example3
"foo/d\\\\/\\d/\\/\\/example2", // foo → d\ → \d → //example3
"foo/e\\\\;e/\\/\\/example2", // foo → e\;e → //example3
"foo/f\\/f/\\/\\/example4", // foo → f/f → //example4
"foo/g\\\\\\/g/\\/\\/example3" // foo → g\/g → //example3
])
]
});
}

0 comments on commit 850dd7d

Please sign in to comment.