Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: chartjs/Chart.js
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 06f73dc3590084b2c464bf08189c7aee2b6b92d2
Choose a base ref
...
head repository: chartjs/Chart.js
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 1d92605aa6c29add400c4c551413fc2306c15e8d
Choose a head ref
  • 9 commits
  • 14 files changed
  • 8 contributors

Commits on Feb 11, 2020

  1. Copy the full SHA
    2df6986 View commit details

Commits on Jun 4, 2020

  1. Preserve object prototypes when cloning (#7404)

    Co-authored-by: Bryan.Iddings <bryan.iddings@noaa.gov>
    iddings and Bryan.Iddings authored Jun 4, 2020
    Copy the full SHA
    484f0d1 View commit details

Commits on Jul 5, 2020

  1. Verified

    This commit was signed with the committer’s verified signature.
    targos Michaël Zasso
    Copy the full SHA
    679ec4a View commit details

Commits on Oct 8, 2020

  1. Use node v12.18.2 on Travis CI (#7864)

    Due to an issue with deprecated deps (gitbook-cli), forcing travis to and older
    compatible version of nodejs.
    
    Fixes #7863
    alessandroasm authored Oct 8, 2020

    Verified

    This commit was signed with the committer’s verified signature.
    targos Michaël Zasso
    Copy the full SHA
    2493cb5 View commit details

Commits on Oct 9, 2020

  1. [2.9] FitBoxes recursion when dimensions are NaN (#7853)

    * Infinite recursion when dimensions are NaN
    
    Adding a verification on updateDims that handles a case when dimensions are both
    NaN. This caused an infinite recursion on fitBoxes when calculating the layout
    for a chart that is mounted on an element that is not yet in DOM.
    
    Fixes #7761
    alessandroasm authored Oct 9, 2020

    Verified

    This commit was signed with the committer’s verified signature.
    BethGriggs Bethany Griggs
    Copy the full SHA
    063b7dc View commit details

Commits on Oct 17, 2020

  1. Fix Maximum call stack size exception in computeLabelSizes (#7883)

    Calling Math.max with a large number of values was throwing an exception.
    Tracking the current largest width and height as the widths and heights are
    built up should be faster and avoids the exception.
    silentmatt authored Oct 17, 2020

    Verified

    This commit was signed with the committer’s verified signature.
    BethGriggs Bethany Griggs
    Copy the full SHA
    42ed589 View commit details

Commits on Oct 18, 2020

  1. Verified

    This commit was signed with the committer’s verified signature.
    BethGriggs Bethany Griggs
    Copy the full SHA
    d919188 View commit details
  2. When objects are merged together, the target prototype can be pollute…

    …d. (#7918)
    
    * When objects are merged together, the target prototype can be polluted.
    
    This change blocks updates to the `__proto__` key during config merge
    etimberg authored Oct 18, 2020

    Verified

    This commit was signed with the committer’s verified signature.
    BethGriggs Bethany Griggs
    Copy the full SHA
    dff7140 View commit details
  3. Verified

    This commit was signed with the committer’s verified signature.
    BethGriggs Bethany Griggs
    Copy the full SHA
    1d92605 View commit details
4 changes: 3 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
language: node_js
node_js:
- lts/*
# Using node 12.18.2 instead of lts
# https://github.com/chartjs/Chart.js/issues/7863#issuecomment-705222874
- "12.18.2"

before_install:
- "export CHROME_BIN=/usr/bin/google-chrome"
4 changes: 1 addition & 3 deletions docs/getting-started/integration.md
Original file line number Diff line number Diff line change
@@ -39,9 +39,7 @@ var myChart = new Chart(ctx, {...});
```javascript
// Rollup
{
external: {
['moment']
}
external: ['moment']
}
```

2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@
"name": "chart.js",
"homepage": "https://www.chartjs.org",
"description": "Simple HTML5 charts using the canvas element.",
"version": "2.9.3",
"version": "2.9.4",
"license": "MIT",
"jsdelivr": "dist/Chart.min.js",
"unpkg": "dist/Chart.min.js",
2 changes: 1 addition & 1 deletion scripts/deploy.sh
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@ TARGET_REPO_URL="https://$GITHUB_AUTH_TOKEN@github.com/chartjs/chartjs.github.io
VERSION_REGEX='[[:digit:]]+.[[:digit:]]+.[[:digit:]]+(-.*)?'

# Make sure that this script is executed only for the release and master branches
if [ "$TRAVIS_BRANCH" == "release" ]; then
if [ "$TRAVIS_BRANCH" =~ ^release.*$ ]; then
# Travis executes this script from the repository root, so at the same level than package.json
VERSION=$(node -p -e "require('./package.json').version")
elif [ "$TRAVIS_BRANCH" == "master" ]; then
2 changes: 1 addition & 1 deletion scripts/release.sh
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@

set -e

if [ "$TRAVIS_BRANCH" != "release" ]; then
if [[ ! "$TRAVIS_BRANCH" =~ ^release.*$ ]]; then
echo "Skipping release because this is not the 'release' branch"
exit 0
fi
8 changes: 4 additions & 4 deletions src/core/core.controller.js
Original file line number Diff line number Diff line change
@@ -41,7 +41,7 @@ defaults._set('global', {
* returns a deep copy of the result, thus doesn't alter inputs.
*/
function mergeScaleConfig(/* config objects ... */) {
return helpers.merge({}, [].slice.call(arguments), {
return helpers.merge(Object.create(null), [].slice.call(arguments), {
merger: function(key, target, source, options) {
if (key === 'xAxes' || key === 'yAxes') {
var slen = source[key].length;
@@ -81,9 +81,9 @@ function mergeScaleConfig(/* config objects ... */) {
* a deep copy of the result, thus doesn't alter inputs.
*/
function mergeConfig(/* config objects ... */) {
return helpers.merge({}, [].slice.call(arguments), {
return helpers.merge(Object.create(null), [].slice.call(arguments), {
merger: function(key, target, source, options) {
var tval = target[key] || {};
var tval = target[key] || Object.create(null);
var sval = source[key];

if (key === 'scales') {
@@ -100,7 +100,7 @@ function mergeConfig(/* config objects ... */) {
}

function initConfig(config) {
config = config || {};
config = config || Object.create(null);

// Do NOT use mergeConfig for the data object because this method merges arrays
// and so would change references to labels and datasets, preventing data updates.
2 changes: 1 addition & 1 deletion src/core/core.datasetController.js
Original file line number Diff line number Diff line change
@@ -275,7 +275,7 @@ helpers.extend(DatasetController.prototype, {
*/
_configure: function() {
var me = this;
me._config = helpers.merge({}, [
me._config = helpers.merge(Object.create(null), [
me.chart.options.datasets[me._type],
me.getDataset(),
], {
3 changes: 2 additions & 1 deletion src/core/core.layouts.js
Original file line number Diff line number Diff line change
@@ -99,7 +99,8 @@ function updateDims(chartArea, params, layout) {
chartArea.h = newHeight;

// return true if chart area changed in layout's direction
return layout.horizontal ? newWidth !== chartArea.w : newHeight !== chartArea.h;
var sizes = layout.horizontal ? [newWidth, chartArea.w] : [newHeight, chartArea.h];
return sizes[0] !== sizes[1] && (!isNaN(sizes[0]) || !isNaN(sizes[1]));
}
}

8 changes: 6 additions & 2 deletions src/core/core.scale.js
Original file line number Diff line number Diff line change
@@ -130,6 +130,8 @@ function computeLabelSizes(ctx, tickFonts, ticks, caches) {
var widths = [];
var heights = [];
var offsets = [];
var widestLabelSize = 0;
var highestLabelSize = 0;
var i, j, jlen, label, tickFont, fontString, cache, lineHeight, width, height, nestedLabel, widest, highest;

for (i = 0; i < length; ++i) {
@@ -157,11 +159,13 @@ function computeLabelSizes(ctx, tickFonts, ticks, caches) {
widths.push(width);
heights.push(height);
offsets.push(lineHeight / 2);
widestLabelSize = Math.max(width, widestLabelSize);
highestLabelSize = Math.max(height, highestLabelSize);
}
garbageCollect(caches, length);

widest = widths.indexOf(Math.max.apply(null, widths));
highest = heights.indexOf(Math.max.apply(null, heights));
widest = widths.indexOf(widestLabelSize);
highest = heights.indexOf(highestLabelSize);

function valueAt(idx) {
return {
2 changes: 1 addition & 1 deletion src/core/core.scaleService.js
Original file line number Diff line number Diff line change
@@ -22,7 +22,7 @@ module.exports = {
},
getScaleDefaults: function(type) {
// Return the scale defaults merged with the global settings so that we always use the latest ones
return this.defaults.hasOwnProperty(type) ? helpers.merge({}, [defaults.scale, this.defaults[type]]) : {};
return this.defaults.hasOwnProperty(type) ? helpers.merge(Object.create(null), [defaults.scale, this.defaults[type]]) : {};
},
updateScaleDefaults: function(type, additions) {
var me = this;
18 changes: 17 additions & 1 deletion src/helpers/helpers.core.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
'use strict';

function isValidKey(key) {
return ['__proto__', 'prototype', 'constructor'].indexOf(key) === -1;
}

/**
* @namespace Chart.helpers
*/
@@ -175,7 +179,7 @@ var helpers = {
}

if (helpers.isObject(source)) {
var target = {};
var target = Object.create(source);
var keys = Object.keys(source);
var klen = keys.length;
var k = 0;
@@ -196,6 +200,12 @@ var helpers = {
* @private
*/
_merger: function(key, target, source, options) {
if (!isValidKey(key)) {
// We want to ensure we do not copy prototypes over
// as this can pollute global namespaces
return;
}

var tval = target[key];
var sval = source[key];

@@ -211,6 +221,12 @@ var helpers = {
* @private
*/
_mergerIf: function(key, target, source) {
if (!isValidKey(key)) {
// We want to ensure we do not copy prototypes over
// as this can pollute global namespaces
return;
}

var tval = target[key];
var sval = source[key];

40 changes: 40 additions & 0 deletions test/specs/core.layouts.tests.js
Original file line number Diff line number Diff line change
@@ -653,5 +653,45 @@ describe('Chart.layouts', function() {
expect(yAxis.width).toBeCloseToPixel(33);
expect(yAxis.ticks).toEqual(['2.5', '2.0', '1.5', '1.0', '0.5', '0']);
});

it('should correctly handle NaN dimensions', function() {

// issue #7761: Maximum call stack size exceeded
var chartContainer = document.createElement('div');
chartContainer.style.width = '600px';
chartContainer.style.height = '400px';

var chartCanvas = document.createElement('canvas');
chartContainer.appendChild(chartCanvas);

var chart = new Chart(chartCanvas, {
type: 'line',
responsive: true,
data: {
labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3]
}]
},
options: {
scales: {
yAxes: [{
type: 'linear',
label: 'first axis',
position: 'right'
}, {
type: 'linear',
label: 'second axis',
position: 'right'
}]
}
}
});

expect(chart.width).toBeNaN();
expect(chart.height).toBeNaN();

});
});
});
29 changes: 29 additions & 0 deletions test/specs/helpers.core.tests.js
Original file line number Diff line number Diff line change
@@ -265,6 +265,11 @@ describe('Chart.helpers.core', function() {
});

describe('clone', function() {
it('should not allow prototype pollution', function() {
var test = helpers.clone(JSON.parse('{"__proto__":{"polluted": true}}'));
expect(test.prototype).toBeUndefined();
expect(Object.prototype.polluted).toBeUndefined();
});
it('should clone primitive values', function() {
expect(helpers.clone()).toBe(undefined);
expect(helpers.clone(null)).toBe(null);
@@ -301,9 +306,33 @@ describe('Chart.helpers.core', function() {
expect(output.o.a).not.toBe(a1);
expect(output.a).not.toBe(a0);
});
it('should preserve prototype of objects', function() {
// https://github.com/chartjs/Chart.js/issues/7340
function MyConfigObject(s) {
this._s = s;
}
MyConfigObject.prototype.func = function() {
return 10;
};
var original = new MyConfigObject('something');
var output = helpers.merge({}, {
plugins: [{
test: original
}]
});
var clone = output.plugins[0].test;
expect(clone).toBeInstanceOf(MyConfigObject);
expect(clone).toEqual(original);
expect(clone === original).toBeFalse();
});
});

describe('merge', function() {
it('should not allow prototype pollution', function() {
var test = helpers.merge({}, JSON.parse('{"__proto__":{"polluted": true}}'));
expect(test.prototype).toBeUndefined();
expect(Object.prototype.polluted).toBeUndefined();
});
it('should update target and return it', function() {
var target = {a: 1};
var result = helpers.merge(target, {a: 2, b: 'foo'});