Skip to content

Commit 7a22ca4

Browse files
committed
move (back) crawl and friends from coerce.js -> plot_schema.js
- (now that this doesn't cause circular deps anymore)
1 parent 8cf071b commit 7a22ca4

File tree

5 files changed

+102
-146
lines changed

5 files changed

+102
-146
lines changed

src/lib/coerce.js

+4-132
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,12 @@
1111

1212
var isNumeric = require('fast-isnumeric');
1313
var tinycolor = require('tinycolor2');
14-
var nestedProperty = require('./nested_property');
15-
var isPlainObject = require('./is_plain_object');
16-
var filterUnique = require('./filter_unique');
1714

1815
var getColorscale = require('../components/colorscale/get_scale');
1916
var colorscaleNames = Object.keys(require('../components/colorscale/scales'));
17+
var nestedProperty = require('./nested_property');
2018

21-
var idRegex = /^([2-9]|[1-9][0-9]+)$/;
22-
23-
function isValObject(obj) {
24-
return obj && obj.valType !== undefined;
25-
}
19+
var ID_REGEX = /^([2-9]|[1-9][0-9]+)$/;
2620

2721
exports.valObjects = {
2822
data_array: {
@@ -174,7 +168,7 @@ exports.valObjects = {
174168
coerceFunction: function(v, propOut, dflt) {
175169
var dlen = dflt.length;
176170
if(typeof v === 'string' && v.substr(0, dlen) === dflt &&
177-
idRegex.test(v.substr(dlen))) {
171+
ID_REGEX.test(v.substr(dlen))) {
178172
propOut.set(v);
179173
return;
180174
}
@@ -186,7 +180,7 @@ exports.valObjects = {
186180

187181
if(v === dflt) return true;
188182
if(typeof v !== 'string') return false;
189-
if(v.substr(0, dlen) === dflt && idRegex.test(v.substr(dlen))) {
183+
if(v.substr(0, dlen) === dflt && ID_REGEX.test(v.substr(dlen))) {
190184
return true;
191185
}
192186

@@ -361,125 +355,3 @@ exports.validate = function(value, opts) {
361355
valObject.coerceFunction(value, propMock, failed, opts);
362356
return out !== failed;
363357
};
364-
365-
/*
366-
* returns true for a valid value object and false for tree nodes in the attribute hierarchy
367-
*/
368-
exports.isValObject = isValObject;
369-
370-
exports.IS_SUBPLOT_OBJ = '_isSubplotObj';
371-
exports.IS_LINKED_TO_ARRAY = '_isLinkedToArray';
372-
exports.DEPRECATED = '_deprecated';
373-
374-
// list of underscore attributes to keep in schema as is
375-
exports.UNDERSCORE_ATTRS = [exports.IS_SUBPLOT_OBJ, exports.IS_LINKED_TO_ARRAY, exports.DEPRECATED];
376-
377-
/**
378-
* Crawl the attribute tree, recursively calling a callback function
379-
*
380-
* @param {object} attrs
381-
* The node of the attribute tree (e.g. the root) from which recursion originates
382-
* @param {Function} callback
383-
* A callback function with the signature:
384-
* @callback callback
385-
* @param {object} attr an attribute
386-
* @param {String} attrName name string
387-
* @param {object[]} attrs all the attributes
388-
* @param {Number} level the recursion level, 0 at the root
389-
* @param {Number} [specifiedLevel]
390-
* The level in the tree, in order to let the callback function detect descend or backtrack,
391-
* typically unsupplied (implied 0), just used by the self-recursive call.
392-
* The necessity arises because the tree traversal is not controlled by callback return values.
393-
* The decision to not use callback return values for controlling tree pruning arose from
394-
* the goal of keeping the crawler backwards compatible. Observe that one of the pruning conditions
395-
* precedes the callback call.
396-
*
397-
* @return {object} transformOut
398-
* copy of transformIn that contains attribute defaults
399-
*/
400-
exports.crawl = function(attrs, callback, specifiedLevel) {
401-
var level = specifiedLevel || 0;
402-
Object.keys(attrs).forEach(function(attrName) {
403-
var attr = attrs[attrName];
404-
405-
if(exports.UNDERSCORE_ATTRS.indexOf(attrName) !== -1) return;
406-
407-
callback(attr, attrName, attrs, level);
408-
409-
if(isValObject(attr)) return;
410-
if(isPlainObject(attr)) exports.crawl(attr, callback, level + 1);
411-
});
412-
};
413-
414-
/**
415-
* Find all data array attributes in a given trace object - including
416-
* `arrayOk` attributes.
417-
*
418-
* @param {object} trace
419-
* full trace object that contains a reference to `_module.attributes`
420-
*
421-
* @return {array} arrayAttributes
422-
* list of array attributes for the given trace
423-
*/
424-
exports.findArrayAttributes = function(trace) {
425-
var arrayAttributes = [],
426-
stack = [];
427-
428-
/**
429-
* A closure that gathers attribute paths into its enclosed arraySplitAttributes
430-
* Attribute paths are collected iff their leaf node is a splittable attribute
431-
*
432-
* @callback callback
433-
* @param {object} attr an attribute
434-
* @param {String} attrName name string
435-
* @param {object[]} attrs all the attributes
436-
* @param {Number} level the recursion level, 0 at the root
437-
*
438-
* @closureVariable {String[][]} arrayAttributes the set of gathered attributes
439-
* Example of filled closure variable (expected to be initialized to []):
440-
* [["marker","size"],["marker","line","width"],["marker","line","color"]]
441-
*/
442-
function callback(attr, attrName, attrs, level) {
443-
stack = stack.slice(0, level).concat([attrName]);
444-
445-
var splittableAttr = attr.valType === 'data_array' || attr.arrayOk === true;
446-
if(!splittableAttr) return;
447-
448-
var astr = toAttrString(stack);
449-
var val = nestedProperty(trace, astr).get();
450-
if(!Array.isArray(val)) return;
451-
452-
arrayAttributes.push(astr);
453-
}
454-
455-
function toAttrString(stack) {
456-
return stack.join('.');
457-
}
458-
459-
exports.crawl(trace._module.attributes, callback);
460-
461-
if(trace.transforms) {
462-
var transforms = trace.transforms;
463-
464-
for(var i = 0; i < transforms.length; i++) {
465-
var transform = transforms[i];
466-
467-
stack = ['transforms[' + i + ']'];
468-
exports.crawl(transform._module.attributes, callback, 1);
469-
}
470-
}
471-
472-
// Look into the fullInput module attributes for array attributes
473-
// to make sure that 'custom' array attributes are detected.
474-
//
475-
// At the moment, we need this block to make sure that
476-
// ohlc and candlestick 'open', 'high', 'low', 'close' can be
477-
// used with filter ang groupby transforms.
478-
if(trace._fullInput) {
479-
exports.crawl(trace._fullInput._module.attributes, callback);
480-
481-
arrayAttributes = filterUnique(arrayAttributes);
482-
}
483-
484-
return arrayAttributes;
485-
};

src/lib/index.js

-7
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,6 @@ lib.coerce = coerceModule.coerce;
2323
lib.coerce2 = coerceModule.coerce2;
2424
lib.coerceFont = coerceModule.coerceFont;
2525
lib.validate = coerceModule.validate;
26-
lib.isValObject = coerceModule.isValObject;
27-
lib.crawl = coerceModule.crawl;
28-
lib.findArrayAttributes = coerceModule.findArrayAttributes;
29-
lib.IS_SUBPLOT_OBJ = coerceModule.IS_SUBPLOT_OBJ;
30-
lib.IS_LINKED_TO_ARRAY = coerceModule.IS_LINKED_TO_ARRAY;
31-
lib.DEPRECATED = coerceModule.DEPRECATED;
32-
lib.UNDERSCORE_ATTRS = coerceModule.UNDERSCORE_ATTRS;
3326

3427
var datesModule = require('./dates');
3528
lib.dateTime2ms = datesModule.dateTime2ms;

src/plot_api/plot_schema.js

+94-5
Original file line numberDiff line numberDiff line change
@@ -65,26 +65,114 @@ exports.get = function() {
6565
transforms: transforms,
6666

6767

68+
/**
69+
* Crawl the attribute tree, recursively calling a callback function
70+
*
71+
* @param {object} attrs
72+
* The node of the attribute tree (e.g. the root) from which recursion originates
73+
* @param {Function} callback
74+
* A callback function with the signature:
75+
* @callback callback
76+
* @param {object} attr an attribute
77+
* @param {String} attrName name string
78+
* @param {object[]} attrs all the attributes
79+
* @param {Number} level the recursion level, 0 at the root
80+
* @param {Number} [specifiedLevel]
81+
* The level in the tree, in order to let the callback function detect descend or backtrack,
82+
* typically unsupplied (implied 0), just used by the self-recursive call.
83+
* The necessity arises because the tree traversal is not controlled by callback return values.
84+
* The decision to not use callback return values for controlling tree pruning arose from
85+
* the goal of keeping the crawler backwards compatible. Observe that one of the pruning conditions
86+
* precedes the callback call.
87+
*
88+
* @return {object} transformOut
89+
* copy of transformIn that contains attribute defaults
90+
*/
91+
exports.crawl = function(attrs, callback, specifiedLevel) {
92+
var level = specifiedLevel || 0;
6893

94+
Object.keys(attrs).forEach(function(attrName) {
95+
var attr = attrs[attrName];
6996

70-
PlotSchema.crawl = Lib.crawl;
97+
if(UNDERSCORE_ATTRS.indexOf(attrName) !== -1) return;
7198

72-
PlotSchema.isValObject = Lib.isValObject;
99+
callback(attr, attrName, attrs, level);
73100

101+
if(exports.isValObject(attr)) return;
74102

103+
if(Lib.isPlainObject(attr)) exports.crawl(attr, callback, level + 1);
104+
});
105+
};
75106

107+
/** Is object a value object (or a container object)?
108+
*
109+
* @param {object} obj
110+
* @return {boolean}
111+
* returns true for a valid value object and
112+
* false for tree nodes in the attribute hierarchy
113+
*/
114+
exports.isValObject = function(obj) {
115+
return obj && obj.valType !== undefined;
116+
};
76117

118+
/**
119+
* Find all data array attributes in a given trace object - including
120+
* `arrayOk` attributes.
121+
*
122+
* @param {object} trace
123+
* full trace object that contains a reference to `_module.attributes`
124+
*
125+
* @return {array} arrayAttributes
126+
* list of array attributes for the given trace
127+
*/
128+
exports.findArrayAttributes = function(trace) {
129+
var arrayAttributes = [],
130+
stack = [];
77131

132+
function callback(attr, attrName, attrs, level) {
133+
stack = stack.slice(0, level).concat([attrName]);
78134

135+
var splittableAttr = attr.valType === 'data_array' || attr.arrayOk === true;
136+
if(!splittableAttr) return;
137+
138+
var astr = toAttrString(stack);
139+
var val = Lib.nestedProperty(trace, astr).get();
140+
if(!Array.isArray(val)) return;
141+
142+
arrayAttributes.push(astr);
79143
}
80144

145+
function toAttrString(stack) {
146+
return stack.join('.');
147+
}
81148

149+
exports.crawl(trace._module.attributes, callback);
82150

151+
if(trace.transforms) {
152+
var transforms = trace.transforms;
83153

154+
for(var i = 0; i < transforms.length; i++) {
155+
var transform = transforms[i];
156+
157+
stack = ['transforms[' + i + ']'];
158+
exports.crawl(transform._module.attributes, callback, 1);
159+
}
84160
}
85-
}
86161

162+
// Look into the fullInput module attributes for array attributes
163+
// to make sure that 'custom' array attributes are detected.
164+
//
165+
// At the moment, we need this block to make sure that
166+
// ohlc and candlestick 'open', 'high', 'low', 'close' can be
167+
// used with filter ang groupby transforms.
168+
if(trace._fullInput) {
169+
exports.crawl(trace._fullInput._module.attributes, callback);
170+
171+
arrayAttributes = Lib.filterUnique(arrayAttributes);
172+
}
87173

174+
return arrayAttributes;
175+
};
88176

89177
function getTraceAttributes(type) {
90178
var _module, basePlotModule;
@@ -209,7 +297,7 @@ function mergeValTypeAndRole(attrs) {
209297
}
210298

211299
function callback(attr, attrName, attrs) {
212-
if(PlotSchema.isValObject(attr)) {
300+
if(exports.isValObject(attr)) {
213301
if(attr.valType === 'data_array') {
214302
// all 'data_array' attrs have role 'data'
215303
attr.role = 'data';
@@ -227,7 +315,7 @@ function mergeValTypeAndRole(attrs) {
227315
}
228316
}
229317

230-
Lib.crawl(attrs, callback);
318+
exports.crawl(attrs, callback);
231319
}
232320

233321
function formatArrayContainers(attrs) {
@@ -244,6 +332,7 @@ function formatArrayContainers(attrs) {
244332
attrs[attrName] = { items: {} };
245333
attrs[attrName].items[itemName] = attr;
246334
attrs[attrName].role = 'object';
335+
}
247336

248337
exports.crawl(attrs, callback);
249338
}

src/transforms/filter.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
'use strict';
1010

1111
var Lib = require('../lib');
12+
var PlotSchema = require('../plot_api/plot_schema');
1213
var axisIds = require('../plots/cartesian/axis_ids');
1314
var autoType = require('../plots/cartesian/axis_autotype');
1415
var setConvert = require('../plots/cartesian/set_convert');
@@ -131,7 +132,7 @@ exports.calcTransform = function(gd, trace, opts) {
131132

132133
var dataToCoord = getDataToCoordFunc(gd, trace, target),
133134
filterFunc = getFilterFunc(opts, dataToCoord),
134-
arrayAttrs = Lib.findArrayAttributes(trace),
135+
arrayAttrs = PlotSchema.findArrayAttributes(trace),
135136
originalArrays = {};
136137

137138
// copy all original array attribute values,

src/transforms/groupby.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
'use strict';
1010

1111
var Lib = require('../lib');
12+
var PlotSchema = require('../plot_api/plot_schema');
1213

1314
exports.moduleType = 'transform';
1415

@@ -125,7 +126,7 @@ function transformOne(trace, state) {
125126
newData = new Array(groupNames.length),
126127
len = groups.length;
127128

128-
var arrayAttrs = Lib.findArrayAttributes(trace);
129+
var arrayAttrs = PlotSchema.findArrayAttributes(trace);
129130

130131
var style = opts.style || {};
131132

0 commit comments

Comments
 (0)