refs.js 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. "use strict";
  2. const { ono } = require("@jsdevtools/ono");
  3. const $Ref = require("./ref");
  4. const url = require("./util/url");
  5. module.exports = $Refs;
  6. /**
  7. * This class is a map of JSON references and their resolved values.
  8. */
  9. function $Refs () {
  10. /**
  11. * Indicates whether the schema contains any circular references.
  12. *
  13. * @type {boolean}
  14. */
  15. this.circular = false;
  16. /**
  17. * A map of paths/urls to {@link $Ref} objects
  18. *
  19. * @type {object}
  20. * @protected
  21. */
  22. this._$refs = {};
  23. /**
  24. * The {@link $Ref} object that is the root of the JSON schema.
  25. *
  26. * @type {$Ref}
  27. * @protected
  28. */
  29. this._root$Ref = null;
  30. }
  31. /**
  32. * Returns the paths of all the files/URLs that are referenced by the JSON schema,
  33. * including the schema itself.
  34. *
  35. * @param {...string|string[]} [types] - Only return paths of the given types ("file", "http", etc.)
  36. * @returns {string[]}
  37. */
  38. $Refs.prototype.paths = function (types) { // eslint-disable-line no-unused-vars
  39. let paths = getPaths(this._$refs, arguments);
  40. return paths.map((path) => {
  41. return path.decoded;
  42. });
  43. };
  44. /**
  45. * Returns the map of JSON references and their resolved values.
  46. *
  47. * @param {...string|string[]} [types] - Only return references of the given types ("file", "http", etc.)
  48. * @returns {object}
  49. */
  50. $Refs.prototype.values = function (types) { // eslint-disable-line no-unused-vars
  51. let $refs = this._$refs;
  52. let paths = getPaths($refs, arguments);
  53. return paths.reduce((obj, path) => {
  54. obj[path.decoded] = $refs[path.encoded].value;
  55. return obj;
  56. }, {});
  57. };
  58. /**
  59. * Returns a POJO (plain old JavaScript object) for serialization as JSON.
  60. *
  61. * @returns {object}
  62. */
  63. $Refs.prototype.toJSON = $Refs.prototype.values;
  64. /**
  65. * Determines whether the given JSON reference exists.
  66. *
  67. * @param {string} path - The path being resolved, optionally with a JSON pointer in the hash
  68. * @param {$RefParserOptions} [options]
  69. * @returns {boolean}
  70. */
  71. $Refs.prototype.exists = function (path, options) {
  72. try {
  73. this._resolve(path, "", options);
  74. return true;
  75. }
  76. catch (e) {
  77. return false;
  78. }
  79. };
  80. /**
  81. * Resolves the given JSON reference and returns the resolved value.
  82. *
  83. * @param {string} path - The path being resolved, with a JSON pointer in the hash
  84. * @param {$RefParserOptions} [options]
  85. * @returns {*} - Returns the resolved value
  86. */
  87. $Refs.prototype.get = function (path, options) {
  88. return this._resolve(path, "", options).value;
  89. };
  90. /**
  91. * Sets the value of a nested property within this {@link $Ref#value}.
  92. * If the property, or any of its parents don't exist, they will be created.
  93. *
  94. * @param {string} path - The path of the property to set, optionally with a JSON pointer in the hash
  95. * @param {*} value - The value to assign
  96. */
  97. $Refs.prototype.set = function (path, value) {
  98. let absPath = url.resolve(this._root$Ref.path, path);
  99. let withoutHash = url.stripHash(absPath);
  100. let $ref = this._$refs[withoutHash];
  101. if (!$ref) {
  102. throw ono(`Error resolving $ref pointer "${path}". \n"${withoutHash}" not found.`);
  103. }
  104. $ref.set(absPath, value);
  105. };
  106. /**
  107. * Creates a new {@link $Ref} object and adds it to this {@link $Refs} object.
  108. *
  109. * @param {string} path - The file path or URL of the referenced file
  110. */
  111. $Refs.prototype._add = function (path) {
  112. let withoutHash = url.stripHash(path);
  113. let $ref = new $Ref();
  114. $ref.path = withoutHash;
  115. $ref.$refs = this;
  116. this._$refs[withoutHash] = $ref;
  117. this._root$Ref = this._root$Ref || $ref;
  118. return $ref;
  119. };
  120. /**
  121. * Resolves the given JSON reference.
  122. *
  123. * @param {string} path - The path being resolved, optionally with a JSON pointer in the hash
  124. * @param {string} pathFromRoot - The path of `obj` from the schema root
  125. * @param {$RefParserOptions} [options]
  126. * @returns {Pointer}
  127. * @protected
  128. */
  129. $Refs.prototype._resolve = function (path, pathFromRoot, options) {
  130. let absPath = url.resolve(this._root$Ref.path, path);
  131. let withoutHash = url.stripHash(absPath);
  132. let $ref = this._$refs[withoutHash];
  133. if (!$ref) {
  134. throw ono(`Error resolving $ref pointer "${path}". \n"${withoutHash}" not found.`);
  135. }
  136. return $ref.resolve(absPath, options, path, pathFromRoot);
  137. };
  138. /**
  139. * Returns the specified {@link $Ref} object, or undefined.
  140. *
  141. * @param {string} path - The path being resolved, optionally with a JSON pointer in the hash
  142. * @returns {$Ref|undefined}
  143. * @protected
  144. */
  145. $Refs.prototype._get$Ref = function (path) {
  146. path = url.resolve(this._root$Ref.path, path);
  147. let withoutHash = url.stripHash(path);
  148. return this._$refs[withoutHash];
  149. };
  150. /**
  151. * Returns the encoded and decoded paths keys of the given object.
  152. *
  153. * @param {object} $refs - The object whose keys are URL-encoded paths
  154. * @param {...string|string[]} [types] - Only return paths of the given types ("file", "http", etc.)
  155. * @returns {object[]}
  156. */
  157. function getPaths ($refs, types) {
  158. let paths = Object.keys($refs);
  159. // Filter the paths by type
  160. types = Array.isArray(types[0]) ? types[0] : Array.prototype.slice.call(types);
  161. if (types.length > 0 && types[0]) {
  162. paths = paths.filter((key) => {
  163. return types.indexOf($refs[key].pathType) !== -1;
  164. });
  165. }
  166. // Decode local filesystem paths
  167. return paths.map((path) => {
  168. return {
  169. encoded: path,
  170. decoded: $refs[path].pathType === "file" ? url.toFileSystemPath(path, true) : path
  171. };
  172. });
  173. }