common.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. 'use strict';
  2. const Assert = require('@hapi/hoek/lib/assert');
  3. const AssertError = require('@hapi/hoek/lib/error');
  4. const Pkg = require('../package.json');
  5. let Messages;
  6. let Schemas;
  7. const internals = {
  8. isoDate: /^(?:[-+]\d{2})?(?:\d{4}(?!\d{2}\b))(?:(-?)(?:(?:0[1-9]|1[0-2])(?:\1(?:[12]\d|0[1-9]|3[01]))?|W(?:[0-4]\d|5[0-2])(?:-?[1-7])?|(?:00[1-9]|0[1-9]\d|[12]\d{2}|3(?:[0-5]\d|6[1-6])))(?![T]$|[T][\d]+Z$)(?:[T\s](?:(?:(?:[01]\d|2[0-3])(?:(:?)[0-5]\d)?|24\:?00)(?:[.,]\d+(?!:))?)(?:\2[0-5]\d(?:[.,]\d+)?)?(?:[Z]|(?:[+-])(?:[01]\d|2[0-3])(?::?[0-5]\d)?)?)?)?$/
  9. };
  10. exports.version = Pkg.version;
  11. exports.defaults = {
  12. abortEarly: true,
  13. allowUnknown: false,
  14. artifacts: false,
  15. cache: true,
  16. context: null,
  17. convert: true,
  18. dateFormat: 'iso',
  19. errors: {
  20. escapeHtml: false,
  21. label: 'path',
  22. language: null,
  23. render: true,
  24. stack: false,
  25. wrap: {
  26. label: '"',
  27. array: '[]'
  28. }
  29. },
  30. externals: true,
  31. messages: {},
  32. nonEnumerables: false,
  33. noDefaults: false,
  34. presence: 'optional',
  35. skipFunctions: false,
  36. stripUnknown: false,
  37. warnings: false
  38. };
  39. exports.symbols = {
  40. any: Symbol.for('@hapi/joi/schema'), // Used to internally identify any-based types (shared with other joi versions)
  41. arraySingle: Symbol('arraySingle'),
  42. deepDefault: Symbol('deepDefault'),
  43. errors: Symbol('errors'),
  44. literal: Symbol('literal'),
  45. override: Symbol('override'),
  46. parent: Symbol('parent'),
  47. prefs: Symbol('prefs'),
  48. ref: Symbol('ref'),
  49. template: Symbol('template'),
  50. values: Symbol('values')
  51. };
  52. exports.assertOptions = function (options, keys, name = 'Options') {
  53. Assert(options && typeof options === 'object' && !Array.isArray(options), 'Options must be of type object');
  54. const unknownKeys = Object.keys(options).filter((k) => !keys.includes(k));
  55. Assert(unknownKeys.length === 0, `${name} contain unknown keys: ${unknownKeys}`);
  56. };
  57. exports.checkPreferences = function (prefs) {
  58. Schemas = Schemas || require('./schemas');
  59. const result = Schemas.preferences.validate(prefs);
  60. if (result.error) {
  61. throw new AssertError([result.error.details[0].message]);
  62. }
  63. };
  64. exports.compare = function (a, b, operator) {
  65. switch (operator) {
  66. case '=': return a === b;
  67. case '>': return a > b;
  68. case '<': return a < b;
  69. case '>=': return a >= b;
  70. case '<=': return a <= b;
  71. }
  72. };
  73. exports.default = function (value, defaultValue) {
  74. return value === undefined ? defaultValue : value;
  75. };
  76. exports.isIsoDate = function (date) {
  77. return internals.isoDate.test(date);
  78. };
  79. exports.isNumber = function (value) {
  80. return typeof value === 'number' && !isNaN(value);
  81. };
  82. exports.isResolvable = function (obj) {
  83. if (!obj) {
  84. return false;
  85. }
  86. return obj[exports.symbols.ref] || obj[exports.symbols.template];
  87. };
  88. exports.isSchema = function (schema, options = {}) {
  89. const any = schema && schema[exports.symbols.any];
  90. if (!any) {
  91. return false;
  92. }
  93. Assert(options.legacy || any.version === exports.version, 'Cannot mix different versions of joi schemas');
  94. return true;
  95. };
  96. exports.isValues = function (obj) {
  97. return obj[exports.symbols.values];
  98. };
  99. exports.limit = function (value) {
  100. return Number.isSafeInteger(value) && value >= 0;
  101. };
  102. exports.preferences = function (target, source) {
  103. Messages = Messages || require('./messages');
  104. target = target || {};
  105. source = source || {};
  106. const merged = Object.assign({}, target, source);
  107. if (source.errors &&
  108. target.errors) {
  109. merged.errors = Object.assign({}, target.errors, source.errors);
  110. merged.errors.wrap = Object.assign({}, target.errors.wrap, source.errors.wrap);
  111. }
  112. if (source.messages) {
  113. merged.messages = Messages.compile(source.messages, target.messages);
  114. }
  115. delete merged[exports.symbols.prefs];
  116. return merged;
  117. };
  118. exports.tryWithPath = function (fn, key, options = {}) {
  119. try {
  120. return fn();
  121. }
  122. catch (err) {
  123. if (err.path !== undefined) {
  124. err.path = key + '.' + err.path;
  125. }
  126. else {
  127. err.path = key;
  128. }
  129. if (options.append) {
  130. err.message = `${err.message} (${err.path})`;
  131. }
  132. throw err;
  133. }
  134. };
  135. exports.validateArg = function (value, label, { assert, message }) {
  136. if (exports.isSchema(assert)) {
  137. const result = assert.validate(value);
  138. if (!result.error) {
  139. return;
  140. }
  141. return result.error.message;
  142. }
  143. else if (!assert(value)) {
  144. return label ? `${label} ${message}` : message;
  145. }
  146. };
  147. exports.verifyFlat = function (args, method) {
  148. for (const arg of args) {
  149. Assert(!Array.isArray(arg), 'Method no longer accepts array arguments:', method);
  150. }
  151. };