dereference.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. import { encodePointer } from './pointer.js';
  2. export const schemaKeyword = {
  3. additionalItems: true,
  4. unevaluatedItems: true,
  5. items: true,
  6. contains: true,
  7. additionalProperties: true,
  8. unevaluatedProperties: true,
  9. propertyNames: true,
  10. not: true,
  11. if: true,
  12. then: true,
  13. else: true
  14. };
  15. export const schemaArrayKeyword = {
  16. prefixItems: true,
  17. items: true,
  18. allOf: true,
  19. anyOf: true,
  20. oneOf: true
  21. };
  22. export const schemaMapKeyword = {
  23. $defs: true,
  24. definitions: true,
  25. properties: true,
  26. patternProperties: true,
  27. dependentSchemas: true
  28. };
  29. export const ignoredKeyword = {
  30. id: true,
  31. $id: true,
  32. $ref: true,
  33. $schema: true,
  34. $anchor: true,
  35. $vocabulary: true,
  36. $comment: true,
  37. default: true,
  38. enum: true,
  39. const: true,
  40. required: true,
  41. type: true,
  42. maximum: true,
  43. minimum: true,
  44. exclusiveMaximum: true,
  45. exclusiveMinimum: true,
  46. multipleOf: true,
  47. maxLength: true,
  48. minLength: true,
  49. pattern: true,
  50. format: true,
  51. maxItems: true,
  52. minItems: true,
  53. uniqueItems: true,
  54. maxProperties: true,
  55. minProperties: true
  56. };
  57. export let initialBaseURI = typeof self !== 'undefined' &&
  58. self.location &&
  59. self.location.origin !== 'null'
  60. ?
  61. new URL(self.location.origin + self.location.pathname + location.search)
  62. : new URL('https://github.com/cfworker');
  63. export function dereference(schema, lookup = Object.create(null), baseURI = initialBaseURI, basePointer = '') {
  64. if (schema && typeof schema === 'object' && !Array.isArray(schema)) {
  65. const id = schema.$id || schema.id;
  66. if (id) {
  67. const url = new URL(id, baseURI.href);
  68. if (url.hash.length > 1) {
  69. lookup[url.href] = schema;
  70. }
  71. else {
  72. url.hash = '';
  73. if (basePointer === '') {
  74. baseURI = url;
  75. }
  76. else {
  77. dereference(schema, lookup, baseURI);
  78. }
  79. }
  80. }
  81. }
  82. else if (schema !== true && schema !== false) {
  83. return lookup;
  84. }
  85. const schemaURI = baseURI.href + (basePointer ? '#' + basePointer : '');
  86. if (lookup[schemaURI] !== undefined) {
  87. throw new Error(`Duplicate schema URI "${schemaURI}".`);
  88. }
  89. lookup[schemaURI] = schema;
  90. if (schema === true || schema === false) {
  91. return lookup;
  92. }
  93. if (schema.__absolute_uri__ === undefined) {
  94. Object.defineProperty(schema, '__absolute_uri__', {
  95. enumerable: false,
  96. value: schemaURI
  97. });
  98. }
  99. if (schema.$ref && schema.__absolute_ref__ === undefined) {
  100. const url = new URL(schema.$ref, baseURI.href);
  101. url.hash = url.hash;
  102. Object.defineProperty(schema, '__absolute_ref__', {
  103. enumerable: false,
  104. value: url.href
  105. });
  106. }
  107. if (schema.$recursiveRef && schema.__absolute_recursive_ref__ === undefined) {
  108. const url = new URL(schema.$recursiveRef, baseURI.href);
  109. url.hash = url.hash;
  110. Object.defineProperty(schema, '__absolute_recursive_ref__', {
  111. enumerable: false,
  112. value: url.href
  113. });
  114. }
  115. if (schema.$anchor) {
  116. const url = new URL('#' + schema.$anchor, baseURI.href);
  117. lookup[url.href] = schema;
  118. }
  119. for (let key in schema) {
  120. if (ignoredKeyword[key]) {
  121. continue;
  122. }
  123. const keyBase = `${basePointer}/${encodePointer(key)}`;
  124. const subSchema = schema[key];
  125. if (Array.isArray(subSchema)) {
  126. if (schemaArrayKeyword[key]) {
  127. const length = subSchema.length;
  128. for (let i = 0; i < length; i++) {
  129. dereference(subSchema[i], lookup, baseURI, `${keyBase}/${i}`);
  130. }
  131. }
  132. }
  133. else if (schemaMapKeyword[key]) {
  134. for (let subKey in subSchema) {
  135. dereference(subSchema[subKey], lookup, baseURI, `${keyBase}/${encodePointer(subKey)}`);
  136. }
  137. }
  138. else {
  139. dereference(subSchema, lookup, baseURI, keyBase);
  140. }
  141. }
  142. return lookup;
  143. }