scan.js 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. "use strict";
  2. var helpers = require('./helpers');
  3. module.exports.SchemaScanResult = SchemaScanResult;
  4. function SchemaScanResult(found, ref){
  5. this.id = found;
  6. this.ref = ref;
  7. }
  8. /**
  9. * Adds a schema with a certain urn to the Validator instance.
  10. * @param string uri
  11. * @param object schema
  12. * @return {Object}
  13. */
  14. module.exports.scan = function scan(base, schema){
  15. function scanSchema(baseuri, schema){
  16. if(!schema || typeof schema!='object') return;
  17. // Mark all referenced schemas so we can tell later which schemas are referred to, but never defined
  18. if(schema.$ref){
  19. let resolvedUri = helpers.resolveUrl(baseuri,schema.$ref);
  20. ref[resolvedUri] = ref[resolvedUri] ? ref[resolvedUri]+1 : 0;
  21. return;
  22. }
  23. var id = schema.$id || schema.id;
  24. let resolvedBase = helpers.resolveUrl(baseuri,id);
  25. var ourBase = id ? resolvedBase : baseuri;
  26. if (ourBase) {
  27. // If there's no fragment, append an empty one
  28. if(ourBase.indexOf('#')<0) ourBase += '#';
  29. if(found[ourBase]){
  30. if(!helpers.deepCompareStrict(found[ourBase], schema)){
  31. throw new Error('Schema <'+ourBase+'> already exists with different definition');
  32. }
  33. return found[ourBase];
  34. }
  35. found[ourBase] = schema;
  36. // strip trailing fragment
  37. if(ourBase[ourBase.length-1]=='#'){
  38. found[ourBase.substring(0, ourBase.length-1)] = schema;
  39. }
  40. }
  41. scanArray(ourBase+'/items', (Array.isArray(schema.items)?schema.items:[schema.items]));
  42. scanArray(ourBase+'/extends', (Array.isArray(schema.extends)?schema.extends:[schema.extends]));
  43. scanSchema(ourBase+'/additionalItems', schema.additionalItems);
  44. scanObject(ourBase+'/properties', schema.properties);
  45. scanSchema(ourBase+'/additionalProperties', schema.additionalProperties);
  46. scanObject(ourBase+'/definitions', schema.definitions);
  47. scanObject(ourBase+'/patternProperties', schema.patternProperties);
  48. scanObject(ourBase+'/dependencies', schema.dependencies);
  49. scanArray(ourBase+'/disallow', schema.disallow);
  50. scanArray(ourBase+'/allOf', schema.allOf);
  51. scanArray(ourBase+'/anyOf', schema.anyOf);
  52. scanArray(ourBase+'/oneOf', schema.oneOf);
  53. scanSchema(ourBase+'/not', schema.not);
  54. }
  55. function scanArray(baseuri, schemas){
  56. if(!Array.isArray(schemas)) return;
  57. for(var i=0; i<schemas.length; i++){
  58. scanSchema(baseuri+'/'+i, schemas[i]);
  59. }
  60. }
  61. function scanObject(baseuri, schemas){
  62. if(!schemas || typeof schemas!='object') return;
  63. for(var p in schemas){
  64. scanSchema(baseuri+'/'+p, schemas[p]);
  65. }
  66. }
  67. var found = {};
  68. var ref = {};
  69. scanSchema(base, schema);
  70. return new SchemaScanResult(found, ref);
  71. };