|
|
'use strict'; |
|
|
|
|
|
var getFieldAsFn = require('./get-field-as-fn'); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function decodeSourcesWith(codecs, mustDecode) { |
|
|
|
|
|
var context = this; |
|
|
|
|
|
|
|
|
var candidates = [].concat(codecs) |
|
|
.reduce(reduceValidDecoder.bind(null, codecs), []); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return function decode(inputSource) { |
|
|
|
|
|
|
|
|
for (var i = 0, decoded = null; i < candidates.length && !decoded; i++) { |
|
|
|
|
|
|
|
|
try { |
|
|
decoded = candidates[i].decode.call(context, inputSource); |
|
|
} |
|
|
catch (exception) { |
|
|
return getNamedError(exception); |
|
|
} |
|
|
|
|
|
|
|
|
if (decoded) { |
|
|
|
|
|
|
|
|
if (candidates[i].abstract) { |
|
|
return undefined; |
|
|
} |
|
|
|
|
|
if (typeof decoded !== 'string') { |
|
|
return getNamedError('Decoder returned a truthy value but it is not a string:\n' + decoded); |
|
|
} |
|
|
|
|
|
else { |
|
|
return decoded; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return mustDecode ? new Error('No viable decoder for source: ' + inputSource) : undefined; |
|
|
|
|
|
function getNamedError(details) { |
|
|
var name = candidates[i].name || '(unnamed)', |
|
|
message = [ |
|
|
'Decoding with codec: ' + name, |
|
|
'Incoming source: ' + inputSource, |
|
|
details && (details.stack ? details.stack : details) |
|
|
] |
|
|
.filter(Boolean) |
|
|
.join('\n'); |
|
|
return new Error(message); |
|
|
} |
|
|
}; |
|
|
} |
|
|
|
|
|
module.exports = decodeSourcesWith; |
|
|
|
|
|
function reduceValidDecoder(reduced, codec) { |
|
|
var decoder = getFieldAsFn('decode')(codec); |
|
|
return decoder ? reduced.concat(codec) : reduced; |
|
|
} |