Comparing version 2.0.3 to 2.1.0
@@ -1,6 +0,46 @@ | ||
var util = require('util'); | ||
var _ = require('lodash'); | ||
var inflection = require('inflection'); | ||
var merge = require('object-merge'); | ||
var inflection = require('inflection') | ||
var merge = require('object-merge') | ||
var isArray = function(item) { | ||
return typeof item === 'object' && item.length !== undefined | ||
} | ||
var isEmpty = function(item) { | ||
return !item || (typeof item === 'object' && !Object.keys(item).length) | ||
} | ||
var where = function(collection, props) { | ||
return collection.map(item => { | ||
for (var attribute in props) { | ||
let value = props[attribute] | ||
if (item[attribute] !== value) { | ||
return false | ||
} | ||
} | ||
return true | ||
}) | ||
} | ||
var findWhere = function(collection, props) { | ||
let matches = collection.filter(item => { | ||
for (var attribute in props) { | ||
let value = props[attribute] | ||
if (item[attribute] !== value) { | ||
return false | ||
} | ||
} | ||
return true | ||
}) | ||
if (!matches.length) { | ||
return false | ||
} | ||
return matches[0] | ||
} | ||
function Treeize(options) { | ||
@@ -19,3 +59,3 @@ this.baseOptions = { | ||
log: false, | ||
}; | ||
} | ||
@@ -29,3 +69,3 @@ this.data = { | ||
tree: [], | ||
}; | ||
} | ||
@@ -39,12 +79,12 @@ this.stats = { | ||
sources: 0, | ||
}; | ||
} | ||
// set default options (below) | ||
this.resetOptions(); | ||
this.resetOptions() | ||
if (options) { | ||
this.options(options); | ||
this.options(options) | ||
} | ||
return this; | ||
return this | ||
} | ||
@@ -54,19 +94,19 @@ | ||
if (this._options.log) { | ||
console.log.apply(this, arguments); | ||
console.log.apply(this, arguments) | ||
} | ||
return this; | ||
}; | ||
return this | ||
} | ||
Treeize.prototype.getData = function() { | ||
return this.data.tree; | ||
}; | ||
return this.data.tree | ||
} | ||
Treeize.prototype.getSeedData = function() { | ||
return this.data.seed; | ||
}; | ||
return this.data.seed | ||
} | ||
Treeize.prototype.getStats = function() { | ||
return this.stats; | ||
}; | ||
return this.stats | ||
} | ||
@@ -79,65 +119,65 @@ /* | ||
if (!row) { | ||
return this.data.signature; | ||
return this.data.signature | ||
} | ||
// start timer | ||
var t1 = (new Date()).getTime(); | ||
var t1 = (new Date()).getTime() | ||
// sets the signature as fixed (or not) when manually set | ||
this.data.signature.isFixed = auto !== true; | ||
this.data.signature.isFixed = auto !== true | ||
var nodes = this.data.signature.nodes = []; | ||
var isArray = _.isArray(row); | ||
var opt = merge(this._options, options || {}); | ||
var nodes = this.data.signature.nodes = [] | ||
var isRowAnArray = isArray(row) | ||
var opt = merge(this._options, options || {}) | ||
this.data.signature.type = isArray ? 'array' : 'object'; | ||
this.data.signature.type = isArray ? 'array' : 'object' | ||
_.each(row, function(value, key) { | ||
// set up attribute | ||
for (var key in row) { | ||
let value = row[key] | ||
var attr = {} | ||
attr.key = typeof key === 'number' ? key : key;//.replace(/^[\*\-\+]|[\*\-\+]$/g,''); | ||
attr.fullPath = isArray ? value : key; | ||
attr.split = attr.fullPath.split(opt.input.delimiter); | ||
attr.path = attr.split.slice(0,attr.split.length-1).join(opt.input.delimiter); | ||
attr.parent = attr.split.slice(0,attr.split.length-2).join(opt.input.delimiter);//.replace(/^[\*\-\+]|[\*\-\+]$/g,''); | ||
attr.node = attr.split[attr.split.length - 2]; | ||
attr.attr = attr.split[attr.split.length - 1]; | ||
attr.key = typeof key === 'number' ? key : key//.replace(/^[\*\-\+]|[\*\-\+]$/g,'') | ||
attr.fullPath = isRowAnArray ? value : key | ||
attr.split = attr.fullPath.split(opt.input.delimiter) | ||
attr.path = attr.split.slice(0,attr.split.length-1).join(opt.input.delimiter) | ||
attr.parent = attr.split.slice(0,attr.split.length-2).join(opt.input.delimiter)//.replace(/^[\*\-\+]|[\*\-\+]$/g,'') | ||
attr.node = attr.split[attr.split.length - 2] | ||
attr.attr = attr.split[attr.split.length - 1] | ||
if (attr.attr.match(/\*/gi)) { | ||
attr.attr = attr.attr.replace(/[\*]/gi,''); | ||
attr.pk = true; | ||
attr.attr = attr.attr.replace(/[\*]/gi,'') | ||
attr.pk = true | ||
} | ||
if (attr.pk) { | ||
this.log('primary key detected in node "' + attr.attr + '"'); | ||
} | ||
// if (attr.pk) { | ||
// this.log('primary key detected in node "' + attr.attr + '"') | ||
// } | ||
// set up node reference | ||
var node = _.findWhere(nodes, { path: attr.path }); | ||
var node = findWhere(nodes, { path: attr.path }) | ||
if (!node) { | ||
node = { path: attr.path, attributes: [], blueprint: [] }; | ||
nodes.push(node); | ||
node = { path: attr.path, attributes: [], blueprint: [] } | ||
nodes.push(node) | ||
} | ||
node.isCollection = !attr.node || (opt.input.detectCollections && inflection.pluralize(attr.node) === attr.node); | ||
node.isCollection = !attr.node || (opt.input.detectCollections && inflection.pluralize(attr.node) === attr.node) | ||
var collectionFlag = attr.node && attr.node.match(/^[\-\+]|[\-\+]$/g); | ||
var collectionFlag = attr.node && attr.node.match(/^[\-\+]|[\-\+]$/g) | ||
if (collectionFlag) { | ||
this.log('collection flag "' + collectionFlag + '" detected in node "' + attr.node + '"'); | ||
node.flags = true; | ||
node.isCollection = attr.node.match(/^\+|\+$/g); | ||
attr.node = attr.node.replace(/^[\*\-\+]|[\*\-\+]$/g,''); // clean node | ||
//this.log('collection flag "' + collectionFlag + '" detected in node "' + attr.node + '"') | ||
node.flags = true | ||
node.isCollection = attr.node.match(/^\+|\+$/g) | ||
attr.node = attr.node.replace(/^[\*\-\+]|[\*\-\+]$/g,'') // clean node | ||
} | ||
node.name = attr.node; | ||
node.depth = attr.split.length - 1; | ||
node.parent = attr.split.slice(0, attr.split.length - 2).join(opt.input.delimiter); | ||
node.attributes.push({ name: attr.attr, key: attr.key }); | ||
node.name = attr.node | ||
node.depth = attr.split.length - 1 | ||
node.parent = attr.split.slice(0, attr.split.length - 2).join(opt.input.delimiter) | ||
node.attributes.push({ name: attr.attr, key: attr.key }) | ||
if (attr.pk) { | ||
this.log('adding node to blueprint'); | ||
node.flags = true; | ||
node.blueprint.push({ name: attr.attr, key: attr.key }); | ||
//this.log('adding node to blueprint') | ||
node.flags = true | ||
node.blueprint.push({ name: attr.attr, key: attr.key }) | ||
} | ||
}, this); | ||
} | ||
@@ -147,63 +187,62 @@ // backfill blueprint when not specifically defined | ||
if (!node.blueprint.length) { | ||
node.blueprint = node.attributes; | ||
node.blueprint = node.attributes | ||
} | ||
}); | ||
}) | ||
nodes.sort(function(a, b) { return a.depth < b.depth ? -1 : 1; }); | ||
nodes.sort(function(a, b) { return a.depth < b.depth ? -1 : 1 }) | ||
// end timer and add time | ||
var t2 = ((new Date()).getTime() - t1); | ||
this.stats.time.signatures += t2; | ||
this.stats.time.total += t2; | ||
var t2 = ((new Date()).getTime() - t1) | ||
this.stats.time.signatures += t2 | ||
this.stats.time.total += t2 | ||
return this; | ||
}; | ||
return this | ||
} | ||
Treeize.prototype.getSignature = function() { | ||
return this.signature(); | ||
}; | ||
return this.signature() | ||
} | ||
Treeize.prototype.setSignature = function(row, options) { | ||
return this.signature(row, options); | ||
}; | ||
return this.signature(row, options) | ||
} | ||
Treeize.prototype.setSignatureAuto = function(row, options) { | ||
return this.signature(row, options, true); | ||
}; | ||
return this.signature(row, options, true) | ||
} | ||
Treeize.prototype.clearSignature = function() { | ||
this.data.signature = { nodes: [], type: null }; | ||
this.data.signature.isFixed = false; | ||
this.data.signature = { nodes: [], type: null } | ||
this.data.signature.isFixed = false | ||
return this; | ||
}; | ||
return this | ||
} | ||
Treeize.prototype.grow = function(data, options) { | ||
var opt = merge(this._options, options || {}); | ||
var opt = merge(this._options, options || {}) | ||
// chain past if no data to grow | ||
if (!data || !_.isArray(data) || !data.length) { | ||
return this; | ||
if (typeof data !== 'object' || !data.length) { | ||
return this | ||
} | ||
this.log('OPTIONS>', opt); | ||
//this.log('OPTIONS>', opt) | ||
// locate existing signature (when sharing signatures between data sources) | ||
var signature = this.getSignature(); | ||
var signature = this.getSignature() | ||
// set data uniformity (locally) to true to avoid signature fetching on data rows | ||
if (_.isArray(data[0])) { | ||
opt.input.uniformRows = true; | ||
if (isArray(data[0])) { | ||
opt.input.uniformRows = true | ||
} | ||
if (!signature.nodes.length) { | ||
this.log('setting signature from first row of data (auto)'); | ||
//this.log('setting signature from first row of data (auto)') | ||
// set signature from first row | ||
signature = this.setSignatureAuto(data[0], options).getSignature(); | ||
signature = this.setSignatureAuto(data[0], options).getSignature() | ||
// remove header row in flat array data (avoids processing headers as actual values) | ||
if (_.isArray(data[0])) { | ||
var originalData = data; | ||
data = []; | ||
if (isArray(data[0])) { | ||
var originalData = data | ||
data = [] | ||
@@ -213,95 +252,97 @@ // copy data without original signature row before processing | ||
if (index > 0) { | ||
data.push(row); | ||
data.push(row) | ||
} | ||
}); | ||
}) | ||
} | ||
} | ||
if (opt.output.resultsAsObject && _.isArray(this.data.tree)) { | ||
this.data.tree = {}; | ||
if (opt.output.resultsAsObject && isArray(this.data.tree)) { | ||
this.data.tree = {} | ||
} | ||
this.log('SIGNATURE>', util.inspect(this.getSignature(), false, null)); | ||
//this.log('SIGNATURE>', util.inspect(this.getSignature(), false, null)) | ||
this.stats.sources++; | ||
var t1 = (new Date()).getTime(); | ||
this.stats.sources++ | ||
var t1 = (new Date()).getTime() | ||
data.forEach(function(row) { | ||
this.data.seed.push(row); | ||
var trails = {}; // LUT for trails (find parent of new node in trails path) | ||
var trail = base = this.data.tree; // OPTIMIZATION: do we need to reset this trail for each row? | ||
this.log('CURRENT TRAIL STATUS>', trail); | ||
var t = null; | ||
this.data.seed.push(row) | ||
var trails = {} // LUT for trails (find parent of new node in trails path) | ||
var trail = base = this.data.tree // OPTIMIZATION: do we need to reset this trail for each row? | ||
//this.log('CURRENT TRAIL STATUS>', trail) | ||
var t = null | ||
// set initial base object path for non-array datasets | ||
if (opt.output.resultsAsObject) { | ||
trails[''] = trail; | ||
trails[''] = trail | ||
} | ||
if (!this.data.signature.isFixed && !opt.input.uniformRows) { | ||
this.log('setting signature from new row of data (auto)'); | ||
//this.log('setting signature from new row of data (auto)') | ||
// get signature from each row | ||
this.setSignatureAuto(row, opt); | ||
this.log('SIGNATURE>', util.inspect(this.getSignature(), false, null)); | ||
this.setSignatureAuto(row, opt) | ||
//this.log('SIGNATURE>', util.inspect(this.getSignature(), false, null)) | ||
} | ||
this.stats.rows++; | ||
this.stats.rows++ | ||
if (_.where(this.signature().nodes, { flags: true }).length) { | ||
if (where(this.signature().nodes, { flags: true }).length) { | ||
// flags detected within signature, clean attributes of row | ||
_.each(row, function(value, key) { | ||
for (var key in row) { | ||
let value = row[key] | ||
if (typeof key === 'string') { | ||
var clean = key.replace(/^[\*\-\+]|[\*\-\+]$/g,''); | ||
var clean = key.replace(/^[\*\-\+]|[\*\-\+]$/g,'') | ||
if (clean !== key) { | ||
this.log('cleaning key "' + key + '" and embedding as "' + clean + '"'); | ||
row[key.replace(/^[\*\-\+]|[\*\-\+]$/g,'')] = value; // simply embed value at clean path (if not already) | ||
//this.log('cleaning key "' + key + '" and embedding as "' + clean + '"') | ||
row[key.replace(/^[\*\-\+]|[\*\-\+]$/g,'')] = value // simply embed value at clean path (if not already) | ||
} | ||
} | ||
}, this); | ||
} | ||
} | ||
this.signature().nodes.forEach(function(node) { | ||
this.log('PROCESSING NODE>', node); | ||
var blueprint = {}; | ||
var blueprintExtended = {}; | ||
//this.log('PROCESSING NODE>', node) | ||
var blueprint = {} | ||
var blueprintExtended = {} | ||
// create blueprint for locating existing nodes | ||
node.blueprint.forEach(function(attribute) { | ||
var key = (node.path ? (node.path + ':') : '') + attribute.name; | ||
blueprint[attribute.name] = row[attribute.key]; | ||
this.log('creating attribute "' + attribute.name + '" within blueprint', row[attribute.key]); | ||
}, this); | ||
var key = (node.path ? (node.path + ':') : '') + attribute.name | ||
blueprint[attribute.name] = row[attribute.key] | ||
//this.log('creating attribute "' + attribute.name + '" within blueprint', row[attribute.key]) | ||
}, this) | ||
// create full node signature for insertion/updating | ||
node.attributes.forEach(function(attribute) { | ||
var key = (node.path ? (node.path + ':') : '') + attribute.name; | ||
var value = row[attribute.key]; | ||
var key = (node.path ? (node.path + ':') : '') + attribute.name | ||
var value = row[attribute.key] | ||
// insert extended blueprint attributes when not empty (or not pruning) | ||
if (!opt.output.prune || (value !== null && value !== undefined)) { | ||
this.log('creating attribute "' + attribute.name + '" within extended blueprint', row[attribute.key]); | ||
blueprintExtended[attribute.name] = row[attribute.key]; | ||
//this.log('creating attribute "' + attribute.name + '" within extended blueprint', row[attribute.key]) | ||
blueprintExtended[attribute.name] = row[attribute.key] | ||
} | ||
}, this); | ||
}, this) | ||
this.log('EXTENDED BLUEPRINT>', blueprintExtended); | ||
this.log('BLUEPRINT>', blueprint); | ||
//this.log('EXTENDED BLUEPRINT>', blueprintExtended) | ||
//this.log('BLUEPRINT>', blueprint) | ||
// ONLY INSERT IF NOT PRUNED | ||
if (!opt.output.prune || !_.isEmpty(blueprintExtended)) { | ||
if (!opt.output.prune || !isEmpty(blueprintExtended)) { | ||
// IF 0 DEPTH AND RESULTSASOBJECT, EXTEND base | ||
if (opt.output.resultsAsObject && node.depth === 0) { | ||
_.extend(trails[node.path] = trail = base, blueprintExtended); | ||
this.log('extending blueprint onto base>', trail); | ||
Object.assign(trails[node.path] = trail = base, blueprintExtended) | ||
//this.log('extending blueprint onto base>', trail) | ||
// IF base TRAIL IS NOT YET MAPPED | ||
} else if (node.isCollection && !(trail = trails[node.parent])) { | ||
this.log('PARENT TRAIL NOT FOUND (base?)'); | ||
//this.log('PARENT TRAIL NOT FOUND (base?)') | ||
// set up target node if doesn't exist | ||
if (!(trail = _.findWhere(base, blueprint))) { | ||
base.push(trail = blueprintExtended); | ||
if (!(trail = findWhere(base, blueprint))) { | ||
base.push(trail = blueprintExtended) | ||
} else { | ||
_.extend(trail, blueprintExtended); | ||
Object.assign(trail, blueprintExtended) | ||
} | ||
trails[node.path] = trail; | ||
trails[node.path] = trail | ||
@@ -313,16 +354,16 @@ // NORMAL NODE TRAVERSAL | ||
// handle collection nodes | ||
this.log('inserting into collection node', trail); | ||
//this.log('inserting into collection node', trail) | ||
if (!trail[node.name]) { | ||
// node attribute doesnt exist, create array with fresh blueprint | ||
trail[node.name] = [blueprintExtended]; | ||
trails[node.path] = blueprintExtended; | ||
trail[node.name] = [blueprintExtended] | ||
trails[node.path] = blueprintExtended | ||
} else { | ||
// node attribute exists, find or inject blueprint | ||
var t; | ||
if (!(t = _.findWhere(trail[node.name], blueprint))) { | ||
trail[node.name].push(trail = blueprintExtended); | ||
var t | ||
if (!(t = findWhere(trail[node.name], blueprint))) { | ||
trail[node.name].push(trail = blueprintExtended) | ||
} else { | ||
_.extend(t, blueprintExtended); | ||
Object.assign(t, blueprintExtended) | ||
} | ||
trails[node.path] = t || trail; | ||
trails[node.path] = t || trail | ||
} | ||
@@ -332,6 +373,6 @@ } else { | ||
if (trail == base && node.parent === '') { | ||
base.push(trails[node.parent] = trail = {}); | ||
this.log('base insertion'); | ||
base.push(trails[node.parent] = trail = {}) | ||
//this.log('base insertion') | ||
} | ||
trail = trails[node.parent]; | ||
trail = trails[node.parent] | ||
@@ -343,50 +384,51 @@ // ON DEEP NODES, THE PARENT WILL BE TOO LONG AND FAIL ON THE NEXT IF STATEMENT BELOW | ||
// backtrack from parent trail segments until trail found, then create creadcrumbs | ||
var breadcrumbs = []; | ||
var segments = node.parent.split(':'); | ||
var pathAttempt = node.parent; | ||
var segmentsStripped = 0; | ||
var breadcrumbs = [] | ||
var segments = node.parent.split(':') | ||
var numSegments = segments.length | ||
var pathAttempt = node.parent | ||
var segmentsStripped = 0 | ||
this.log('path MISSING for location "' + pathAttempt + '"'); | ||
//this.log('path MISSING for location "' + pathAttempt + '"') | ||
while (!(trail = trails[pathAttempt])) { | ||
segmentsStripped++; | ||
pathAttempt = _.initial(segments, segmentsStripped).join(':'); | ||
this.log('..attempting path location for "' + pathAttempt + '"'); | ||
segmentsStripped++ | ||
pathAttempt = segments.slice(0,numSegments-segmentsStripped).join(':') | ||
//this.log('..attempting path location for "' + pathAttempt + '"') | ||
//infinite loop kickout | ||
if (segmentsStripped > 15) break; | ||
if (segmentsStripped > 15) break | ||
} | ||
this.log('path FOUND for location for "' + pathAttempt + '" after removing ' + segmentsStripped + ' segments'); | ||
//this.log('path FOUND for location for "' + pathAttempt + '" after removing ' + segmentsStripped + ' segments') | ||
// create stored nodes if they don't exist. | ||
_.each(_.rest(segments, segments.length - segmentsStripped), function(segment) { | ||
var isCollection = ((inflection.pluralize(segment) === segment) || segment.match(/^\+|\+$/)) && (!segment.match(/^\-|\-$/)); | ||
segments.slice(numSegments - segmentsStripped).forEach(function(segment) { | ||
var isCollection = ((inflection.pluralize(segment) === segment) || segment.match(/^\+|\+$/)) && (!segment.match(/^\-|\-$/)) | ||
// TODO: add modifier detection | ||
this.log('creating or trailing path segment ' + (isCollection ? '[collection]' : '{object}') + ' "' + segment + '"'); | ||
//this.log('creating or trailing path segment ' + (isCollection ? '[collection]' : '{object}') + ' "' + segment + '"') | ||
segment = segment.replace(/^[\*\-\+]|[\*\-\+]$/g,''); | ||
segment = segment.replace(/^[\*\-\+]|[\*\-\+]$/g,'') | ||
if (isCollection) { | ||
// retrieve or set collection segment and push new trail onto it | ||
(trail[segment] = trail[segment] || []).push(trail = {}); | ||
(trail[segment] = trail[segment] || []).push(trail = {}) | ||
} else { | ||
trail = trail[segment] = trail[segment] || {}; | ||
trail = trail[segment] = trail[segment] || {} | ||
} | ||
}, this); | ||
}) | ||
} | ||
this.log('inserting into non-collection node'); | ||
//this.log('inserting into non-collection node') | ||
//if (!trail[node.name]) { // TODO: CONSIDER: add typeof check to this for possible overwriting | ||
if (!trail[node.name] || (opt.output.objectOverwrite && (typeof trail[node.name] !== typeof blueprintExtended))) { | ||
// node attribute doesnt exist, create object | ||
this.log('create object'); | ||
trail[node.name] = blueprintExtended; | ||
trails[node.path] = blueprintExtended; | ||
//this.log('create object') | ||
trail[node.name] = blueprintExtended | ||
trails[node.path] = blueprintExtended | ||
} else { | ||
// node attribute exists, set path for next pass | ||
// TODO: extend trail?? | ||
this.log('object at node "' + node.name + '" exists as "' + trail[node.name] + '", skipping insertion and adding trail'); | ||
//this.log('object at node "' + node.name + '" exists as "' + trail[node.name] + '", skipping insertion and adding trail') | ||
if (typeof trail[node.name] === 'object') { | ||
trail[node.name] = merge(trail[node.name], blueprintExtended); | ||
trail[node.name] = merge(trail[node.name], blueprintExtended) | ||
} | ||
this.log('trail[node.name] updated to "' + trail[node.name]); | ||
trails[node.path] = trail[node.path]; | ||
//this.log('trail[node.name] updated to "' + trail[node.name]) | ||
trails[node.path] = trail[node.path] | ||
} | ||
@@ -397,15 +439,15 @@ } | ||
} | ||
}, this); | ||
}, this); | ||
}, this) | ||
}, this) | ||
var t2 = ((new Date()).getTime() - t1); | ||
this.stats.time.total += t2; | ||
var t2 = ((new Date()).getTime() - t1) | ||
this.stats.time.total += t2 | ||
// clear signature between growth sets - TODO: consider leaving this wipe pass off if processing multiple identical sources (add) | ||
if (!signature.isFixed) { | ||
this.signature([]); | ||
this.signature([]) | ||
} | ||
return this; | ||
}; | ||
return this | ||
} | ||
@@ -420,28 +462,28 @@ /* | ||
if (!options) { | ||
return merge({}, this._options); | ||
return merge({}, this._options) | ||
} | ||
this._options = merge(this._options, options); | ||
this._options = merge(this._options, options) | ||
return this; | ||
}; | ||
return this | ||
} | ||
Treeize.prototype.getOptions = function() { | ||
return this._options; | ||
}; | ||
return this._options | ||
} | ||
Treeize.prototype.setOptions = function(options) { | ||
return this.options(options); | ||
}; | ||
return this.options(options) | ||
} | ||
Treeize.prototype.resetOptions = function() { | ||
this._options = merge({}, this.baseOptions); | ||
this._options = merge({}, this.baseOptions) | ||
return this; | ||
}; | ||
return this | ||
} | ||
Treeize.prototype.toString = function treeToString() { | ||
return util.inspect(this.data.tree, false, null); | ||
}; | ||
return 'WARNING: .toString() method of Treeize is deprecated' | ||
} | ||
module.exports = Treeize; | ||
module.exports = Treeize |
{ | ||
"name": "treeize", | ||
"version": "2.0.3", | ||
"version": "2.1.0", | ||
"description": "Converts tabular row data (as from SQL joins, flat JSON, etc) to deep object graphs based on simple column naming conventions - without the use of an ORM or models.", | ||
@@ -29,3 +29,3 @@ "main": "./lib/treeize.js", | ||
], | ||
"author": "K. R. Whitley <kevin@krwhitley.com> (http://krwhitley.com/)", | ||
"author": "Kevin R. Whitley <kevin3503@gmail.com> (http://krwhitley.com/)", | ||
"licenses": [ | ||
@@ -41,19 +41,16 @@ { | ||
"dependencies": { | ||
"lodash": "~1.3.1", | ||
"inflection": "~1.2.6", | ||
"object-merge": "~2.5.1" | ||
"inflection": "^1.12.0", | ||
"object-merge": "^2.5.1" | ||
}, | ||
"devDependencies": { | ||
"grunt": "latest", | ||
"grunt-cli": "latest", | ||
"benchmark": "^2.1.4", | ||
"mocha": "latest", | ||
"should": "latest", | ||
"grunt-contrib-jshint": "latest", | ||
"grunt-contrib-nodeunit": "latest", | ||
"grunt-contrib-watch": "latest", | ||
"grunt-mocha-test": "~0.12.0" | ||
"nodemon": "^1.11.0", | ||
"should": "latest" | ||
}, | ||
"scripts": { | ||
"test": "node_modules/.bin/grunt test" | ||
"test": "mocha", | ||
"test:watch": "mocha --watch test/test.js .", | ||
"benchmark": "npm run test:watch & nodemon --watch . benchmark/index.js" | ||
} | ||
} |
@@ -134,4 +134,2 @@ # Treeize.js | ||
- [`getStats()`](#getStats) - returns object with growth statistics | ||
- [`toString()`](#toString) - uses `util` to return data in visually formatted object graph | ||
- [`log(arg1, arg2, arg3)`](#log) - console.log output of `arg1..n` when `log` option is set to `true` | ||
@@ -160,4 +158,3 @@ # API | ||
resultsAsObject: false, // root structure defaults to array (instead of object) | ||
}, | ||
log: false, // enable logging | ||
} | ||
} | ||
@@ -169,3 +166,3 @@ ``` | ||
```js | ||
.setOptions({ log: true, input: { delimiter: '|' }}); | ||
.setOptions({ input: { delimiter: '|' }}); | ||
``` | ||
@@ -198,6 +195,2 @@ | ||
`log`<a name="optionsLog" /> | ||
Setting to true enables traversal information to be logged to console during growth process. | ||
### .getOptions()<a name="getOptions" /> | ||
@@ -295,35 +288,2 @@ | ||
### .toString()<a name="toString" /> | ||
Typecasting a treeize instance to String or manually calling `.toString()` on it will output it visually using the `util` library from node.js. | ||
```js | ||
var tree = new Treeize(); | ||
tree.grow(data); | ||
// use automatic typecasting to trigger | ||
console.log(tree + ''); | ||
// or call manually | ||
console.log(tree.toString()); | ||
``` | ||
### .log(arg1, arg2, ...)<a name="log" /> | ||
Equivalent to `console.log(arg1, arg2, ...)` when the `log` option is set to `true`. Useful for debugging messages or visual output that you can toggle from a single source. | ||
```js | ||
var tree = new Treeize(); | ||
tree.log('my message'); | ||
// 'my message' will NOT be written to the console | ||
tree | ||
.setOptions({ log: true }) | ||
.log('my message') | ||
; | ||
// 'my message' WILL be written to the console | ||
``` | ||
--- | ||
@@ -690,1 +650,2 @@ | ||
- **2.0.3** - internal variable renaming to avoid deprecation error | ||
- **2.1.0** - major (> 3x) performance improvement - required dropping support for .toString() and internal logging, removed lodash as a dependency |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
2
4
52726
8
785
646
1
+ Addedinflection@1.13.4(transitive)
- Removedlodash@~1.3.1
- Removedinflection@1.2.7(transitive)
- Removedlodash@1.3.1(transitive)
Updatedinflection@^1.12.0
Updatedobject-merge@^2.5.1