Skip to content

Commit 926bfd5

Browse files
authored
Merge pull request #697 from plotly/validate
Introducing Plotly.validate(data, layout)
2 parents ead4bc5 + 54a6ed0 commit 926bfd5

File tree

8 files changed

+876
-29
lines changed

8 files changed

+876
-29
lines changed

src/components/colorscale/is_valid_scale_array.js

+17-15
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,23 @@ var tinycolor = require('tinycolor2');
1313

1414

1515
module.exports = function isValidScaleArray(scl) {
16-
var isValid = true,
17-
highestVal = 0,
18-
si;
19-
20-
if(!Array.isArray(scl)) return false;
21-
else {
22-
if(+scl[0][0] !== 0 || +scl[scl.length - 1][0] !== 1) return false;
23-
for(var i = 0; i < scl.length; i++) {
24-
si = scl[i];
25-
if(si.length !== 2 || +si[0] < highestVal || !tinycolor(si[1]).isValid()) {
26-
isValid = false;
27-
break;
28-
}
29-
highestVal = +si[0];
16+
var highestVal = 0;
17+
18+
if(!Array.isArray(scl) || scl.length < 2) return false;
19+
20+
if(!scl[0] || !scl[scl.length - 1]) return false;
21+
22+
if(+scl[0][0] !== 0 || +scl[scl.length - 1][0] !== 1) return false;
23+
24+
for(var i = 0; i < scl.length; i++) {
25+
var si = scl[i];
26+
27+
if(si.length !== 2 || +si[0] < highestVal || !tinycolor(si[1]).isValid()) {
28+
return false;
3029
}
31-
return isValid;
30+
31+
highestVal = +si[0];
3232
}
33+
34+
return true;
3335
};

src/core.js

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ exports.setPlotConfig = require('./plot_api/set_plot_config');
3333
exports.register = Plotly.register;
3434
exports.toImage = require('./plot_api/to_image');
3535
exports.downloadImage = require('./snapshot/download');
36+
exports.validate = require('./plot_api/validate');
3637

3738
// plot icons
3839
exports.Icons = require('../build/ploticon');

src/lib/coerce.js

+56-11
Original file line numberDiff line numberDiff line change
@@ -99,16 +99,14 @@ exports.valObjects = {
9999
// TODO 'values shouldn't be in there (edge case: 'dash' in Scatter)
100100
otherOpts: ['dflt', 'noBlank', 'strict', 'arrayOk', 'values'],
101101
coerceFunction: function(v, propOut, dflt, opts) {
102-
if(opts.strict === true && typeof v !== 'string') {
103-
propOut.set(dflt);
104-
return;
105-
}
102+
if(typeof v !== 'string') {
103+
var okToCoerce = (typeof v === 'number');
106104

107-
var s = String(v);
108-
if(v === undefined || (opts.noBlank === true && !s)) {
109-
propOut.set(dflt);
105+
if(opts.strict === true || !okToCoerce) propOut.set(dflt);
106+
else propOut.set(String(v));
110107
}
111-
else propOut.set(s);
108+
else if(opts.noBlank && !v) propOut.set(dflt);
109+
else propOut.set(v);
112110
}
113111
},
114112
color: {
@@ -162,11 +160,11 @@ exports.valObjects = {
162160
subplotid: {
163161
description: [
164162
'An id string of a subplot type (given by dflt), optionally',
165-
'followed by an integer >1. e.g. if dflt=\'geo\', we can have',
163+
'followed by an integer >1. e.g. if dflt=\'geo\', we can have',
166164
'\'geo\', \'geo2\', \'geo3\', ...'
167165
].join(' '),
168-
requiredOpts: [],
169-
otherOpts: ['dflt'],
166+
requiredOpts: ['dflt'],
167+
otherOpts: [],
170168
coerceFunction: function(v, propOut, dflt) {
171169
var dlen = dflt.length;
172170
if(typeof v === 'string' && v.substr(0, dlen) === dflt &&
@@ -175,6 +173,18 @@ exports.valObjects = {
175173
return;
176174
}
177175
propOut.set(dflt);
176+
},
177+
validateFunction: function(v, opts) {
178+
var dflt = opts.dflt,
179+
dlen = dflt.length;
180+
181+
if(v === dflt) return true;
182+
if(typeof v !== 'string') return false;
183+
if(v.substr(0, dlen) === dflt && idRegex.test(v.substr(dlen))) {
184+
return true;
185+
}
186+
187+
return false;
178188
}
179189
},
180190
flaglist: {
@@ -239,6 +249,22 @@ exports.valObjects = {
239249
}
240250

241251
propOut.set(vOut);
252+
},
253+
validateFunction: function(v, opts) {
254+
if(!Array.isArray(v)) return false;
255+
256+
var items = opts.items;
257+
258+
if(v.length !== items.length) return false;
259+
260+
// valid when all items are valid
261+
for(var i = 0; i < items.length; i++) {
262+
var isItemValid = exports.validate(v[i], opts.items[i]);
263+
264+
if(!isItemValid) return false;
265+
}
266+
267+
return true;
242268
}
243269
}
244270
};
@@ -309,3 +335,22 @@ exports.coerceFont = function(coerce, attr, dfltObj) {
309335

310336
return out;
311337
};
338+
339+
exports.validate = function(value, opts) {
340+
var valObject = exports.valObjects[opts.valType];
341+
342+
if(opts.arrayOk && Array.isArray(value)) return true;
343+
344+
if(valObject.validateFunction) {
345+
return valObject.validateFunction(value, opts);
346+
}
347+
348+
var failed = {},
349+
out = failed,
350+
propMock = { set: function(v) { out = v; } };
351+
352+
// 'failed' just something mutable that won't be === anything else
353+
354+
valObject.coerceFunction(value, propMock, failed, opts);
355+
return out !== failed;
356+
};

src/lib/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ lib.valObjects = coerceModule.valObjects;
2121
lib.coerce = coerceModule.coerce;
2222
lib.coerce2 = coerceModule.coerce2;
2323
lib.coerceFont = coerceModule.coerceFont;
24+
lib.validate = coerceModule.validate;
2425

2526
var datesModule = require('./dates');
2627
lib.dateTime2ms = datesModule.dateTime2ms;

0 commit comments

Comments
 (0)