attribute.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785
  1. 'use strict';
  2. var helpers = require('./helpers');
  3. /** @type ValidatorResult */
  4. var ValidatorResult = helpers.ValidatorResult;
  5. /** @type SchemaError */
  6. var SchemaError = helpers.SchemaError;
  7. var attribute = {};
  8. attribute.ignoreProperties = {
  9. // informative properties
  10. 'id': true,
  11. 'default': true,
  12. 'description': true,
  13. 'title': true,
  14. // arguments to other properties
  15. 'exclusiveMinimum': true,
  16. 'exclusiveMaximum': true,
  17. 'additionalItems': true,
  18. // special-handled properties
  19. '$schema': true,
  20. '$ref': true,
  21. 'extends': true
  22. };
  23. /**
  24. * @name validators
  25. */
  26. var validators = attribute.validators = {};
  27. /**
  28. * Validates whether the instance if of a certain type
  29. * @param instance
  30. * @param schema
  31. * @param options
  32. * @param ctx
  33. * @return {ValidatorResult|null}
  34. */
  35. validators.type = function validateType (instance, schema, options, ctx) {
  36. // Ignore undefined instances
  37. if (instance === undefined) {
  38. return null;
  39. }
  40. var result = new ValidatorResult(instance, schema, options, ctx);
  41. var types = (schema.type instanceof Array) ? schema.type : [schema.type];
  42. if (!types.some(this.testType.bind(this, instance, schema, options, ctx))) {
  43. var list = types.map(function (v) {
  44. return v.id && ('<' + v.id + '>') || (v+'');
  45. });
  46. result.addError({
  47. name: 'type',
  48. argument: list,
  49. message: "is not of a type(s) " + list,
  50. });
  51. }
  52. return result;
  53. };
  54. function testSchema(instance, options, ctx, schema){
  55. return this.validateSchema(instance, schema, options, ctx).valid;
  56. }
  57. /**
  58. * Validates whether the instance matches some of the given schemas
  59. * @param instance
  60. * @param schema
  61. * @param options
  62. * @param ctx
  63. * @return {ValidatorResult|null}
  64. */
  65. validators.anyOf = function validateAnyOf (instance, schema, options, ctx) {
  66. // Ignore undefined instances
  67. if (instance === undefined) {
  68. return null;
  69. }
  70. var result = new ValidatorResult(instance, schema, options, ctx);
  71. if (!(schema.anyOf instanceof Array)){
  72. throw new SchemaError("anyOf must be an array");
  73. }
  74. if (!schema.anyOf.some(testSchema.bind(this, instance, options, ctx))) {
  75. var list = schema.anyOf.map(function (v, i) {
  76. return (v.id && ('<' + v.id + '>')) || (v.title && JSON.stringify(v.title)) || (v['$ref'] && ('<' + v['$ref'] + '>')) || '[subschema '+i+']';
  77. });
  78. result.addError({
  79. name: 'anyOf',
  80. argument: list,
  81. message: "is not any of " + list.join(','),
  82. });
  83. }
  84. return result;
  85. };
  86. /**
  87. * Validates whether the instance matches every given schema
  88. * @param instance
  89. * @param schema
  90. * @param options
  91. * @param ctx
  92. * @return {String|null}
  93. */
  94. validators.allOf = function validateAllOf (instance, schema, options, ctx) {
  95. // Ignore undefined instances
  96. if (instance === undefined) {
  97. return null;
  98. }
  99. if (!(schema.allOf instanceof Array)){
  100. throw new SchemaError("allOf must be an array");
  101. }
  102. var result = new ValidatorResult(instance, schema, options, ctx);
  103. var self = this;
  104. schema.allOf.forEach(function(v, i){
  105. var valid = self.validateSchema(instance, v, options, ctx);
  106. if(!valid.valid){
  107. var msg = (v.id && ('<' + v.id + '>')) || (v.title && JSON.stringify(v.title)) || (v['$ref'] && ('<' + v['$ref'] + '>')) || '[subschema '+i+']';
  108. result.addError({
  109. name: 'allOf',
  110. argument: { id: msg, length: valid.errors.length, valid: valid },
  111. message: 'does not match allOf schema ' + msg + ' with ' + valid.errors.length + ' error[s]:',
  112. });
  113. result.importErrors(valid);
  114. }
  115. });
  116. return result;
  117. };
  118. /**
  119. * Validates whether the instance matches exactly one of the given schemas
  120. * @param instance
  121. * @param schema
  122. * @param options
  123. * @param ctx
  124. * @return {String|null}
  125. */
  126. validators.oneOf = function validateOneOf (instance, schema, options, ctx) {
  127. // Ignore undefined instances
  128. if (instance === undefined) {
  129. return null;
  130. }
  131. if (!(schema.oneOf instanceof Array)){
  132. throw new SchemaError("oneOf must be an array");
  133. }
  134. var result = new ValidatorResult(instance, schema, options, ctx);
  135. var count = schema.oneOf.filter(testSchema.bind(this, instance, options, ctx)).length;
  136. var list = schema.oneOf.map(function (v, i) {
  137. return (v.id && ('<' + v.id + '>')) || (v.title && JSON.stringify(v.title)) || (v['$ref'] && ('<' + v['$ref'] + '>')) || '[subschema '+i+']';
  138. });
  139. if (count!==1) {
  140. result.addError({
  141. name: 'oneOf',
  142. argument: list,
  143. message: "is not exactly one from " + list.join(','),
  144. });
  145. }
  146. return result;
  147. };
  148. /**
  149. * Validates properties
  150. * @param instance
  151. * @param schema
  152. * @param options
  153. * @param ctx
  154. * @return {String|null|ValidatorResult}
  155. */
  156. validators.properties = function validateProperties (instance, schema, options, ctx) {
  157. if(instance === undefined || !(instance instanceof Object)) return;
  158. var result = new ValidatorResult(instance, schema, options, ctx);
  159. var properties = schema.properties || {};
  160. for (var property in properties) {
  161. var prop = (instance || undefined) && instance[property];
  162. var res = this.validateSchema(prop, properties[property], options, ctx.makeChild(properties[property], property));
  163. if(res.instance !== result.instance[property]) result.instance[property] = res.instance;
  164. result.importErrors(res);
  165. }
  166. return result;
  167. };
  168. /**
  169. * Test a specific property within in instance against the additionalProperties schema attribute
  170. * This ignores properties with definitions in the properties schema attribute, but no other attributes.
  171. * If too many more types of property-existance tests pop up they may need their own class of tests (like `type` has)
  172. * @private
  173. * @return {boolean}
  174. */
  175. function testAdditionalProperty (instance, schema, options, ctx, property, result) {
  176. if (schema.properties && schema.properties[property] !== undefined) {
  177. return;
  178. }
  179. if (schema.additionalProperties === false) {
  180. result.addError({
  181. name: 'additionalProperties',
  182. argument: property,
  183. message: "additionalProperty " + JSON.stringify(property) + " exists in instance when not allowed",
  184. });
  185. } else {
  186. var additionalProperties = schema.additionalProperties || {};
  187. var res = this.validateSchema(instance[property], additionalProperties, options, ctx.makeChild(additionalProperties, property));
  188. if(res.instance !== result.instance[property]) result.instance[property] = res.instance;
  189. result.importErrors(res);
  190. }
  191. }
  192. /**
  193. * Validates patternProperties
  194. * @param instance
  195. * @param schema
  196. * @param options
  197. * @param ctx
  198. * @return {String|null|ValidatorResult}
  199. */
  200. validators.patternProperties = function validatePatternProperties (instance, schema, options, ctx) {
  201. if(instance === undefined) return;
  202. if(!this.types.object(instance)) return;
  203. var result = new ValidatorResult(instance, schema, options, ctx);
  204. var patternProperties = schema.patternProperties || {};
  205. for (var property in instance) {
  206. var test = true;
  207. for (var pattern in patternProperties) {
  208. var expr = new RegExp(pattern);
  209. if (!expr.test(property)) {
  210. continue;
  211. }
  212. test = false;
  213. var res = this.validateSchema(instance[property], patternProperties[pattern], options, ctx.makeChild(patternProperties[pattern], property));
  214. if(res.instance !== result.instance[property]) result.instance[property] = res.instance;
  215. result.importErrors(res);
  216. }
  217. if (test) {
  218. testAdditionalProperty.call(this, instance, schema, options, ctx, property, result);
  219. }
  220. }
  221. return result;
  222. };
  223. /**
  224. * Validates additionalProperties
  225. * @param instance
  226. * @param schema
  227. * @param options
  228. * @param ctx
  229. * @return {String|null|ValidatorResult}
  230. */
  231. validators.additionalProperties = function validateAdditionalProperties (instance, schema, options, ctx) {
  232. if(instance === undefined) return;
  233. if(!this.types.object(instance)) return;
  234. // if patternProperties is defined then we'll test when that one is called instead
  235. if (schema.patternProperties) {
  236. return null;
  237. }
  238. var result = new ValidatorResult(instance, schema, options, ctx);
  239. for (var property in instance) {
  240. testAdditionalProperty.call(this, instance, schema, options, ctx, property, result);
  241. }
  242. return result;
  243. };
  244. /**
  245. * Validates whether the instance value is at least of a certain length, when the instance value is a string.
  246. * @param instance
  247. * @param schema
  248. * @return {String|null}
  249. */
  250. validators.minProperties = function validateMinProperties (instance, schema, options, ctx) {
  251. if (!instance || typeof instance !== 'object') {
  252. return null;
  253. }
  254. var result = new ValidatorResult(instance, schema, options, ctx);
  255. var keys = Object.keys(instance);
  256. if (!(keys.length >= schema.minProperties)) {
  257. result.addError({
  258. name: 'minProperties',
  259. argument: schema.minProperties,
  260. message: "does not meet minimum property length of " + schema.minProperties,
  261. })
  262. }
  263. return result;
  264. };
  265. /**
  266. * Validates whether the instance value is at most of a certain length, when the instance value is a string.
  267. * @param instance
  268. * @param schema
  269. * @return {String|null}
  270. */
  271. validators.maxProperties = function validateMaxProperties (instance, schema, options, ctx) {
  272. if (!instance || typeof instance !== 'object') {
  273. return null;
  274. }
  275. var result = new ValidatorResult(instance, schema, options, ctx);
  276. var keys = Object.keys(instance);
  277. if (!(keys.length <= schema.maxProperties)) {
  278. result.addError({
  279. name: 'maxProperties',
  280. argument: schema.maxProperties,
  281. message: "does not meet maximum property length of " + schema.maxProperties,
  282. });
  283. }
  284. return result;
  285. };
  286. /**
  287. * Validates items when instance is an array
  288. * @param instance
  289. * @param schema
  290. * @param options
  291. * @param ctx
  292. * @return {String|null|ValidatorResult}
  293. */
  294. validators.items = function validateItems (instance, schema, options, ctx) {
  295. if (!(instance instanceof Array)) {
  296. return null;
  297. }
  298. var self = this;
  299. var result = new ValidatorResult(instance, schema, options, ctx);
  300. if (instance === undefined || !schema.items) {
  301. return result;
  302. }
  303. instance.every(function (value, i) {
  304. var items = (schema.items instanceof Array) ? (schema.items[i] || schema.additionalItems) : schema.items;
  305. if (items === undefined) {
  306. return true;
  307. }
  308. if (items === false) {
  309. result.addError({
  310. name: 'items',
  311. message: "additionalItems not permitted",
  312. });
  313. return false;
  314. }
  315. var res = self.validateSchema(value, items, options, ctx.makeChild(items, i));
  316. if(res.instance !== result.instance[i]) result.instance[i] = res.instance;
  317. result.importErrors(res);
  318. return true;
  319. });
  320. return result;
  321. };
  322. /**
  323. * Validates minimum and exclusiveMinimum when the type of the instance value is a number.
  324. * @param instance
  325. * @param schema
  326. * @return {String|null}
  327. */
  328. validators.minimum = function validateMinimum (instance, schema, options, ctx) {
  329. if (typeof instance !== 'number') {
  330. return null;
  331. }
  332. var result = new ValidatorResult(instance, schema, options, ctx);
  333. var valid = true;
  334. if (schema.exclusiveMinimum && schema.exclusiveMinimum === true) {
  335. valid = instance > schema.minimum;
  336. } else {
  337. valid = instance >= schema.minimum;
  338. }
  339. if (!valid) {
  340. result.addError({
  341. name: 'minimum',
  342. argument: schema.minimum,
  343. message: "must have a minimum value of " + schema.minimum,
  344. });
  345. }
  346. return result;
  347. };
  348. /**
  349. * Validates maximum and exclusiveMaximum when the type of the instance value is a number.
  350. * @param instance
  351. * @param schema
  352. * @return {String|null}
  353. */
  354. validators.maximum = function validateMaximum (instance, schema, options, ctx) {
  355. if (typeof instance !== 'number') {
  356. return null;
  357. }
  358. var result = new ValidatorResult(instance, schema, options, ctx);
  359. var valid;
  360. if (schema.exclusiveMaximum && schema.exclusiveMaximum === true) {
  361. valid = instance < schema.maximum;
  362. } else {
  363. valid = instance <= schema.maximum;
  364. }
  365. if (!valid) {
  366. result.addError({
  367. name: 'maximum',
  368. argument: schema.maximum,
  369. message: "must have a maximum value of " + schema.maximum,
  370. });
  371. }
  372. return result;
  373. };
  374. /**
  375. * Validates divisibleBy when the type of the instance value is a number.
  376. * Of course, this is susceptible to floating point error since it compares the floating points
  377. * and not the JSON byte sequences to arbitrary precision.
  378. * @param instance
  379. * @param schema
  380. * @return {String|null}
  381. */
  382. validators.divisibleBy = function validateDivisibleBy (instance, schema, options, ctx) {
  383. if (typeof instance !== 'number') {
  384. return null;
  385. }
  386. if (schema.divisibleBy == 0) {
  387. throw new SchemaError("divisibleBy cannot be zero");
  388. }
  389. var result = new ValidatorResult(instance, schema, options, ctx);
  390. if (instance / schema.divisibleBy % 1) {
  391. result.addError({
  392. name: 'divisibleBy',
  393. argument: schema.divisibleBy,
  394. message: "is not divisible by (multiple of) " + JSON.stringify(schema.divisibleBy),
  395. });
  396. }
  397. return result;
  398. };
  399. /**
  400. * Validates divisibleBy when the type of the instance value is a number.
  401. * Of course, this is susceptible to floating point error since it compares the floating points
  402. * and not the JSON byte sequences to arbitrary precision.
  403. * @param instance
  404. * @param schema
  405. * @return {String|null}
  406. */
  407. validators.multipleOf = function validateMultipleOf (instance, schema, options, ctx) {
  408. if (typeof instance !== 'number') {
  409. return null;
  410. }
  411. if (schema.multipleOf == 0) {
  412. throw new SchemaError("multipleOf cannot be zero");
  413. }
  414. var result = new ValidatorResult(instance, schema, options, ctx);
  415. if (instance / schema.multipleOf % 1) {
  416. result.addError({
  417. name: 'multipleOf',
  418. argument: schema.multipleOf,
  419. message: "is not a multiple of (divisible by) " + JSON.stringify(schema.multipleOf),
  420. });
  421. }
  422. return result;
  423. };
  424. /**
  425. * Validates whether the instance value is present.
  426. * @param instance
  427. * @param schema
  428. * @return {String|null}
  429. */
  430. validators.required = function validateRequired (instance, schema, options, ctx) {
  431. var result = new ValidatorResult(instance, schema, options, ctx);
  432. if (instance === undefined && schema.required === true) {
  433. result.addError({
  434. name: 'required',
  435. message: "is required"
  436. });
  437. } else if (instance && typeof instance==='object' && Array.isArray(schema.required)) {
  438. schema.required.forEach(function(n){
  439. if(instance[n]===undefined){
  440. result.addError({
  441. name: 'required',
  442. argument: n,
  443. message: "requires property " + JSON.stringify(n),
  444. });
  445. }
  446. });
  447. }
  448. return result;
  449. };
  450. /**
  451. * Validates whether the instance value matches the regular expression, when the instance value is a string.
  452. * @param instance
  453. * @param schema
  454. * @return {String|null}
  455. */
  456. validators.pattern = function validatePattern (instance, schema, options, ctx) {
  457. if (typeof instance !== 'string') {
  458. return null;
  459. }
  460. var result = new ValidatorResult(instance, schema, options, ctx);
  461. if (!instance.match(schema.pattern)) {
  462. result.addError({
  463. name: 'pattern',
  464. argument: schema.pattern,
  465. message: "does not match pattern " + JSON.stringify(schema.pattern),
  466. });
  467. }
  468. return result;
  469. };
  470. /**
  471. * Validates whether the instance value is of a certain defined format or a custom
  472. * format.
  473. * The following formats are supported for string types:
  474. * - date-time
  475. * - date
  476. * - time
  477. * - ip-address
  478. * - ipv6
  479. * - uri
  480. * - color
  481. * - host-name
  482. * - alpha
  483. * - alpha-numeric
  484. * - utc-millisec
  485. * @param instance
  486. * @param schema
  487. * @param [options]
  488. * @param [ctx]
  489. * @return {String|null}
  490. */
  491. validators.format = function validateFormat (instance, schema, options, ctx) {
  492. var result = new ValidatorResult(instance, schema, options, ctx);
  493. if (!result.disableFormat && !helpers.isFormat(instance, schema.format, this)) {
  494. result.addError({
  495. name: 'format',
  496. argument: schema.format,
  497. message: "does not conform to the " + JSON.stringify(schema.format) + " format",
  498. });
  499. }
  500. return result;
  501. };
  502. /**
  503. * Validates whether the instance value is at least of a certain length, when the instance value is a string.
  504. * @param instance
  505. * @param schema
  506. * @return {String|null}
  507. */
  508. validators.minLength = function validateMinLength (instance, schema, options, ctx) {
  509. if (!(typeof instance === 'string')) {
  510. return null;
  511. }
  512. var result = new ValidatorResult(instance, schema, options, ctx);
  513. if (!(instance.length >= schema.minLength)) {
  514. result.addError({
  515. name: 'minLength',
  516. argument: schema.minLength,
  517. message: "does not meet minimum length of " + schema.minLength,
  518. });
  519. }
  520. return result;
  521. };
  522. /**
  523. * Validates whether the instance value is at most of a certain length, when the instance value is a string.
  524. * @param instance
  525. * @param schema
  526. * @return {String|null}
  527. */
  528. validators.maxLength = function validateMaxLength (instance, schema, options, ctx) {
  529. if (!(typeof instance === 'string')) {
  530. return null;
  531. }
  532. var result = new ValidatorResult(instance, schema, options, ctx);
  533. if (!(instance.length <= schema.maxLength)) {
  534. result.addError({
  535. name: 'maxLength',
  536. argument: schema.maxLength,
  537. message: "does not meet maximum length of " + schema.maxLength,
  538. });
  539. }
  540. return result;
  541. };
  542. /**
  543. * Validates whether instance contains at least a minimum number of items, when the instance is an Array.
  544. * @param instance
  545. * @param schema
  546. * @return {String|null}
  547. */
  548. validators.minItems = function validateMinItems (instance, schema, options, ctx) {
  549. if (!(instance instanceof Array)) {
  550. return null;
  551. }
  552. var result = new ValidatorResult(instance, schema, options, ctx);
  553. if (!(instance.length >= schema.minItems)) {
  554. result.addError({
  555. name: 'minItems',
  556. argument: schema.minItems,
  557. message: "does not meet minimum length of " + schema.minItems,
  558. });
  559. }
  560. return result;
  561. };
  562. /**
  563. * Validates whether instance contains no more than a maximum number of items, when the instance is an Array.
  564. * @param instance
  565. * @param schema
  566. * @return {String|null}
  567. */
  568. validators.maxItems = function validateMaxItems (instance, schema, options, ctx) {
  569. if (!(instance instanceof Array)) {
  570. return null;
  571. }
  572. var result = new ValidatorResult(instance, schema, options, ctx);
  573. if (!(instance.length <= schema.maxItems)) {
  574. result.addError({
  575. name: 'maxItems',
  576. argument: schema.maxItems,
  577. message: "does not meet maximum length of " + schema.maxItems,
  578. });
  579. }
  580. return result;
  581. };
  582. /**
  583. * Validates that every item in an instance array is unique, when instance is an array
  584. * @param instance
  585. * @param schema
  586. * @param options
  587. * @param ctx
  588. * @return {String|null|ValidatorResult}
  589. */
  590. validators.uniqueItems = function validateUniqueItems (instance, schema, options, ctx) {
  591. var result = new ValidatorResult(instance, schema, options, ctx);
  592. if (!(instance instanceof Array)) {
  593. return result;
  594. }
  595. function testArrays (v, i, a) {
  596. for (var j = i + 1; j < a.length; j++) if (helpers.deepCompareStrict(v, a[j])) {
  597. return false;
  598. }
  599. return true;
  600. }
  601. if (!instance.every(testArrays)) {
  602. result.addError({
  603. name: 'uniqueItems',
  604. message: "contains duplicate item",
  605. });
  606. }
  607. return result;
  608. };
  609. /**
  610. * Deep compares arrays for duplicates
  611. * @param v
  612. * @param i
  613. * @param a
  614. * @private
  615. * @return {boolean}
  616. */
  617. function testArrays (v, i, a) {
  618. var j, len = a.length;
  619. for (j = i + 1, len; j < len; j++) {
  620. if (helpers.deepCompareStrict(v, a[j])) {
  621. return false;
  622. }
  623. }
  624. return true;
  625. }
  626. /**
  627. * Validates whether there are no duplicates, when the instance is an Array.
  628. * @param instance
  629. * @return {String|null}
  630. */
  631. validators.uniqueItems = function validateUniqueItems (instance, schema, options, ctx) {
  632. if (!(instance instanceof Array)) {
  633. return null;
  634. }
  635. var result = new ValidatorResult(instance, schema, options, ctx);
  636. if (!instance.every(testArrays)) {
  637. result.addError({
  638. name: 'uniqueItems',
  639. message: "contains duplicate item",
  640. });
  641. }
  642. return result;
  643. };
  644. /**
  645. * Validate for the presence of dependency properties, if the instance is an object.
  646. * @param instance
  647. * @param schema
  648. * @param options
  649. * @param ctx
  650. * @return {null|ValidatorResult}
  651. */
  652. validators.dependencies = function validateDependencies (instance, schema, options, ctx) {
  653. if (!instance || typeof instance != 'object') {
  654. return null;
  655. }
  656. var result = new ValidatorResult(instance, schema, options, ctx);
  657. for (var property in schema.dependencies) {
  658. if (instance[property] === undefined) {
  659. continue;
  660. }
  661. var dep = schema.dependencies[property];
  662. var childContext = ctx.makeChild(dep, property);
  663. if (typeof dep == 'string') {
  664. dep = [dep];
  665. }
  666. if (dep instanceof Array) {
  667. dep.forEach(function (prop) {
  668. if (instance[prop] === undefined) {
  669. result.addError({
  670. // FIXME there's two different "dependencies" errors here with slightly different outputs
  671. // Can we make these the same? Or should we create different error types?
  672. name: 'dependencies',
  673. argument: childContext.propertyPath,
  674. message: "property " + prop + " not found, required by " + childContext.propertyPath,
  675. });
  676. }
  677. });
  678. } else {
  679. var res = this.validateSchema(instance, dep, options, childContext);
  680. if(result.instance !== res.instance) result.instance = res.instance;
  681. if (res && res.errors.length) {
  682. result.addError({
  683. name: 'dependencies',
  684. argument: childContext.propertyPath,
  685. message: "does not meet dependency required by " + childContext.propertyPath,
  686. });
  687. result.importErrors(res);
  688. }
  689. }
  690. }
  691. return result;
  692. };
  693. /**
  694. * Validates whether the instance value is one of the enumerated values.
  695. *
  696. * @param instance
  697. * @param schema
  698. * @return {ValidatorResult|null}
  699. */
  700. validators['enum'] = function validateEnum (instance, schema, options, ctx) {
  701. if (!(schema['enum'] instanceof Array)) {
  702. throw new SchemaError("enum expects an array", schema);
  703. }
  704. if (instance === undefined) {
  705. return null;
  706. }
  707. var result = new ValidatorResult(instance, schema, options, ctx);
  708. if (!schema['enum'].some(helpers.deepCompareStrict.bind(null, instance))) {
  709. result.addError({
  710. name: 'enum',
  711. argument: schema['enum'],
  712. message: "is not one of enum values: " + schema['enum'].join(','),
  713. });
  714. }
  715. return result;
  716. };
  717. /**
  718. * Validates whether the instance if of a prohibited type.
  719. * @param instance
  720. * @param schema
  721. * @param options
  722. * @param ctx
  723. * @return {null|ValidatorResult}
  724. */
  725. validators.not = validators.disallow = function validateNot (instance, schema, options, ctx) {
  726. var self = this;
  727. if(instance===undefined) return null;
  728. var result = new ValidatorResult(instance, schema, options, ctx);
  729. var notTypes = schema.not || schema.disallow;
  730. if(!notTypes) return null;
  731. if(!(notTypes instanceof Array)) notTypes=[notTypes];
  732. notTypes.forEach(function (type) {
  733. if (self.testType(instance, schema, options, ctx, type)) {
  734. var schemaId = type && type.id && ('<' + type.id + '>') || type;
  735. result.addError({
  736. name: 'not',
  737. argument: schemaId,
  738. message: "is of prohibited type " + schemaId,
  739. });
  740. }
  741. });
  742. return result;
  743. };
  744. module.exports = attribute;