XdrSchemaValidator.js 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  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. case 'optional':
  53. return this.validateOptionalSchema(schema);
  54. case 'const':
  55. return this.validateConstantSchema(schema);
  56. default:
  57. return false;
  58. }
  59. }
  60. validateEnumSchema(schema) {
  61. if (!schema.values || typeof schema.values !== 'object') {
  62. return false;
  63. }
  64. const values = Object.values(schema.values);
  65. const uniqueValues = new Set(values);
  66. if (values.length !== uniqueValues.size) {
  67. return false;
  68. }
  69. return values.every((value) => Number.isInteger(value));
  70. }
  71. validateOpaqueSchema(schema) {
  72. return typeof schema.size === 'number' && Number.isInteger(schema.size) && schema.size >= 0;
  73. }
  74. validateVarlenOpaqueSchema(schema) {
  75. return !schema.size || (typeof schema.size === 'number' && Number.isInteger(schema.size) && schema.size >= 0);
  76. }
  77. validateStringSchema(schema) {
  78. return !schema.size || (typeof schema.size === 'number' && Number.isInteger(schema.size) && schema.size >= 0);
  79. }
  80. validateArraySchema(schema) {
  81. if (!schema.elements || typeof schema.size !== 'number' || !Number.isInteger(schema.size) || schema.size < 0) {
  82. return false;
  83. }
  84. return this.validateSchemaInternal(schema.elements);
  85. }
  86. validateVarlenArraySchema(schema) {
  87. if (!schema.elements) {
  88. return false;
  89. }
  90. if (schema.size !== undefined) {
  91. if (typeof schema.size !== 'number' || !Number.isInteger(schema.size) || schema.size < 0) {
  92. return false;
  93. }
  94. }
  95. return this.validateSchemaInternal(schema.elements);
  96. }
  97. validateStructSchema(schema) {
  98. if (!Array.isArray(schema.fields)) {
  99. return false;
  100. }
  101. const fieldNames = new Set();
  102. for (const field of schema.fields) {
  103. if (!Array.isArray(field) || field.length !== 2) {
  104. return false;
  105. }
  106. const [fieldSchema, fieldName] = field;
  107. if (typeof fieldName !== 'string' || fieldName === '') {
  108. return false;
  109. }
  110. if (fieldNames.has(fieldName)) {
  111. return false;
  112. }
  113. fieldNames.add(fieldName);
  114. if (!this.validateSchemaInternal(fieldSchema)) {
  115. return false;
  116. }
  117. }
  118. return true;
  119. }
  120. validateUnionSchema(schema) {
  121. if (!Array.isArray(schema.arms) || schema.arms.length === 0) {
  122. return false;
  123. }
  124. const discriminants = new Set();
  125. for (const arm of schema.arms) {
  126. if (!Array.isArray(arm) || arm.length !== 2) {
  127. return false;
  128. }
  129. const [discriminant, armSchema] = arm;
  130. if (discriminants.has(discriminant)) {
  131. return false;
  132. }
  133. discriminants.add(discriminant);
  134. if (typeof discriminant !== 'number' && typeof discriminant !== 'string' && typeof discriminant !== 'boolean') {
  135. return false;
  136. }
  137. if (!this.validateSchemaInternal(armSchema)) {
  138. return false;
  139. }
  140. }
  141. if (schema.default && !this.validateSchemaInternal(schema.default)) {
  142. return false;
  143. }
  144. return true;
  145. }
  146. validateOptionalSchema(schema) {
  147. if (!schema.element) {
  148. return false;
  149. }
  150. return this.validateSchemaInternal(schema.element);
  151. }
  152. validateConstantSchema(schema) {
  153. if (typeof schema.value !== 'number' || !Number.isInteger(schema.value)) {
  154. return false;
  155. }
  156. return true;
  157. }
  158. validateValueInternal(value, schema) {
  159. switch (schema.type) {
  160. case 'void':
  161. return value === null || value === undefined;
  162. case 'int':
  163. return typeof value === 'number' && Number.isInteger(value) && value >= -2147483648 && value <= 2147483647;
  164. case 'unsigned_int':
  165. return typeof value === 'number' && Number.isInteger(value) && value >= 0 && value <= 4294967295;
  166. case 'boolean':
  167. return typeof value === 'boolean';
  168. case 'hyper':
  169. return (typeof value === 'number' && Number.isInteger(value)) || typeof value === 'bigint';
  170. case 'unsigned_hyper':
  171. return ((typeof value === 'number' && Number.isInteger(value) && value >= 0) ||
  172. (typeof value === 'bigint' && value >= BigInt(0)));
  173. case 'float':
  174. case 'double':
  175. case 'quadruple':
  176. return typeof value === 'number';
  177. case 'enum':
  178. const enumSchema = schema;
  179. return typeof value === 'string' && value in enumSchema.values;
  180. case 'opaque':
  181. const opaqueSchema = schema;
  182. return value instanceof Uint8Array && value.length === opaqueSchema.size;
  183. case 'vopaque':
  184. const vopaqueSchema = schema;
  185. return value instanceof Uint8Array && (!vopaqueSchema.size || value.length <= vopaqueSchema.size);
  186. case 'string':
  187. const stringSchema = schema;
  188. return typeof value === 'string' && (!stringSchema.size || value.length <= stringSchema.size);
  189. case 'array':
  190. const arraySchema = schema;
  191. return (Array.isArray(value) &&
  192. value.length === arraySchema.size &&
  193. value.every((item) => this.validateValueInternal(item, arraySchema.elements)));
  194. case 'varray':
  195. const varraySchema = schema;
  196. return (Array.isArray(value) &&
  197. (!varraySchema.size || value.length <= varraySchema.size) &&
  198. value.every((item) => this.validateValueInternal(item, varraySchema.elements)));
  199. case 'struct':
  200. const structSchema = schema;
  201. if (!value || typeof value !== 'object' || Array.isArray(value)) {
  202. return false;
  203. }
  204. const valueObj = value;
  205. return structSchema.fields.every(([fieldSchema, fieldName]) => fieldName in valueObj && this.validateValueInternal(valueObj[fieldName], fieldSchema));
  206. case 'union':
  207. const unionSchema = schema;
  208. const matchesArm = unionSchema.arms.some(([, armSchema]) => this.validateValueInternal(value, armSchema));
  209. const matchesDefault = unionSchema.default ? this.validateValueInternal(value, unionSchema.default) : false;
  210. return matchesArm || matchesDefault;
  211. case 'optional':
  212. const optionalSchema = schema;
  213. return value === null || value === undefined || this.validateValueInternal(value, optionalSchema.element);
  214. case 'const':
  215. return true;
  216. default:
  217. return false;
  218. }
  219. }
  220. }
  221. exports.XdrSchemaValidator = XdrSchemaValidator;
  222. //# sourceMappingURL=XdrSchemaValidator.js.map