Skip to content
Open
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
30 changes: 30 additions & 0 deletions web-common/src/components/vega/util.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { describe, expect, it } from "vitest";
import { parseExpression } from "vega-expression";
import { sanitizeFieldName } from "./util";

describe("sanitizeFieldName", () => {
it("keeps simple field names readable", () => {
expect(sanitizeFieldName("total_sales")).toBe("rill_total_sales");
});

it("returns a valid Vega expression function name for measure names with operators", () => {
const measureNames = [
"Total Sample Revenue",
"Sample Rate* Lift",
"Share(%) | Variant A",
"Share(%) | Baseline",
"Avg Sample Value | Variant A",
"Avg Sample Value | Baseline",
"Success Rate | Variant A",
"Success Rate | Baseline",
"Success Rate | Delta",
];

for (const measureName of measureNames) {
const formatType = sanitizeFieldName(measureName);

expect(formatType).toMatch(/^[A-Za-z_$][A-Za-z0-9_$]*$/);
expect(() => parseExpression(`${formatType}(datum.value)`)).not.toThrow();
}
});
});
16 changes: 10 additions & 6 deletions web-common/src/components/vega/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,17 @@ export function sanitizeValuesForSpec(values: unknown[]) {
}

export function sanitizeFieldName(fieldName: string) {
const specialCharactersRemoved = sanitizeValueForVega(fieldName);
const sanitizedFieldName = specialCharactersRemoved.replace(" ", "__");
const sanitizedFieldName = Array.from(fieldName)
.map((char) => {
if (/[a-zA-Z0-9_$]/.test(char)) return char;
return `_u${char.codePointAt(0)?.toString(16) ?? "0"}_`;
})
.join("");

/**
* Add a prefix to the beginning of the field
* name to avoid variables starting with a special
* character or number.
* Vega-Lite compiles custom formatType values as expression function calls.
* Keep this value to a JavaScript/Vega identifier-safe subset so measure
* names with spaces or operators can still be used as formatter names.
*/
return `rill_${sanitizedFieldName}`;
return `rill_${sanitizedFieldName || "field"}`;
}
Loading