resolve.js 4.9 KB

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