mirror of
https://github.com/chartjs/Chart.js.git
synced 2025-12-08 20:36:08 +00:00
parsing: support dot(s) in object keys (#10517)
This commit is contained in:
parent
144a6c0c27
commit
a4114e84d9
@ -85,11 +85,27 @@ options: {
|
||||
}
|
||||
```
|
||||
|
||||
If the key contains a dot, it needs to be escaped with a double slash:
|
||||
|
||||
```javascript
|
||||
type: 'line',
|
||||
data: {
|
||||
datasets: [{
|
||||
data: [{ 'data.key': 'one', 'data.value': 20 }, { 'data.key': 'two', 'data.value': 30 }]
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
parsing: {
|
||||
xAxisKey: 'data\\.key',
|
||||
yAxisKey: 'data\\.value'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
:::warning
|
||||
When using object notation in a radar chart you still need a labels array with labels for the chart to show correctly.
|
||||
:::
|
||||
|
||||
|
||||
## Object
|
||||
|
||||
```javascript
|
||||
|
||||
@ -293,25 +293,52 @@ export function _deprecated(scope, value, previous, current) {
|
||||
}
|
||||
}
|
||||
|
||||
const emptyString = '';
|
||||
const dot = '.';
|
||||
function indexOfDotOrLength(key, start) {
|
||||
const idx = key.indexOf(dot, start);
|
||||
return idx === -1 ? key.length : idx;
|
||||
}
|
||||
// resolveObjectKey resolver cache
|
||||
const keyResolvers = {
|
||||
// Chart.helpers.core resolveObjectKey should resolve empty key to root object
|
||||
'': v => v,
|
||||
// default resolvers
|
||||
x: o => o.x,
|
||||
y: o => o.y
|
||||
};
|
||||
|
||||
export function resolveObjectKey(obj, key) {
|
||||
if (key === emptyString) {
|
||||
const resolver = keyResolvers[key] || (keyResolvers[key] = _getKeyResolver(key));
|
||||
return resolver(obj);
|
||||
}
|
||||
|
||||
function _getKeyResolver(key) {
|
||||
const keys = _splitKey(key);
|
||||
return obj => {
|
||||
for (const k of keys) {
|
||||
if (k === '') {
|
||||
// For backward compatibility:
|
||||
// Chart.helpers.core resolveObjectKey should break at empty key
|
||||
break;
|
||||
}
|
||||
obj = obj && obj[k];
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
export function _splitKey(key) {
|
||||
const parts = key.split('.');
|
||||
const keys = [];
|
||||
let tmp = '';
|
||||
for (const part of parts) {
|
||||
tmp += part;
|
||||
if (tmp.endsWith('\\')) {
|
||||
tmp = tmp.slice(0, -1) + '.';
|
||||
} else {
|
||||
keys.push(tmp);
|
||||
tmp = '';
|
||||
}
|
||||
}
|
||||
let pos = 0;
|
||||
let idx = indexOfDotOrLength(key, pos);
|
||||
while (obj && idx > pos) {
|
||||
obj = obj[key.slice(pos, idx)];
|
||||
pos = idx + 1;
|
||||
idx = indexOfDotOrLength(key, pos);
|
||||
}
|
||||
return obj;
|
||||
return keys;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -456,6 +456,44 @@ describe('Chart.helpers.core', function() {
|
||||
expect(() => helpers.resolveObjectKey({}, true)).toThrow();
|
||||
expect(() => helpers.resolveObjectKey({}, 1)).toThrow();
|
||||
});
|
||||
it('should allow escaping dot symbol', function() {
|
||||
expect(helpers.resolveObjectKey({'test.dot': 10}, 'test\\.dot')).toEqual(10);
|
||||
expect(helpers.resolveObjectKey({test: {dot: 10}}, 'test\\.dot')).toEqual(undefined);
|
||||
});
|
||||
it('should allow nested keys with a dot', function() {
|
||||
expect(helpers.resolveObjectKey({
|
||||
a: {
|
||||
'bb.ccc': 'works',
|
||||
bb: {
|
||||
ccc: 'fails'
|
||||
}
|
||||
}
|
||||
}, 'a.bb\\.ccc')).toEqual('works');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('_splitKey', function() {
|
||||
it('should return array with one entry for string without a dot', function() {
|
||||
expect(helpers._splitKey('')).toEqual(['']);
|
||||
expect(helpers._splitKey('test')).toEqual(['test']);
|
||||
const asciiWithoutDot = ' !"#$%&\'()*+,-/0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
|
||||
expect(helpers._splitKey(asciiWithoutDot)).toEqual([asciiWithoutDot]);
|
||||
});
|
||||
|
||||
it('should split on dot', function() {
|
||||
expect(helpers._splitKey('test1.test2')).toEqual(['test1', 'test2']);
|
||||
expect(helpers._splitKey('a.b.c')).toEqual(['a', 'b', 'c']);
|
||||
expect(helpers._splitKey('a.b.')).toEqual(['a', 'b', '']);
|
||||
expect(helpers._splitKey('a..c')).toEqual(['a', '', 'c']);
|
||||
});
|
||||
|
||||
it('should preserve escaped dot', function() {
|
||||
expect(helpers._splitKey('test1\\.test2')).toEqual(['test1.test2']);
|
||||
expect(helpers._splitKey('a\\.b.c')).toEqual(['a.b', 'c']);
|
||||
expect(helpers._splitKey('a.b\\.c')).toEqual(['a', 'b.c']);
|
||||
expect(helpers._splitKey('a.\\.c')).toEqual(['a', '.c']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setsEqual', function() {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user