resolve.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.getSchemaRefs = exports.resolveUrl = exports.normalizeId = exports._getFullPath = exports.getFullPath = exports.inlineRef = void 0;
  4. const util_1 = require("./util");
  5. const equal = require("fast-deep-equal");
  6. const traverse = require("json-schema-traverse");
  7. const URI = require("uri-js");
  8. // TODO refactor to use keyword definitions
  9. const SIMPLE_INLINED = new Set([
  10. "type",
  11. "format",
  12. "pattern",
  13. "maxLength",
  14. "minLength",
  15. "maxProperties",
  16. "minProperties",
  17. "maxItems",
  18. "minItems",
  19. "maximum",
  20. "minimum",
  21. "uniqueItems",
  22. "multipleOf",
  23. "required",
  24. "enum",
  25. "const",
  26. ]);
  27. function inlineRef(schema, limit = true) {
  28. if (typeof schema == "boolean")
  29. return true;
  30. if (limit === true)
  31. return !hasRef(schema);
  32. if (!limit)
  33. return false;
  34. return countKeys(schema) <= limit;
  35. }
  36. exports.inlineRef = inlineRef;
  37. const REF_KEYWORDS = new Set([
  38. "$ref",
  39. "$recursiveRef",
  40. "$recursiveAnchor",
  41. "$dynamicRef",
  42. "$dynamicAnchor",
  43. ]);
  44. function hasRef(schema) {
  45. for (const key in schema) {
  46. if (REF_KEYWORDS.has(key))
  47. return true;
  48. const sch = schema[key];
  49. if (Array.isArray(sch) && sch.some(hasRef))
  50. return true;
  51. if (typeof sch == "object" && hasRef(sch))
  52. return true;
  53. }
  54. return false;
  55. }
  56. function countKeys(schema) {
  57. let count = 0;
  58. for (const key in schema) {
  59. if (key === "$ref")
  60. return Infinity;
  61. count++;
  62. if (SIMPLE_INLINED.has(key))
  63. continue;
  64. if (typeof schema[key] == "object") {
  65. util_1.eachItem(schema[key], (sch) => (count += countKeys(sch)));
  66. }
  67. if (count === Infinity)
  68. return Infinity;
  69. }
  70. return count;
  71. }
  72. function getFullPath(id = "", normalize) {
  73. if (normalize !== false)
  74. id = normalizeId(id);
  75. const p = URI.parse(id);
  76. return _getFullPath(p);
  77. }
  78. exports.getFullPath = getFullPath;
  79. function _getFullPath(p) {
  80. return URI.serialize(p).split("#")[0] + "#";
  81. }
  82. exports._getFullPath = _getFullPath;
  83. const TRAILING_SLASH_HASH = /#\/?$/;
  84. function normalizeId(id) {
  85. return id ? id.replace(TRAILING_SLASH_HASH, "") : "";
  86. }
  87. exports.normalizeId = normalizeId;
  88. function resolveUrl(baseId, id) {
  89. id = normalizeId(id);
  90. return URI.resolve(baseId, id);
  91. }
  92. exports.resolveUrl = resolveUrl;
  93. const ANCHOR = /^[a-z_][-a-z0-9._]*$/i;
  94. function getSchemaRefs(schema) {
  95. if (typeof schema == "boolean")
  96. return {};
  97. const schemaId = normalizeId(schema.$id);
  98. const baseIds = { "": schemaId };
  99. const pathPrefix = getFullPath(schemaId, false);
  100. const localRefs = {};
  101. const schemaRefs = new Set();
  102. traverse(schema, { allKeys: true }, (sch, jsonPtr, _, parentJsonPtr) => {
  103. if (parentJsonPtr === undefined)
  104. return;
  105. const fullPath = pathPrefix + jsonPtr;
  106. let baseId = baseIds[parentJsonPtr];
  107. if (typeof sch.$id == "string")
  108. baseId = addRef.call(this, sch.$id);
  109. addAnchor.call(this, sch.$anchor);
  110. addAnchor.call(this, sch.$dynamicAnchor);
  111. baseIds[jsonPtr] = baseId;
  112. function addRef(ref) {
  113. ref = normalizeId(baseId ? URI.resolve(baseId, ref) : ref);
  114. if (schemaRefs.has(ref))
  115. throw ambiguos(ref);
  116. schemaRefs.add(ref);
  117. let schOrRef = this.refs[ref];
  118. if (typeof schOrRef == "string")
  119. schOrRef = this.refs[schOrRef];
  120. if (typeof schOrRef == "object") {
  121. checkAmbiguosRef(sch, schOrRef.schema, ref);
  122. }
  123. else if (ref !== normalizeId(fullPath)) {
  124. if (ref[0] === "#") {
  125. checkAmbiguosRef(sch, localRefs[ref], ref);
  126. localRefs[ref] = sch;
  127. }
  128. else {
  129. this.refs[ref] = fullPath;
  130. }
  131. }
  132. return ref;
  133. }
  134. function addAnchor(anchor) {
  135. if (typeof anchor == "string") {
  136. if (!ANCHOR.test(anchor))
  137. throw new Error(`invalid anchor "${anchor}"`);
  138. addRef.call(this, `#${anchor}`);
  139. }
  140. }
  141. });
  142. return localRefs;
  143. function checkAmbiguosRef(sch1, sch2, ref) {
  144. if (sch2 !== undefined && !equal(sch1, sch2))
  145. throw ambiguos(ref);
  146. }
  147. function ambiguos(ref) {
  148. return new Error(`reference "${ref}" resolves to more than one schema`);
  149. }
  150. }
  151. exports.getSchemaRefs = getSchemaRefs;
  152. //# sourceMappingURL=resolve.js.map