cast.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. 'use strict';
  2. /*!
  3. * Module dependencies.
  4. */
  5. const MongooseError = require('./mongooseError');
  6. const util = require('util');
  7. /**
  8. * Casting Error constructor.
  9. *
  10. * @param {String} type
  11. * @param {String} value
  12. * @inherits MongooseError
  13. * @api private
  14. */
  15. class CastError extends MongooseError {
  16. constructor(type, value, path, reason, schemaType) {
  17. // If no args, assume we'll `init()` later.
  18. if (arguments.length > 0) {
  19. const valueType = getValueType(value);
  20. const messageFormat = getMessageFormat(schemaType);
  21. const msg = formatMessage(null, type, value, path, messageFormat, valueType, reason);
  22. super(msg);
  23. this.init(type, value, path, reason, schemaType);
  24. } else {
  25. super(formatMessage());
  26. }
  27. }
  28. toJSON() {
  29. return {
  30. stringValue: this.stringValue,
  31. valueType: this.valueType,
  32. kind: this.kind,
  33. value: this.value,
  34. path: this.path,
  35. reason: this.reason,
  36. name: this.name,
  37. message: this.message
  38. };
  39. }
  40. /*!
  41. * ignore
  42. */
  43. init(type, value, path, reason, schemaType) {
  44. this.stringValue = getStringValue(value);
  45. this.messageFormat = getMessageFormat(schemaType);
  46. this.kind = type;
  47. this.value = value;
  48. this.path = path;
  49. this.reason = reason;
  50. this.valueType = getValueType(value);
  51. }
  52. /**
  53. * ignore
  54. * @param {Readonly<CastError>} other
  55. * @api private
  56. */
  57. copy(other) {
  58. this.messageFormat = other.messageFormat;
  59. this.stringValue = other.stringValue;
  60. this.kind = other.kind;
  61. this.value = other.value;
  62. this.path = other.path;
  63. this.reason = other.reason;
  64. this.message = other.message;
  65. this.valueType = other.valueType;
  66. }
  67. /*!
  68. * ignore
  69. */
  70. setModel(model) {
  71. this.message = formatMessage(model, this.kind, this.value, this.path,
  72. this.messageFormat, this.valueType);
  73. }
  74. }
  75. Object.defineProperty(CastError.prototype, 'name', {
  76. value: 'CastError'
  77. });
  78. function getStringValue(value) {
  79. let stringValue = util.inspect(value);
  80. stringValue = stringValue.replace(/^'|'$/g, '"');
  81. if (!stringValue.startsWith('"')) {
  82. stringValue = '"' + stringValue + '"';
  83. }
  84. return stringValue;
  85. }
  86. function getValueType(value) {
  87. if (value == null) {
  88. return '' + value;
  89. }
  90. const t = typeof value;
  91. if (t !== 'object') {
  92. return t;
  93. }
  94. if (typeof value.constructor !== 'function') {
  95. return t;
  96. }
  97. return value.constructor.name;
  98. }
  99. function getMessageFormat(schemaType) {
  100. const messageFormat = schemaType?._castErrorMessage || null;
  101. if (typeof messageFormat === 'string' || typeof messageFormat === 'function') {
  102. return messageFormat;
  103. }
  104. }
  105. /*!
  106. * ignore
  107. */
  108. function formatMessage(model, kind, value, path, messageFormat, valueType, reason) {
  109. if (typeof messageFormat === 'string') {
  110. const stringValue = getStringValue(value);
  111. let ret = messageFormat.
  112. replace('{KIND}', kind).
  113. replace('{VALUE}', stringValue).
  114. replace('{PATH}', path);
  115. if (model != null) {
  116. ret = ret.replace('{MODEL}', model.modelName);
  117. }
  118. return ret;
  119. } else if (typeof messageFormat === 'function') {
  120. return messageFormat(value, path, model, kind);
  121. } else {
  122. const stringValue = getStringValue(value);
  123. const valueTypeMsg = valueType ? ' (type ' + valueType + ')' : '';
  124. let ret = 'Cast to ' + kind + ' failed for value ' +
  125. stringValue + valueTypeMsg + ' at path "' + path + '"';
  126. if (model != null) {
  127. ret += ' for model "' + model.modelName + '"';
  128. }
  129. if (reason != null &&
  130. typeof reason.constructor === 'function' &&
  131. reason.constructor.name !== 'AssertionError' &&
  132. reason.constructor.name !== 'Error') {
  133. ret += ' because of "' + reason.constructor.name + '"';
  134. }
  135. return ret;
  136. }
  137. }
  138. /*!
  139. * exports
  140. */
  141. module.exports = CastError;