current commit
260904.2 · errors: validate constructor name
// Flags: --expose-internals

import '../common/index.mjs';
import assert from 'node:assert';
import errorsModule from 'internal/errors';


const { determineSpecificType } = errorsModule;

assert.strictEqual(
  determineSpecificType(1n),
  'type bigint (1n)',
);

assert.strictEqual(
  determineSpecificType(true),
  'type boolean (true)',
);
assert.strictEqual(
  determineSpecificType(false),
  'type boolean (false)',
);

assert.strictEqual(
  determineSpecificType(2),
  'type number (2)',
);

assert.strictEqual(
  determineSpecificType(NaN),
  'type number (NaN)',
);

assert.strictEqual(
  determineSpecificType(Infinity),
  'type number (Infinity)',
);

assert.strictEqual(
  determineSpecificType({ __proto__: null }),
  '[Object: null prototype] {}',
);

assert.strictEqual(
  determineSpecificType(''),
  "type string ('')",
);

assert.strictEqual(
  determineSpecificType(''),
  "type string ('')",
);
assert.strictEqual(
  determineSpecificType("''"),
  "type string (\"''\")",
);
assert.strictEqual(
  determineSpecificType('Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor'),
  "type string ('Lorem ipsum dolor sit ame...')",
);
assert.strictEqual(
  determineSpecificType("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor'"),
  "type string ('Lorem ipsum dolor sit ame...')",
);
assert.strictEqual(
  determineSpecificType("Lorem' ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor"),
  "type string (\"Lorem' ipsum dolor sit am...\")",
);

assert.strictEqual(
  determineSpecificType(Symbol('foo')),
  'type symbol (Symbol(foo))',
);

assert.strictEqual(
  determineSpecificType(function foo() {}),
  'function foo',
);

const implicitlyNamed = function() {}; // eslint-disable-line func-style
assert.strictEqual(
  determineSpecificType(implicitlyNamed),
  'function implicitlyNamed',
);
assert.strictEqual(
  determineSpecificType(() => {}),
  'function ',
);
function noName() {}
delete noName.name;
assert.strictEqual(
  noName.name,
  '',
);
assert.strictEqual(
  determineSpecificType(noName),
  'function ',
);

function * generatorFn() {}
assert.strictEqual(
  determineSpecificType(generatorFn),
  'function generatorFn',
);

async function asyncFn() {}
assert.strictEqual(
  determineSpecificType(asyncFn),
  'function asyncFn',
);

assert.strictEqual(
  determineSpecificType(null),
  'null',
);

assert.strictEqual(
  determineSpecificType(undefined),
  'undefined',
);

assert.strictEqual(
  determineSpecificType([]),
  'an instance of Array',
);

assert.strictEqual(
  determineSpecificType(new Array()),
  'an instance of Array',
);
assert.strictEqual(
  determineSpecificType(new BigInt64Array()),
  'an instance of BigInt64Array',
);
assert.strictEqual(
  determineSpecificType(new BigUint64Array()),
  'an instance of BigUint64Array',
);
assert.strictEqual(
  determineSpecificType(new Int8Array()),
  'an instance of Int8Array',
);
assert.strictEqual(
  determineSpecificType(new Int16Array()),
  'an instance of Int16Array',
);
assert.strictEqual(
  determineSpecificType(new Int32Array()),
  'an instance of Int32Array',
);
assert.strictEqual(
  determineSpecificType(new Float32Array()),
  'an instance of Float32Array',
);
assert.strictEqual(
  determineSpecificType(new Float64Array()),
  'an instance of Float64Array',
);
assert.strictEqual(
  determineSpecificType(new Uint8Array()),
  'an instance of Uint8Array',
);
assert.strictEqual(
  determineSpecificType(new Uint8ClampedArray()),
  'an instance of Uint8ClampedArray',
);
assert.strictEqual(
  determineSpecificType(new Uint16Array()),
  'an instance of Uint16Array',
);
assert.strictEqual(
  determineSpecificType(new Uint32Array()),
  'an instance of Uint32Array',
);

assert.strictEqual(
  determineSpecificType(new Date()),
  'an instance of Date',
);

assert.strictEqual(
  determineSpecificType(new Map()),
  'an instance of Map',
);
assert.strictEqual(
  determineSpecificType(new WeakMap()),
  'an instance of WeakMap',
);

assert.strictEqual(
  determineSpecificType({}),
  'an instance of Object',
);
assert.strictEqual(
  determineSpecificType(new Object()),
  'an instance of Object',
);

assert.strictEqual(
  determineSpecificType(Promise.resolve('foo')),
  'an instance of Promise',
);

assert.strictEqual(
  determineSpecificType(new Set()),
  'an instance of Set',
);
assert.strictEqual(
  determineSpecificType(new WeakSet()),
  'an instance of WeakSet',
);

// Anonymous classes have an empty `name`, so the value is inspected instead.
// `inspect(..., { depth: -1 })` prints this one as `{}` because it has no own
// properties; the values below carry a `constructor` property of their own and
// print as `[Object]`.
assert.strictEqual(
  determineSpecificType(new (class {})()),
  '{}',
);

// `constructor` is an ordinary, user-controlled property that need not be a
// function. Describing such a value must not throw.
assert.strictEqual(
  determineSpecificType(JSON.parse('{"constructor": 5}')),
  '[Object]',
);

assert.strictEqual(
  determineSpecificType({ constructor: { name: '' } }),
  '[Object]',
);

// A `constructor.name` that is not a usable string must not be interpolated
// into the message.
assert.strictEqual(
  determineSpecificType({ constructor: { name: Symbol('x') } }),
  '[Object]',
);

assert.strictEqual(
  determineSpecificType({ constructor: { name: 42 } }),
  '[Object]',
);

// `constructor` and its `name` are each read once. Both may be accessors, so
// repeated reads are observable, and a `name` validated by one read and
// interpolated from another need not be the same value twice.
let constructorReads = 0;
let nameReads = 0;
const named = {
  get constructor() {
    constructorReads++;
    return { get name() { nameReads++; return 'Foo'; } };
  },
};
assert.strictEqual(determineSpecificType(named), 'an instance of Foo');
assert.strictEqual(constructorReads, 1);
assert.strictEqual(nameReads, 1);

// Building the error must not fail when `constructor` is a truthy primitive.
assert.strictEqual(
  new errorsModule.codes.ERR_INVALID_ARG_TYPE(
    'arg', 'string', JSON.parse('{"constructor": 5}')).code,
  'ERR_INVALID_ARG_TYPE',
);