issues.spec.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816
  1. 'use strict';
  2. var Ajv = require('./ajv')
  3. , should = require('./chai').should();
  4. describe('issue #8: schema with shared references', function() {
  5. it('should be supported by addSchema', spec('addSchema'));
  6. it('should be supported by compile', spec('compile'));
  7. function spec(method) {
  8. return function() {
  9. var ajv = new Ajv;
  10. var propertySchema = {
  11. type: 'string',
  12. maxLength: 4
  13. };
  14. var schema = {
  15. $id: 'obj.json#',
  16. type: 'object',
  17. properties: {
  18. foo: propertySchema,
  19. bar: propertySchema
  20. }
  21. };
  22. ajv[method](schema);
  23. var result = ajv.validate('obj.json#', { foo: 'abc', bar: 'def' });
  24. result .should.equal(true);
  25. result = ajv.validate('obj.json#', { foo: 'abcde', bar: 'fghg' });
  26. result .should.equal(false);
  27. ajv.errors .should.have.length(1);
  28. };
  29. }
  30. });
  31. describe('issue #50: references with "definitions"', function () {
  32. it('should be supported by addSchema', spec('addSchema'));
  33. it('should be supported by compile', spec('addSchema'));
  34. function spec(method) {
  35. return function() {
  36. var result;
  37. var ajv = new Ajv;
  38. ajv[method]({
  39. $id: 'http://example.com/test/person.json#',
  40. definitions: {
  41. name: { type: 'string' }
  42. },
  43. type: 'object',
  44. properties: {
  45. name: { $ref: '#/definitions/name'}
  46. }
  47. });
  48. ajv[method]({
  49. $id: 'http://example.com/test/employee.json#',
  50. type: 'object',
  51. properties: {
  52. person: { $ref: '/test/person.json#' },
  53. role: { type: 'string' }
  54. }
  55. });
  56. result = ajv.validate('http://example.com/test/employee.json#', {
  57. person: {
  58. name: 'Alice'
  59. },
  60. role: 'Programmer'
  61. });
  62. result. should.equal(true);
  63. should.equal(ajv.errors, null);
  64. };
  65. }
  66. });
  67. describe('issue #182, NaN validation', function() {
  68. it('should not pass minimum/maximum validation', function() {
  69. testNaN({ minimum: 1 }, false);
  70. testNaN({ maximum: 1 }, false);
  71. });
  72. it('should pass type: number validation', function() {
  73. testNaN({ type: 'number' }, true);
  74. });
  75. it('should not pass type: integer validation', function() {
  76. testNaN({ type: 'integer' }, false);
  77. });
  78. function testNaN(schema, NaNisValid) {
  79. var ajv = new Ajv;
  80. var validate = ajv.compile(schema);
  81. validate(NaN) .should.equal(NaNisValid);
  82. }
  83. });
  84. describe('issue #204, options schemas and $data used together', function() {
  85. it('should use v5 metaschemas by default', function() {
  86. var ajv = new Ajv({
  87. schemas: [{$id: 'str', type: 'string'}],
  88. $data: true
  89. });
  90. var schema = { const: 42 };
  91. var validate = ajv.compile(schema);
  92. validate(42) .should.equal(true);
  93. validate(43) .should.equal(false);
  94. ajv.validate('str', 'foo') .should.equal(true);
  95. ajv.validate('str', 42) .should.equal(false);
  96. });
  97. });
  98. describe('issue #181, custom keyword is not validated in allErrors mode if there were previous error', function() {
  99. it('should validate custom keyword that doesn\'t create errors', function() {
  100. testCustomKeywordErrors({
  101. type:'object',
  102. errors: true,
  103. validate: function v(/* value */) {
  104. return false;
  105. }
  106. });
  107. });
  108. it('should validate custom keyword that creates errors', function() {
  109. testCustomKeywordErrors({
  110. type:'object',
  111. errors: true,
  112. validate: function v(/* value */) {
  113. v.errors = v.errors || [];
  114. v.errors.push({
  115. keyword: 'alwaysFails',
  116. message: 'alwaysFails error',
  117. params: {
  118. keyword: 'alwaysFails'
  119. }
  120. });
  121. return false;
  122. }
  123. });
  124. });
  125. function testCustomKeywordErrors(def) {
  126. var ajv = new Ajv({ allErrors: true });
  127. ajv.addKeyword('alwaysFails', def);
  128. var schema = {
  129. required: ['foo'],
  130. alwaysFails: true
  131. };
  132. var validate = ajv.compile(schema);
  133. validate({ foo: 1 }) .should.equal(false);
  134. validate.errors .should.have.length(1);
  135. validate.errors[0].keyword .should.equal('alwaysFails');
  136. validate({}) .should.equal(false);
  137. validate.errors .should.have.length(2);
  138. validate.errors[0].keyword .should.equal('required');
  139. validate.errors[1].keyword .should.equal('alwaysFails');
  140. }
  141. });
  142. describe('issue #210, mutual recursive $refs that are schema fragments', function() {
  143. it('should compile and validate schema when one ref is fragment', function() {
  144. var ajv = new Ajv;
  145. ajv.addSchema({
  146. "$id" : "foo",
  147. "definitions": {
  148. "bar": {
  149. "properties": {
  150. "baz": {
  151. "anyOf": [
  152. { "enum": [42] },
  153. { "$ref": "boo" }
  154. ]
  155. }
  156. }
  157. }
  158. }
  159. });
  160. ajv.addSchema({
  161. "$id" : "boo",
  162. "type": "object",
  163. "required": ["quux"],
  164. "properties": {
  165. "quux": { "$ref": "foo#/definitions/bar" }
  166. }
  167. });
  168. var validate = ajv.compile({ "$ref": "foo#/definitions/bar" });
  169. validate({ baz: { quux: { baz: 42 } } }) .should.equal(true);
  170. validate({ baz: { quux: { baz: "foo" } } }) .should.equal(false);
  171. });
  172. it('should compile and validate schema when both refs are fragments', function() {
  173. var ajv = new Ajv;
  174. ajv.addSchema({
  175. "$id" : "foo",
  176. "definitions": {
  177. "bar": {
  178. "properties": {
  179. "baz": {
  180. "anyOf": [
  181. { "enum": [42] },
  182. { "$ref": "boo#/definitions/buu" }
  183. ]
  184. }
  185. }
  186. }
  187. }
  188. });
  189. ajv.addSchema({
  190. "$id" : "boo",
  191. "definitions": {
  192. "buu": {
  193. "type": "object",
  194. "required": ["quux"],
  195. "properties": {
  196. "quux": { "$ref": "foo#/definitions/bar" }
  197. }
  198. }
  199. }
  200. });
  201. var validate = ajv.compile({ "$ref": "foo#/definitions/bar" });
  202. validate({ baz: { quux: { baz: 42 } } }) .should.equal(true);
  203. validate({ baz: { quux: { baz: "foo" } } }) .should.equal(false);
  204. });
  205. });
  206. describe('issue #240, mutually recursive fragment refs reference a common schema', function() {
  207. var apiSchema = {
  208. $schema: 'http://json-schema.org/draft-07/schema#',
  209. $id: 'schema://api.schema#',
  210. resource: {
  211. $id: '#resource',
  212. properties: {
  213. id: { type: 'string' }
  214. }
  215. },
  216. resourceIdentifier: {
  217. $id: '#resource_identifier',
  218. properties: {
  219. id: { type: 'string' },
  220. type: { type: 'string' }
  221. }
  222. }
  223. };
  224. var domainSchema = {
  225. $schema: 'http://json-schema.org/draft-07/schema#',
  226. $id: 'schema://domain.schema#',
  227. properties: {
  228. data: {
  229. oneOf: [
  230. { $ref: 'schema://library.schema#resource_identifier' },
  231. { $ref: 'schema://catalog_item.schema#resource_identifier' },
  232. ]
  233. }
  234. }
  235. };
  236. it('should compile and validate schema when one ref is fragment', function() {
  237. var ajv = new Ajv;
  238. var librarySchema = {
  239. $schema: 'http://json-schema.org/draft-07/schema#',
  240. $id: 'schema://library.schema#',
  241. properties: {
  242. name: { type: 'string' },
  243. links: {
  244. properties: {
  245. catalogItems: {
  246. type: 'array',
  247. items: { $ref: 'schema://catalog_item_resource_identifier.schema#' }
  248. }
  249. }
  250. }
  251. },
  252. definitions: {
  253. resource_identifier: {
  254. $id: '#resource_identifier',
  255. allOf: [
  256. {
  257. properties: {
  258. type: {
  259. type: 'string',
  260. 'enum': ['Library']
  261. }
  262. }
  263. },
  264. { $ref: 'schema://api.schema#resource_identifier' }
  265. ]
  266. }
  267. }
  268. };
  269. var catalogItemSchema = {
  270. $schema: 'http://json-schema.org/draft-07/schema#',
  271. $id: 'schema://catalog_item.schema#',
  272. properties: {
  273. name: { type: 'string' },
  274. links: {
  275. properties: {
  276. library: { $ref: 'schema://library.schema#resource_identifier' }
  277. }
  278. }
  279. },
  280. definitions: {
  281. resource_identifier: {
  282. $id: '#resource_identifier',
  283. allOf: [
  284. {
  285. properties: {
  286. type: {
  287. type: 'string',
  288. 'enum': ['CatalogItem']
  289. }
  290. }
  291. },
  292. { $ref: 'schema://api.schema#resource_identifier' }
  293. ]
  294. }
  295. }
  296. };
  297. var catalogItemResourceIdentifierSchema = {
  298. $schema: 'http://json-schema.org/draft-07/schema#',
  299. $id: 'schema://catalog_item_resource_identifier.schema#',
  300. allOf: [
  301. {
  302. properties: {
  303. type: {
  304. type: 'string',
  305. enum: ['CatalogItem']
  306. }
  307. }
  308. },
  309. {
  310. $ref: 'schema://api.schema#resource_identifier'
  311. }
  312. ]
  313. };
  314. ajv.addSchema(librarySchema);
  315. ajv.addSchema(catalogItemSchema);
  316. ajv.addSchema(catalogItemResourceIdentifierSchema);
  317. ajv.addSchema(apiSchema);
  318. var validate = ajv.compile(domainSchema);
  319. testSchema(validate);
  320. });
  321. it('should compile and validate schema when both refs are fragments', function() {
  322. var ajv = new Ajv;
  323. var librarySchema = {
  324. $schema: 'http://json-schema.org/draft-07/schema#',
  325. $id: 'schema://library.schema#',
  326. properties: {
  327. name: { type: 'string' },
  328. links: {
  329. properties: {
  330. catalogItems: {
  331. type: 'array',
  332. items: { $ref: 'schema://catalog_item.schema#resource_identifier' }
  333. }
  334. }
  335. }
  336. },
  337. definitions: {
  338. resource_identifier: {
  339. $id: '#resource_identifier',
  340. allOf: [
  341. {
  342. properties: {
  343. type: {
  344. type: 'string',
  345. 'enum': ['Library']
  346. }
  347. }
  348. },
  349. { $ref: 'schema://api.schema#resource_identifier' }
  350. ]
  351. }
  352. }
  353. };
  354. var catalogItemSchema = {
  355. $schema: 'http://json-schema.org/draft-07/schema#',
  356. $id: 'schema://catalog_item.schema#',
  357. properties: {
  358. name: { type: 'string' },
  359. links: {
  360. properties: {
  361. library: { $ref: 'schema://library.schema#resource_identifier' }
  362. }
  363. }
  364. },
  365. definitions: {
  366. resource_identifier: {
  367. $id: '#resource_identifier',
  368. allOf: [
  369. {
  370. properties: {
  371. type: {
  372. type: 'string',
  373. 'enum': ['CatalogItem']
  374. }
  375. }
  376. },
  377. { $ref: 'schema://api.schema#resource_identifier' }
  378. ]
  379. }
  380. }
  381. };
  382. ajv.addSchema(librarySchema);
  383. ajv.addSchema(catalogItemSchema);
  384. ajv.addSchema(apiSchema);
  385. var validate = ajv.compile(domainSchema);
  386. testSchema(validate);
  387. });
  388. function testSchema(validate) {
  389. validate({ data: { type: 'Library', id: '123' } }) .should.equal(true);
  390. validate({ data: { type: 'Library', id: 123 } }) .should.equal(false);
  391. validate({ data: { type: 'CatalogItem', id: '123' } }) .should.equal(true);
  392. validate({ data: { type: 'CatalogItem', id: 123 } }) .should.equal(false);
  393. validate({ data: { type: 'Foo', id: '123' } }) .should.equal(false);
  394. }
  395. });
  396. describe('issue #259, support validating [meta-]schemas against themselves', function() {
  397. it('should add schema before validation if "id" is the same as "$schema"', function() {
  398. var ajv = new Ajv;
  399. var hyperSchema = require('./remotes/hyper-schema.json');
  400. ajv.addMetaSchema(hyperSchema);
  401. });
  402. });
  403. describe.skip('issue #273, schemaPath in error in referenced schema', function() {
  404. it('should have canonic reference with hash after file name', function() {
  405. test(new Ajv);
  406. test(new Ajv({inlineRefs: false}));
  407. function test(ajv) {
  408. var schema = {
  409. "properties": {
  410. "a": { "$ref": "int" }
  411. }
  412. };
  413. var referencedSchema = {
  414. "id": "int",
  415. "type": "integer"
  416. };
  417. ajv.addSchema(referencedSchema);
  418. var validate = ajv.compile(schema);
  419. validate({ "a": "foo" }) .should.equal(false);
  420. validate.errors[0].schemaPath .should.equal('int#/type');
  421. }
  422. });
  423. });
  424. describe('issue #342, support uniqueItems with some non-JSON objects', function() {
  425. var validate;
  426. before(function() {
  427. var ajv = new Ajv;
  428. validate = ajv.compile({ uniqueItems: true });
  429. });
  430. it('should allow different RegExps', function() {
  431. validate([/foo/, /bar/]) .should.equal(true);
  432. validate([/foo/ig, /foo/gi]) .should.equal(false);
  433. validate([/foo/, {}]) .should.equal(true);
  434. });
  435. it('should allow different Dates', function() {
  436. validate([new Date('2016-11-11'), new Date('2016-11-12')]) .should.equal(true);
  437. validate([new Date('2016-11-11'), new Date('2016-11-11')]) .should.equal(false);
  438. validate([new Date('2016-11-11'), {}]) .should.equal(true);
  439. });
  440. it('should allow undefined properties', function() {
  441. validate([{}, {foo: undefined}]) .should.equal(true);
  442. validate([{foo: undefined}, {}]) .should.equal(true);
  443. validate([{foo: undefined}, {bar: undefined}]) .should.equal(true);
  444. validate([{foo: undefined}, {foo: undefined}]) .should.equal(false);
  445. });
  446. });
  447. describe('issue #388, code clean-up not working', function() {
  448. it('should remove assignement to rootData if it is not used', function() {
  449. var ajv = new Ajv;
  450. var validate = ajv.compile({
  451. type: 'object',
  452. properties: {
  453. foo: { type: 'string' }
  454. }
  455. });
  456. var code = validate.toString();
  457. code.match(/rootData/g).length .should.equal(1);
  458. });
  459. it('should remove assignement to errors if they are not used', function() {
  460. var ajv = new Ajv;
  461. var validate = ajv.compile({
  462. type: 'object'
  463. });
  464. var code = validate.toString();
  465. should.equal(code.match(/[^.]errors|vErrors/g), null);
  466. });
  467. });
  468. describe('issue #485, order of type validation', function() {
  469. it('should validate types befor keywords', function() {
  470. var ajv = new Ajv({allErrors: true});
  471. var validate = ajv.compile({
  472. type: ['integer', 'string'],
  473. required: ['foo'],
  474. minimum: 2
  475. });
  476. validate(2) .should.equal(true);
  477. validate('foo') .should.equal(true);
  478. validate(1.5) .should.equal(false);
  479. checkErrors(['type', 'minimum']);
  480. validate({}) .should.equal(false);
  481. checkErrors(['type', 'required']);
  482. function checkErrors(expectedErrs) {
  483. validate.errors .should.have.length(expectedErrs.length);
  484. expectedErrs.forEach(function (keyword, i) {
  485. validate.errors[i].keyword .should.equal(keyword);
  486. });
  487. }
  488. });
  489. });
  490. describe('issue #521, incorrect warning with "id" property', function() {
  491. it('should not log warning', function() {
  492. var ajv = new Ajv({schemaId: '$id'});
  493. var consoleWarn = console.warn;
  494. console.warn = function() {
  495. throw new Error('should not log warning');
  496. };
  497. try {
  498. ajv.compile({
  499. "$id": "http://example.com/schema.json",
  500. "type": "object",
  501. "properties": {
  502. "id": {"type": "string"},
  503. },
  504. "required": [ "id"]
  505. });
  506. } finally {
  507. console.warn = consoleWarn;
  508. }
  509. });
  510. });
  511. describe('issue #533, throwing missing ref exception with option missingRefs: "ignore"', function() {
  512. var schema = {
  513. "type": "object",
  514. "properties": {
  515. "foo": {"$ref": "#/definitions/missing"},
  516. "bar": {"$ref": "#/definitions/missing"}
  517. }
  518. };
  519. it('should pass validation without throwing exception', function() {
  520. var ajv = new Ajv({missingRefs: 'ignore'});
  521. var validate = ajv.compile(schema);
  522. validate({foo: 'anything'}) .should.equal(true);
  523. validate({foo: 'anything', bar: 'whatever'}) .should.equal(true);
  524. });
  525. it('should throw exception during schema compilation with option missingRefs: true', function() {
  526. var ajv = new Ajv;
  527. should.throw(function() {
  528. ajv.compile(schema);
  529. });
  530. });
  531. });
  532. describe('full date format validation should understand leap years', function () {
  533. it('should handle non leap year affected dates with date-time', function() {
  534. var ajv = new Ajv({ format: 'full' });
  535. var schema = { format: 'date-time' };
  536. var validDateTime = '2016-01-31T00:00:00Z';
  537. ajv.validate(schema, validDateTime).should.equal(true);
  538. });
  539. it('should handle non leap year affected dates with date', function () {
  540. var ajv = new Ajv({ format: 'full' });
  541. var schema = { format: 'date' };
  542. var validDate = '2016-11-30';
  543. ajv.validate(schema, validDate).should.equal(true);
  544. });
  545. it('should handle year leaps as date-time', function() {
  546. var ajv = new Ajv({ format: 'full' });
  547. var schema = { format: 'date-time' };
  548. var validDateTime = '2016-02-29T00:00:00Z';
  549. var invalidDateTime = '2017-02-29T00:00:00Z';
  550. ajv.validate(schema, validDateTime) .should.equal(true);
  551. ajv.validate(schema, invalidDateTime) .should.equal(false);
  552. });
  553. it('should handle year leaps as date', function() {
  554. var ajv = new Ajv({ format: 'full' });
  555. var schema = { format: 'date' };
  556. var validDate = '2016-02-29';
  557. var invalidDate = '2017-02-29';
  558. ajv.validate(schema, validDate) .should.equal(true);
  559. ajv.validate(schema, invalidDate) .should.equal(false);
  560. });
  561. });
  562. describe('property __proto__ should be removed with removeAdditional option, issue #743', function() {
  563. it('should remove additional properties', function() {
  564. var ajv = new Ajv({removeAdditional: true});
  565. var schema = {
  566. properties: {
  567. obj: {
  568. additionalProperties: false,
  569. properties: {
  570. a: { type: 'string' },
  571. b: { type: 'string' },
  572. c: { type: 'string' },
  573. d: { type: 'string' },
  574. e: { type: 'string' },
  575. f: { type: 'string' },
  576. g: { type: 'string' },
  577. h: { type: 'string' },
  578. i: { type: 'string' }
  579. }
  580. }
  581. }
  582. };
  583. var obj= Object.create(null);
  584. obj.__proto__ = null; // should be removed
  585. obj.additional = 'will be removed';
  586. obj.a = 'valid';
  587. obj.b = 'valid';
  588. var data = {obj: obj};
  589. ajv.validate(schema, data) .should.equal(true);
  590. Object.keys(data.obj) .should.eql(['a', 'b']);
  591. });
  592. });
  593. describe('issue #768, fix passContext in recursive $ref', function() {
  594. var ajv, contexts;
  595. beforeEach(function() {
  596. contexts = [];
  597. });
  598. describe('passContext = true', function() {
  599. it('should pass this value as context to custom keyword validation function', function() {
  600. var validate = getValidate(true);
  601. var self = {};
  602. validate.call(self, { bar: 'a', baz: { bar: 'b' } });
  603. contexts .should.have.length(2);
  604. contexts.forEach(function(ctx) {
  605. ctx .should.equal(self);
  606. });
  607. });
  608. });
  609. describe('passContext = false', function() {
  610. it('should pass ajv instance as context to custom keyword validation function', function() {
  611. var validate = getValidate(false);
  612. validate({ bar: 'a', baz: { bar: 'b' } });
  613. contexts .should.have.length(2);
  614. contexts.forEach(function(ctx) {
  615. ctx .should.equal(ajv);
  616. });
  617. });
  618. });
  619. describe('ref is fragment and passContext = true', function() {
  620. it('should pass this value as context to custom keyword validation function', function() {
  621. var validate = getValidateFragments(true);
  622. var self = {};
  623. validate.call(self, { baz: { corge: 'a', quux: { baz: { corge: 'b' } } } });
  624. contexts .should.have.length(2);
  625. contexts.forEach(function(ctx) {
  626. ctx .should.equal(self);
  627. });
  628. });
  629. });
  630. describe('ref is fragment and passContext = false', function() {
  631. it('should pass ajv instance as context to custom keyword validation function', function() {
  632. var validate = getValidateFragments(false);
  633. validate({ baz: { corge: 'a', quux: { baz: { corge: 'b' } } } });
  634. contexts .should.have.length(2);
  635. contexts.forEach(function(ctx) {
  636. ctx .should.equal(ajv);
  637. });
  638. });
  639. });
  640. function getValidate(passContext) {
  641. ajv = new Ajv({ passContext: passContext });
  642. ajv.addKeyword('testValidate', { validate: storeContext });
  643. var schema = {
  644. "$id" : "foo",
  645. "type": "object",
  646. "required": ["bar"],
  647. "properties": {
  648. "bar": { "testValidate": true },
  649. "baz": {
  650. "$ref": "foo"
  651. }
  652. }
  653. };
  654. return ajv.compile(schema);
  655. }
  656. function getValidateFragments(passContext) {
  657. ajv = new Ajv({ passContext: passContext });
  658. ajv.addKeyword('testValidate', { validate: storeContext });
  659. ajv.addSchema({
  660. "$id" : "foo",
  661. "definitions": {
  662. "bar": {
  663. "properties": {
  664. "baz": {
  665. "$ref": "boo"
  666. }
  667. }
  668. }
  669. }
  670. });
  671. ajv.addSchema({
  672. "$id" : "boo",
  673. "type": "object",
  674. "required": ["corge"],
  675. "properties": {
  676. "quux": { "$ref": "foo#/definitions/bar" },
  677. "corge": { "testValidate": true }
  678. }
  679. });
  680. return ajv.compile({ "$ref": "foo#/definitions/bar" });
  681. }
  682. function storeContext() {
  683. contexts.push(this);
  684. return true;
  685. }
  686. });