diff --git a/lib/yargs-parser.ts b/lib/yargs-parser.ts index 48a2d0f2..5116b8ec 100644 --- a/lib/yargs-parser.ts +++ b/lib/yargs-parser.ts @@ -637,7 +637,13 @@ export class YargsParser { return value } - function maybeCoerceNumber (key: string, value: string | number | null | undefined) { + function maybeCoerceNumber (key: string, value: unknown) { + // Coercion callbacks may intentionally return objects (for example, + // parsed connection strings). Only strings and numbers can be inspected + // for numeric syntax; passing other values to the regular expressions + // in `looksLikeNumber` can throw for objects without a prototype. + if (typeof value !== 'string' && typeof value !== 'number') return value + if (!configuration['parse-positional-numbers'] && key === '_') return value if (!checkAllAliases(key, flags.strings) && !checkAllAliases(key, flags.bools) && !Array.isArray(value)) { const shouldCoerceNumber = looksLikeNumber(value) && configuration['parse-numbers'] && ( diff --git a/test/yargs-parser.mjs b/test/yargs-parser.mjs index 4c692375..d5c4cae9 100644 --- a/test/yargs-parser.mjs +++ b/test/yargs-parser.mjs @@ -3536,6 +3536,21 @@ describe('yargs-parser', function () { parsed.foo.should.equal('BAR') }) + it('preserves objects returned by coercion functions', function () { + const value = Object.create(null) + value.database = 'postgres' + + const parsed = parser(['--connection', 'postgresql://db/example'], { + coerce: { + connection: function () { + return value + } + } + }) + + parsed.connection.should.equal(value) + }) + it('applies coercion function to an implicit array', function () { const parsed = parser(['--foo', '99', '-f', '33'], { coerce: {