MetadataStorage.js 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.getMetadataStorage = exports.MetadataStorage = void 0;
  4. const ValidationSchemaToMetadataTransformer_1 = require("../validation-schema/ValidationSchemaToMetadataTransformer");
  5. const utils_1 = require("../utils");
  6. /**
  7. * Storage all metadatas.
  8. */
  9. class MetadataStorage {
  10. constructor() {
  11. // -------------------------------------------------------------------------
  12. // Private properties
  13. // -------------------------------------------------------------------------
  14. this.validationMetadatas = new Map();
  15. this.constraintMetadatas = new Map();
  16. }
  17. get hasValidationMetaData() {
  18. return !!this.validationMetadatas.size;
  19. }
  20. // -------------------------------------------------------------------------
  21. // Public Methods
  22. // -------------------------------------------------------------------------
  23. /**
  24. * Adds a new validation metadata.
  25. */
  26. addValidationSchema(schema) {
  27. const validationMetadatas = new ValidationSchemaToMetadataTransformer_1.ValidationSchemaToMetadataTransformer().transform(schema);
  28. validationMetadatas.forEach(validationMetadata => this.addValidationMetadata(validationMetadata));
  29. }
  30. /**
  31. * Adds a new validation metadata.
  32. */
  33. addValidationMetadata(metadata) {
  34. const existingMetadata = this.validationMetadatas.get(metadata.target);
  35. if (existingMetadata) {
  36. existingMetadata.push(metadata);
  37. }
  38. else {
  39. this.validationMetadatas.set(metadata.target, [metadata]);
  40. }
  41. }
  42. /**
  43. * Adds a new constraint metadata.
  44. */
  45. addConstraintMetadata(metadata) {
  46. const existingMetadata = this.constraintMetadatas.get(metadata.target);
  47. if (existingMetadata) {
  48. existingMetadata.push(metadata);
  49. }
  50. else {
  51. this.constraintMetadatas.set(metadata.target, [metadata]);
  52. }
  53. }
  54. /**
  55. * Groups metadata by their property names.
  56. */
  57. groupByPropertyName(metadata) {
  58. const grouped = {};
  59. metadata.forEach(metadata => {
  60. if (!grouped[metadata.propertyName])
  61. grouped[metadata.propertyName] = [];
  62. grouped[metadata.propertyName].push(metadata);
  63. });
  64. return grouped;
  65. }
  66. /**
  67. * Gets all validation metadatas for the given object with the given groups.
  68. */
  69. getTargetValidationMetadatas(targetConstructor, targetSchema, always, strictGroups, groups) {
  70. const includeMetadataBecauseOfAlwaysOption = (metadata) => {
  71. // `metadata.always` overrides global default.
  72. if (typeof metadata.always !== 'undefined')
  73. return metadata.always;
  74. // `metadata.groups` overrides global default.
  75. if (metadata.groups && metadata.groups.length)
  76. return false;
  77. // Use global default.
  78. return always;
  79. };
  80. const excludeMetadataBecauseOfStrictGroupsOption = (metadata) => {
  81. if (strictGroups) {
  82. // Validation is not using groups.
  83. if (!groups || !groups.length) {
  84. // `metadata.groups` has at least one group.
  85. if (metadata.groups && metadata.groups.length)
  86. return true;
  87. }
  88. }
  89. return false;
  90. };
  91. // get directly related to a target metadatas
  92. const filteredForOriginalMetadatasSearch = this.validationMetadatas.get(targetConstructor) || [];
  93. const originalMetadatas = filteredForOriginalMetadatasSearch.filter(metadata => {
  94. if (metadata.target !== targetConstructor && metadata.target !== targetSchema)
  95. return false;
  96. if (includeMetadataBecauseOfAlwaysOption(metadata))
  97. return true;
  98. if (excludeMetadataBecauseOfStrictGroupsOption(metadata))
  99. return false;
  100. if (groups && groups.length > 0)
  101. return metadata.groups && !!metadata.groups.find(group => groups.indexOf(group) !== -1);
  102. return true;
  103. });
  104. // get metadatas for inherited classes
  105. const filteredForInheritedMetadatasSearch = [];
  106. for (const [key, value] of this.validationMetadatas.entries()) {
  107. if (targetConstructor.prototype instanceof key) {
  108. filteredForInheritedMetadatasSearch.push(...value);
  109. }
  110. }
  111. const inheritedMetadatas = filteredForInheritedMetadatasSearch.filter(metadata => {
  112. // if target is a string it's means we validate against a schema, and there is no inheritance support for schemas
  113. if (typeof metadata.target === 'string')
  114. return false;
  115. if (metadata.target === targetConstructor)
  116. return false;
  117. if (metadata.target instanceof Function && !(targetConstructor.prototype instanceof metadata.target))
  118. return false;
  119. if (includeMetadataBecauseOfAlwaysOption(metadata))
  120. return true;
  121. if (excludeMetadataBecauseOfStrictGroupsOption(metadata))
  122. return false;
  123. if (groups && groups.length > 0)
  124. return metadata.groups && !!metadata.groups.find(group => groups.indexOf(group) !== -1);
  125. return true;
  126. });
  127. // filter out duplicate metadatas, prefer original metadatas instead of inherited metadatas
  128. const uniqueInheritedMetadatas = inheritedMetadatas.filter(inheritedMetadata => {
  129. return !originalMetadatas.find(originalMetadata => {
  130. return (originalMetadata.propertyName === inheritedMetadata.propertyName &&
  131. originalMetadata.type === inheritedMetadata.type);
  132. });
  133. });
  134. return originalMetadatas.concat(uniqueInheritedMetadatas);
  135. }
  136. /**
  137. * Gets all validator constraints for the given object.
  138. */
  139. getTargetValidatorConstraints(target) {
  140. return this.constraintMetadatas.get(target) || [];
  141. }
  142. }
  143. exports.MetadataStorage = MetadataStorage;
  144. /**
  145. * Gets metadata storage.
  146. * Metadata storage follows the best practices and stores metadata in a global variable.
  147. */
  148. function getMetadataStorage() {
  149. const global = (0, utils_1.getGlobal)();
  150. if (!global.classValidatorMetadataStorage) {
  151. global.classValidatorMetadataStorage = new MetadataStorage();
  152. }
  153. return global.classValidatorMetadataStorage;
  154. }
  155. exports.getMetadataStorage = getMetadataStorage;
  156. //# sourceMappingURL=MetadataStorage.js.map