|
1 | 1 | import { isLocalRef, pointerToPath } from '@stoplight/json'; |
2 | 2 | import { Tree, TreeListParentNode, TreeState } from '@stoplight/tree-list'; |
3 | | -import { JsonPath } from '@stoplight/types'; |
| 3 | +import { JsonPath, Optional } from '@stoplight/types'; |
4 | 4 | import { JSONSchema4 } from 'json-schema'; |
5 | | -import { get as _get, isEqual as _isEqual } from 'lodash'; |
| 5 | +import { get as _get, isEqual as _isEqual, isObject as _isObject } from 'lodash'; |
6 | 6 | import { isRefNode } from '../utils/guards'; |
7 | 7 | import { getNodeMetadata, metadataStore } from './metadata'; |
8 | 8 | import { populateTree } from './populateTree'; |
9 | 9 |
|
| 10 | +export type SchemaTreeRefDereferenceFn = (path: JsonPath, schema: JSONSchema4) => Optional<JSONSchema4>; |
| 11 | + |
10 | 12 | export type SchemaTreeOptions = { |
11 | 13 | expandedDepth: number; |
12 | 14 | mergeAllOf: boolean; |
| 15 | + resolveRef: Optional<SchemaTreeRefDereferenceFn>; |
13 | 16 | }; |
14 | 17 |
|
15 | 18 | export { TreeState as SchemaTreeState }; |
16 | 19 |
|
17 | 20 | export class SchemaTree extends Tree { |
18 | 21 | public expandedDepth: number; |
19 | 22 | public mergeAllOf: boolean; |
| 23 | + protected resolveRef: Optional<SchemaTreeRefDereferenceFn>; |
20 | 24 |
|
21 | 25 | constructor(public schema: JSONSchema4, public state: TreeState, opts: SchemaTreeOptions) { |
22 | 26 | super(); |
23 | 27 |
|
24 | 28 | this.expandedDepth = opts.expandedDepth; |
25 | 29 | this.mergeAllOf = opts.mergeAllOf; |
| 30 | + this.resolveRef = opts.resolveRef; |
26 | 31 | } |
27 | 32 |
|
28 | 33 | protected readonly visited = new WeakSet(); |
@@ -78,7 +83,11 @@ export class SchemaTree extends Tree { |
78 | 83 | const { path, schemaNode, schema } = metadata; |
79 | 84 | if (isRefNode(schemaNode)) { |
80 | 85 | const refPath = pointerToPath(schemaNode.$ref); |
81 | | - const schemaFragment = _get(this.schema, refPath); |
| 86 | + const schemaFragment = this.resolveRef ? this.resolveRef(refPath, this.schema) : _get(this.schema, refPath); |
| 87 | + if (!_isObject(schemaFragment)) { |
| 88 | + throw new ReferenceError(`Could not dereference ${refPath.join('.')}`); |
| 89 | + } |
| 90 | + |
82 | 91 | this.populateTreeFragment(node, schemaFragment, path); |
83 | 92 | metadata.schema = schemaFragment; |
84 | 93 | } else { |
|
0 commit comments