validate-projection-schema.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. import {InvalidArgumentError} from '@e22m4u/js-format';
  2. /**
  3. * Validate projection schema.
  4. *
  5. * @param {object|Function|string} schema
  6. * @param {boolean} [shallowMode]
  7. * @param {Set} [validatedSchemas]
  8. */
  9. export function validateProjectionSchema(
  10. schema,
  11. shallowMode = false,
  12. validatedSchemas = new Set(),
  13. ) {
  14. // если схема не является объектом, функцией
  15. // и не пустой строкой, то выбрасывается ошибка
  16. if (
  17. !schema ||
  18. (typeof schema !== 'object' &&
  19. typeof schema !== 'function' &&
  20. typeof schema !== 'string') ||
  21. Array.isArray(schema)
  22. ) {
  23. throw new InvalidArgumentError(
  24. 'Projection schema must be an Object, a Function ' +
  25. 'or a non-empty String, but %v was given.',
  26. schema,
  27. );
  28. }
  29. // если флаг поверхностного режима не является
  30. // логическим значением, то выбрасывается ошибка
  31. if (typeof shallowMode !== 'boolean') {
  32. throw new InvalidArgumentError(
  33. 'Argument "shallowMode" must be a Boolean, but %v was given.',
  34. shallowMode,
  35. );
  36. }
  37. // если набор проверенных схем не является
  38. // экземпляром Set, то выбрасывается ошибка
  39. if (!(validatedSchemas instanceof Set)) {
  40. throw new InvalidArgumentError(
  41. 'Argument "validatedSchemas" must be ' +
  42. 'an instance of Set, but %v was given.',
  43. validatedSchemas,
  44. );
  45. }
  46. // если схема уже была проверена,
  47. // то проверка пропускается
  48. if (validatedSchemas.has(schema)) {
  49. return;
  50. }
  51. // если схема не является объектом,
  52. // то проверка пропускается
  53. if (typeof schema !== 'object') {
  54. return;
  55. }
  56. // для исключения бесконечного цикла,
  57. // текущая схема добавляется в историю
  58. validatedSchemas.add(schema);
  59. // schema[k]
  60. Object.keys(schema).forEach(propName => {
  61. const propOptions = schema[propName];
  62. if (propOptions === undefined) {
  63. return;
  64. }
  65. if (
  66. propOptions === null ||
  67. (typeof propOptions !== 'object' && typeof propOptions !== 'boolean') ||
  68. Array.isArray(propOptions)
  69. ) {
  70. throw new InvalidArgumentError(
  71. 'Property options must be an Object or a Boolean, but %v was given.',
  72. propOptions,
  73. );
  74. }
  75. if (typeof propOptions === 'boolean') {
  76. return;
  77. }
  78. // schema[k].select
  79. if (
  80. propOptions.select !== undefined &&
  81. typeof propOptions.select !== 'boolean'
  82. ) {
  83. throw new InvalidArgumentError(
  84. 'Property option "select" must be a Boolean, but %v was given.',
  85. propOptions.select,
  86. );
  87. }
  88. // schema[k].scopes
  89. if (propOptions.scopes !== undefined) {
  90. if (
  91. !propOptions.scopes ||
  92. typeof propOptions.scopes !== 'object' ||
  93. Array.isArray(propOptions.scopes)
  94. ) {
  95. throw new InvalidArgumentError(
  96. 'Property option "scopes" must be an Object, but %v was given.',
  97. propOptions.scopes,
  98. );
  99. }
  100. Object.values(propOptions.scopes).forEach(scopeOptions => {
  101. if (scopeOptions === undefined) {
  102. return;
  103. }
  104. // schema[k].scopes[k]
  105. if (
  106. scopeOptions === null ||
  107. (typeof scopeOptions !== 'object' &&
  108. typeof scopeOptions !== 'boolean') ||
  109. Array.isArray(scopeOptions)
  110. ) {
  111. throw new InvalidArgumentError(
  112. 'Scope options must be an Object or a Boolean, but %v was given.',
  113. scopeOptions,
  114. );
  115. }
  116. // schema[k].scopes[k].select
  117. if (
  118. scopeOptions.select !== undefined &&
  119. typeof scopeOptions.select !== 'boolean'
  120. ) {
  121. throw new InvalidArgumentError(
  122. 'Scope option "select" must be a Boolean, but %v was given.',
  123. scopeOptions.select,
  124. );
  125. }
  126. });
  127. }
  128. // schema[k].schema
  129. if (propOptions.schema !== undefined) {
  130. if (
  131. !propOptions.schema ||
  132. (typeof propOptions.schema !== 'object' &&
  133. typeof propOptions.schema !== 'function' &&
  134. typeof propOptions.schema !== 'string') ||
  135. Array.isArray(propOptions.schema)
  136. ) {
  137. throw new InvalidArgumentError(
  138. 'Property option "schema" must be an Object, a Function' +
  139. ' or a non-empty String, but %v was given.',
  140. propOptions.schema,
  141. );
  142. }
  143. if (!shallowMode && typeof propOptions.schema === 'object') {
  144. validateProjectionSchema(
  145. propOptions.schema,
  146. shallowMode,
  147. validatedSchemas,
  148. );
  149. }
  150. }
  151. });
  152. }