Comparing version 1.4.0 to 1.5.0
@@ -73,6 +73,8 @@ /** | ||
@param key: the key within the object to fix. | ||
modifies byref - no return. | ||
modifies byref. | ||
@return new key. | ||
*/ | ||
function _flattenSillyArray(parentObj, key, requestContext) { | ||
//debug('_flattenSillyArray', key, parentObj[key]); | ||
var subKey = key.replace(/Array$/, ''); // e.g. 'Order' from 'OrderArray' | ||
@@ -90,2 +92,4 @@ var newKey = subKey + 's'; // e.g. 'Orders' | ||
}); | ||
return newKey; | ||
} | ||
@@ -130,76 +134,77 @@ | ||
also transforms numbers and booleans from strings to types. | ||
`maxDepth` of -1 equals infinity. | ||
*/ | ||
exports.flatten = function flatten(el, maxDepth, requestContext, _depth) { | ||
if (_.isUndefined(_depth)) _depth = 0; | ||
if (_.isUndefined(maxDepth) || maxDepth < 1) maxDepth = 10; | ||
if (_depth == null) _depth = 1; | ||
if (maxDepth == null) maxDepth = 10; // default | ||
if (_depth === 0) debug('flattening', el, {maxDepth: maxDepth, requestContext: requestContext}); | ||
if (_depth <= maxDepth) { | ||
if (maxDepth >= 0 && _depth > maxDepth) { | ||
return el; | ||
} | ||
// flatten 1-item arrays. | ||
// note: this is dangerous, means responses w/ single value can look different from multiple values. | ||
// trying to mitigate with `canFlattenKey()` check below. | ||
if (_.isArray(el) && el.length === 1) { | ||
el = _.first(el); | ||
} | ||
// flatten 1-item arrays. | ||
// note: this is dangerous, means responses w/ single value can look different from multiple values. | ||
// trying to mitigate with `canFlattenKey()` check below. | ||
if (_.isArray(el) && el.length === 1) { | ||
el = _.first(el); | ||
} | ||
// weird value-pair structure: | ||
// turn `{ @key:KEY, __value__:VALUE }` into `{ KEY: VALUE }` | ||
if (_isValuePair(el)) { | ||
var values = _.values(el); | ||
debug('converting key-value pair', el); | ||
el = {}; | ||
el[ values[0] ] = values[1]; | ||
} | ||
// weird value-pair structure: | ||
// turn `{ @key:KEY, __value__:VALUE }` into `{ KEY: VALUE }` | ||
if (_isValuePair(el)) { | ||
var values = _.values(el); | ||
debug('converting key-value pair', el); | ||
el = {}; | ||
el[ values[0] ] = values[1]; | ||
} | ||
//// previous fix just creates an array of these. we want a clean key:val obj. | ||
//// so, is this an array of special value-pairs? | ||
//// TODO - disabled this b/c old and inefficient - understand where it was needed, and try to optimize. | ||
//if (_isArrayOfValuePairs(el)) { | ||
// var fixEl = {}; | ||
// _(el).each(function(pair) { | ||
// _.extend(fixEl, flatten(pair, maxDepth, requestContext, _depth + 1)); // fix each, combine | ||
// }); | ||
// el = fixEl; | ||
//} | ||
//// previous fix just creates an array of these. we want a clean key:val obj. | ||
//// so, is this an array of special value-pairs? | ||
//// TODO - disabled this b/c old and inefficient - understand where it was needed, and try to optimize. | ||
//if (_isArrayOfValuePairs(el)) { | ||
// var fixEl = {}; | ||
// _(el).each(function(pair) { | ||
// _.extend(fixEl, flatten(pair, maxDepth, requestContext, _depth + 1)); // fix each, combine | ||
// }); | ||
// el = fixEl; | ||
//} | ||
// flatten sub-elements | ||
if (_.isObject(el) && !_.isArray(el)) { | ||
debug('--is an object', el); | ||
_.forOwn(el, function(childEl, childKey) { | ||
debug('--child', childKey, childEl); | ||
// special cases | ||
if (/Array$/.test(childKey)) { | ||
_flattenSillyArray(el, childKey, requestContext); // on parent, byref | ||
} | ||
else if (/(Amount|Cost|Price)/.test(childKey)) { | ||
el[childKey] = _convertAmountStructure(childEl, requestContext); | ||
} | ||
// flatten sub-elements | ||
if (_.isObject(el) && !_.isArray(el)) { | ||
_.forOwn(el, function(childEl, childKey) { | ||
// special cases | ||
if (/Array$/.test(childKey)) { | ||
childKey = _flattenSillyArray(el, childKey, requestContext); // on parent, byref; childKey changes! | ||
childEl = el[childKey]; // ref to new element | ||
} | ||
else if (/(Amount|Cost|Price)/.test(childKey)) { | ||
el[childKey] = _convertAmountStructure(childEl, requestContext); | ||
} | ||
if (_canFlattenKey(childKey, requestContext)) { | ||
el[childKey] = flatten(childEl, maxDepth, requestContext, _depth + 1); | ||
} | ||
// can't flatten [presumed] array itself, but can still flatten its children. | ||
// @REVIEW: this causes weird skipping behavior, where grandchildren are flattened before higher levels, | ||
// so can't assume that lower levels haven't been flattened yet! | ||
else if (_.isArray(childEl)) { | ||
debug('---grandchildren', childKey, childEl, el[childKey]===childEl, typeof childEl.map); | ||
el[childKey] = childEl.map(function(grandChildEl) { | ||
return flatten(grandChildEl, maxDepth, requestContext, _depth + 1); | ||
}); | ||
} | ||
}); | ||
} | ||
if (_canFlattenKey(childKey, requestContext)) { | ||
el[childKey] = flatten(childEl, maxDepth, requestContext, _depth + 1); | ||
} | ||
// can't flatten [presumed] array itself, but can still flatten its children. | ||
// @REVIEW: this causes weird skipping behavior, where grandchildren are flattened before higher levels, | ||
// so can't assume that lower levels haven't been flattened yet! | ||
else if (_.isArray(childEl)) { | ||
el[childKey] = childEl.map(function(grandChildEl) { | ||
return flatten(grandChildEl, maxDepth, requestContext, _depth + 1); | ||
}); | ||
} | ||
}); | ||
} | ||
if (_.isArray(el)) { | ||
el = el.map(function(childEl) { | ||
return flatten(childEl, maxDepth, requestContext, _depth + 1); | ||
}); | ||
} | ||
if (_.isArray(el)) { | ||
el = el.map(function(childEl) { | ||
return flatten(childEl, maxDepth, requestContext, _depth + 1); | ||
}); | ||
} | ||
} //depth | ||
// DISABLE - also casting IDs - fix. | ||
//el = _castTypes(el); | ||
el = _castTypes(el); | ||
debug('flattened to', el); | ||
@@ -214,2 +219,3 @@ return el; | ||
@param requestContext: context on the request. | ||
- same as `options` in `xmlRequest()`, see docs there. | ||
@param callback: gets `null, data` in success case, and `error, data` on error case. | ||
@@ -224,7 +230,8 @@ - error can be from response or parsing failure. (see error types.) | ||
requestContext = requestContext || {}; | ||
// flattening can be slow with big responses; | ||
// don't necessarily want to flatten all the way up front. | ||
// (maybe better to let app pick the keys it wants and flatten only them.) | ||
// depth here is arbitrary. | ||
data = flatten(data, 5, requestContext); | ||
data = flatten(data, requestContext.parseDepth, requestContext); | ||
@@ -251,2 +258,3 @@ // find the response key. | ||
var | ||
ack, | ||
errorMessage, // build a string | ||
@@ -256,12 +264,7 @@ errorClassification = 'RequestError', // 'RequestError' or 'SystemError' | ||
// normalize to uppercase | ||
if (!_.isUndefined(data.ack)) { | ||
data.Ack = data.ack; | ||
delete data.ack; | ||
} | ||
if (!_.isUndefined(data.Ack)) { | ||
data.Ack = flatten(data.Ack, -1, requestContext); | ||
} | ||
if (!_.isUndefined(data.Ack)) ack = data.Ack; | ||
else if (!_.isUndefined(data.ack)) ack = data.ack; | ||
// | ||
if (ack != null) ack = flatten(ack, -1, requestContext); | ||
// note: docs say, | ||
@@ -271,5 +274,6 @@ // "Both Success and Warning indicate that the request was successful. | ||
// that may affect your application or the user." | ||
// for now, treat Warning as a failure. | ||
// for now, treat Warning as an error. | ||
// (caller still gets the data, so can choose to ignore.) | ||
// | ||
if (_.isUndefined(data.Ack) || data.Ack !== 'Success') { | ||
if (_.isUndefined(ack) || ack !== 'Success') { | ||
// | ||
@@ -301,5 +305,5 @@ // handle all different ways errors can be represented | ||
debug('response error', errorClassification, data.Ack, errorMessage); | ||
debug('response error', errorClassification, ack, errorMessage); | ||
if (!errorMessage) errorMessage = util.format("Bad ack code: ", data.Ack); // fallback | ||
if (!errorMessage) errorMessage = util.format("Bad ack code: ", ack); // fallback | ||
@@ -306,0 +310,0 @@ if (errorClassification === 'SystemError') { |
@@ -72,4 +72,9 @@ var | ||
@option {object} params: this gets converted to an XML body with request parameters. | ||
all filters go in here. use nested objects where appropriate. see the API docs. | ||
- all filters go in here. use nested objects where appropriate. see the API docs. | ||
@option {int} parseDepth: how many levels down to try to parse/interpret the response. | ||
- see `parseResponseJson()` and its tests. | ||
- higher number can make app-level code easier, but is riskier; | ||
lower number here shifts the parsing burden to the application. | ||
... | ||
@@ -91,2 +96,5 @@ | ||
// for default parser | ||
options.parseDepth = options.parseDepth != null ? options.parseDepth : -1; // default parse all the way | ||
options.reqOptions = options.reqOptions || {}; | ||
@@ -141,2 +149,3 @@ options.reqOptions.headers = options.reqOptions.headers || {}; | ||
// or if actually can't parse. | ||
// `options.parseDepth` is very important here. | ||
options.parser(data, options, next); | ||
@@ -143,0 +152,0 @@ } |
{ | ||
"name": "ebay-api", | ||
"description": "eBay API Client", | ||
"version": "1.4.0", | ||
"version": "1.5.0", | ||
"homepage": "https://github.com/newleafdigital/nodejs-ebay-api", | ||
@@ -6,0 +6,0 @@ "author": "Ben Buckman <ben@newleafdigital.com> (http://newleafdigital.com)", |
@@ -28,2 +28,11 @@ eBay API client for Node.js | ||
### Current state | ||
The 1.x branch is currently under active development, and there may be breaking changes between minor releases. | ||
(I realize this is contrary to best practice, but the module is not yet settled enough to major-bump every time.) | ||
**If you are using the 1.x branch, I recommend that you a) let me know your use case, b) help develop it, | ||
c) watch the commit and release logs carefully.** | ||
## Usage | ||
@@ -74,2 +83,5 @@ | ||
- `raw`: boolean, set `true` to skip parsing and return the raw XML response. | ||
- `parseDepth`: how many levels down to try to parse/interpret the response. | ||
_The default parser is still experimental._ Set this to 0 or 1 to let your app do all the parsing. | ||
(Default: unlimited) | ||
@@ -76,0 +88,0 @@ _for authentication, include:_ |
@@ -10,3 +10,3 @@ require('./helpers'); | ||
describe('`parseResponseJson`', function() { | ||
describe('`parseResponseJson` with unlimited depth', function() { | ||
@@ -18,3 +18,4 @@ context('GetOrders response', function () { | ||
serviceName: 'Trading', | ||
opType: 'GetOrders' | ||
opType: 'GetOrders', | ||
parseDepth: -1 | ||
}; | ||
@@ -53,2 +54,3 @@ | ||
expect(parsedResponse).to.have.property('Orders'); | ||
expect(parsedResponse).not.to.have.property('OrderArray'); | ||
expect(parsedResponse.Orders).to.have.length(2); | ||
@@ -61,3 +63,5 @@ }); | ||
expect(_orders[0]).to.have.property('Transactions'); | ||
expect(_orders[0]).not.to.have.property('TransactionArray'); | ||
// `Transactions` are always arrays | ||
@@ -95,11 +99,16 @@ expect(_orders[0].Transactions).to.have.length(1); | ||
it('converts booleans', function() { | ||
it.skip('converts booleans', function() { // DISABLED temporarily | ||
expect(parsedResponse.Orders[0]).to.have.property('IsMultiLegShipping', false); | ||
}); | ||
it('converts numbers', function() { | ||
it.skip('converts numbers, but not numeric IDs', function() { // DISABLED temporarily | ||
// converted | ||
expect(parsedResponse).to.have.deep.property('PaginationResult.TotalNumberOfPages', 1); | ||
expect(parsedResponse).to.have.deep.property('PaginationResult.TotalNumberOfEntries', 2); | ||
// still a string | ||
expect(parsedResponse.Orders[0].Transactions[0]).to.have.deep.property('Item.ItemID', '222222222222'); | ||
}); | ||
it('converts currency amounts', function() { | ||
@@ -116,2 +125,5 @@ expect(parsedResponse.Orders[0]).to.have.property('AdjustmentAmount') | ||
// TODO test parseDepth:0, shouldn't transform at all | ||
context('GetSingleItem response', function () { | ||
@@ -118,0 +130,0 @@ var responseXml, responseJson, parsedResponse; |
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
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
83147
1437
178