Skip to content

Commit

Permalink
apply single quote escape
Browse files Browse the repository at this point in the history
  • Loading branch information
yhoonkim committed Nov 22, 2024
1 parent 8fa04c8 commit ef2dbb0
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 8 deletions.
13 changes: 5 additions & 8 deletions src/compile/data/timeunit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
normalizeTimeUnit
} from '../../timeunit';
import {TimeUnitTransform} from '../../transform';
import {Dict, duplicate, entries, hash, isEmpty, replacePathInField, vals} from '../../util';
import {Dict, duplicate, entries, escapeSingleQuotes, hash, isEmpty, replacePathInField, vals} from '../../util';
import {ModelWithField, isUnitModel} from '../model';
import {DataFlowNode} from './dataflow';
import {isRectBasedMark} from '../../mark';
Expand Down Expand Up @@ -38,10 +38,7 @@ export class TimeUnitNode extends DataFlowNode {
return new TimeUnitNode(null, duplicate(this.timeUnits));
}

constructor(
parent: DataFlowNode,
private timeUnits: Dict<TimeUnitComponent>
) {
constructor(parent: DataFlowNode, private timeUnits: Dict<TimeUnitComponent>) {

Check warning on line 41 in src/compile/data/timeunit.ts

View workflow job for this annotation

GitHub Actions / Runtime, Linting, and Coverage

Replace `parent:·DataFlowNode,·private·timeUnits:·Dict<TimeUnitComponent>` with `⏎····parent:·DataFlowNode,⏎····private·timeUnits:·Dict<TimeUnitComponent>⏎··`
super(parent);
}

Expand Down Expand Up @@ -218,7 +215,7 @@ function offsetExpr({timeUnit, field, reverse}: {timeUnit: TimeUnitParams; field
const smallestUnit = getSmallestTimeUnitPart(unit);
const {part, step} = getDateTimePartAndStep(smallestUnit, timeUnit.step);
const offsetFn = utc ? 'utcOffset' : 'timeOffset';
const expr = `${offsetFn}('${part}', datum['${field}'], ${reverse ? -step : step})`;
const expr = `${offsetFn}('${part}', datum['${escapeSingleQuotes(field)}'], ${reverse ? -step : step})`;
return expr;
}

Expand All @@ -228,8 +225,8 @@ function offsetedRectFormulas(
timeUnit: TimeUnitParams
): VgFormulaTransform[] {
if (rectBandPosition !== undefined && rectBandPosition !== 0.5) {
const startExpr = `datum['${startField}']`;
const endExpr = `datum['${endField}']`;
const startExpr = `datum['${escapeSingleQuotes(startField)}']`;
const endExpr = `datum['${escapeSingleQuotes(endField)}']`;
return [
{
type: 'formula',
Expand Down
4 changes: 4 additions & 0 deletions src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,10 @@ function escapePathAccess(string: string) {
return string.replace(/(\[|\]|\.|'|")/g, '\\$1');
}

export function escapeSingleQuotes(value: string) {
return value.replaceAll("'", "\\'");
}

/**
* Replaces path accesses with access to non-nested field.
* For example, `foo["bar"].baz` becomes `foo\\.bar\\.baz`.
Expand Down
30 changes: 30 additions & 0 deletions test/compile/data/timeunit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,36 @@ describe('compile/data/timeunit', () => {
]);
});

it('should return a unit transform for bar with bandPosition=0 and escaped field name', () => {
const model = parseUnitModel({
data: {values: []},
mark: 'bar',
encoding: {
x: {field: "\\'a\\'", type: 'temporal', timeUnit: 'month', bandPosition: 0}
}
});

expect(assembleFromEncoding(model)).toEqual([
{
type: 'timeunit',
field: "\\'a\\'",
as: ["month_'a'", "month_'a'_end"],
units: ['month']
},
{
type: 'formula',
expr: "0.5 * timeOffset('month', datum['month_\\'a\\''], -1) + 0.5 * datum['month_\\'a\\'']",
as: `month_'a'_${OFFSETTED_RECT_START_SUFFIX}`
},

{
type: 'formula',
expr: "0.5 * datum['month_\\'a\\''] + 0.5 * datum['month_\\'a\\'_end']",
as: `month_'a'_${OFFSETTED_RECT_END_SUFFIX}`
}
]);
});

it('should return a timeunit transform with step for bar with bandPosition=0', () => {
const model = parseUnitModel({
data: {values: []},
Expand Down

0 comments on commit ef2dbb0

Please sign in to comment.