XdrSchemaValidator.js 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.XdrSchemaValidator = void 0;
  4. class XdrSchemaValidator {
  5. validateSchema(schema) {
  6. try {
  7. return this.validateSchemaInternal(schema);
  8. }
  9. catch {
  10. return false;
  11. }
  12. }
  13. validateValue(value, schema) {
  14. try {
  15. return this.validateValueInternal(value, schema);
  16. }
  17. catch {
  18. return false;
  19. }
  20. }
  21. validateSchemaInternal(schema) {
  22. if (!schema || typeof schema !== 'object' || !schema.type) {
  23. return false;
  24. }
  25. switch (schema.type) {
  26. case 'void':
  27. case 'int':
  28. case 'unsigned_int':
  29. case 'boolean':
  30. case 'hyper':
  31. case 'unsigned_hyper':
  32. case 'float':
  33. case 'double':
  34. case 'quadruple':
  35. return true;
  36. case 'enum':
  37. return this.validateEnumSchema(schema);
  38. case 'opaque':
  39. return this.validateOpaqueSchema(schema);
  40. case 'vopaque':
  41. return this.validateVarlenOpaqueSchema(schema);
  42. case 'string':
  43. return this.validateStringSchema(schema);
  44. case 'array':
  45. return this.validateArraySchema(schema);
  46. case 'varray':
  47. return this.validateVarlenArraySchema(schema);
  48. case 'struct':
  49. return this.validateStructSchema(schema);
  50. case 'union':
  51. return this.validateUnionSchema(schema);
  52. default:
  53. return false;
  54. }
  55. }
  56. validateEnumSchema(schema) {
  57. if (!schema.values || typeof schema.values !== 'object') {
  58. return false;
  59. }
  60. const values = Object.values(schema.values);
  61. const uniqueValues = new Set(values);
  62. if (values.length !== uniqueValues.size) {
  63. return false;
  64. }
  65. return values.every((value) => Number.isInteger(value));
  66. }
  67. validateOpaqueSchema(schema) {
  68. return typeof schema.size === 'number' && Number.isInteger(schema.size) && schema.size >= 0;
  69. }
  70. validateVarlenOpaqueSchema(schema) {
  71. return !schema.size || (typeof schema.size === 'number' && Number.isInteger(schema.size) && schema.size >= 0);
  72. }
  73. validateStringSchema(schema) {
  74. return !schema.size || (typeof schema.size === 'number' && Number.isInteger(schema.size) && schema.size >= 0);
  75. }
  76. validateArraySchema(schema) {
  77. if (!schema.elements || typeof schema.size !== 'number' || !Number.isInteger(schema.size) || schema.size < 0) {
  78. return false;
  79. }
  80. return this.validateSchemaInternal(schema.elements);
  81. }
  82. validateVarlenArraySchema(schema) {
  83. if (!schema.elements) {
  84. return false;
  85. }
  86. if (schema.size !== undefined) {
  87. if (typeof schema.size !== 'number' || !Number.isInteger(schema.size) || schema.size < 0) {
  88. return false;
  89. }
  90. }
  91. return this.validateSchemaInternal(schema.elements);
  92. }
  93. validateStructSchema(schema) {
  94. if (!Array.isArray(schema.fields)) {
  95. return false;
  96. }
  97. const fieldNames = new Set();
  98. for (const field of schema.fields) {
  99. if (!Array.isArray(field) || field.length !== 2) {
  100. return false;
  101. }
  102. const [fieldSchema, fieldName] = field;
  103. if (typeof fieldName !== 'string' || fieldName === '') {
  104. return false;
  105. }
  106. if (fieldNames.has(fieldName)) {
  107. return false;
  108. }
  109. fieldNames.add(fieldName);
  110. if (!this.validateSchemaInternal(fieldSchema)) {
  111. return false;
  112. }
  113. }
  114. return true;
  115. }
  116. validateUnionSchema(schema) {
  117. if (!Array.isArray(schema.arms) || schema.arms.length === 0) {
  118. return false;
  119. }
  120. const discriminants = new Set();
  121. for (const arm of schema.arms) {
  122. if (!Array.isArray(arm) || arm.length !== 2) {
  123. return false;
  124. }
  125. const [discriminant, armSchema] = arm;
  126. if (discriminants.has(discriminant)) {
  127. return false;
  128. }
  129. discriminants.add(discriminant);
  130. if (typeof discriminant !== 'number' && typeof discriminant !== 'string' && typeof discriminant !== 'boolean') {
  131. return false;
  132. }
  133. if (!this.validateSchemaInternal(armSchema)) {
  134. return false;
  135. }
  136. }
  137. if (schema.default && !this.validateSchemaInternal(schema.default)) {
  138. return false;
  139. }
  140. return true;
  141. }
  142. validateValueInternal(value, schema) {
  143. switch (schema.type) {
  144. case 'void':
  145. return value === null || value === undefined;
  146. case 'int':
  147. return typeof value === 'number' && Number.isInteger(value) && value >= -2147483648 && value <= 2147483647;
  148. case 'unsigned_int':
  149. return typeof value === 'number' && Number.isInteger(value) && value >= 0 && value <= 4294967295;
  150. case 'boolean':
  151. return typeof value === 'boolean';
  152. case 'hyper':
  153. return (typeof value === 'number' && Number.isInteger(value)) || typeof value === 'bigint';
  154. case 'unsigned_hyper':
  155. return ((typeof value === 'number' && Number.isInteger(value) && value >= 0) ||
  156. (typeof value === 'bigint' && value >= BigInt(0)));
  157. case 'float':
  158. case 'double':
  159. case 'quadruple':
  160. return typeof value === 'number';
  161. case 'enum':
  162. const enumSchema = schema;
  163. return typeof value === 'string' && value in enumSchema.values;
  164. case 'opaque':
  165. const opaqueSchema = schema;
  166. return value instanceof Uint8Array && value.length === opaqueSchema.size;
  167. case 'vopaque':
  168. const vopaqueSchema = schema;
  169. return value instanceof Uint8Array && (!vopaqueSchema.size || value.length <= vopaqueSchema.size);
  170. case 'string':
  171. const stringSchema = schema;
  172. return typeof value === 'string' && (!stringSchema.size || value.length <= stringSchema.size);
  173. case 'array':
  174. const arraySchema = schema;
  175. return (Array.isArray(value) &&
  176. value.length === arraySchema.size &&
  177. value.every((item) => this.validateValueInternal(item, arraySchema.elements)));
  178. case 'varray':
  179. const varraySchema = schema;
  180. return (Array.isArray(value) &&
  181. (!varraySchema.size || value.length <= varraySchema.size) &&
  182. value.every((item) => this.validateValueInternal(item, varraySchema.elements)));
  183. case 'struct':
  184. const structSchema = schema;
  185. if (!value || typeof value !== 'object' || Array.isArray(value)) {
  186. return false;
  187. }
  188. const valueObj = value;
  189. return structSchema.fields.every(([fieldSchema, fieldName]) => fieldName in valueObj && this.validateValueInternal(valueObj[fieldName], fieldSchema));
  190. case 'union':
  191. const unionSchema = schema;
  192. const matchesArm = unionSchema.arms.some(([, armSchema]) => this.validateValueInternal(value, armSchema));
  193. const matchesDefault = unionSchema.default ? this.validateValueInternal(value, unionSchema.default) : false;
  194. return matchesArm || matchesDefault;
  195. default:
  196. return false;
  197. }
  198. }
  199. }
  200. exports.XdrSchemaValidator = XdrSchemaValidator;
  201. //# sourceMappingURL=XdrSchemaValidator.js.map