File size: 11,412 Bytes
23ac194
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
# json-schema-ref-resolver

[![CI](https://github.com/fastify/json-schema-ref-resolver/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/fastify/json-schema-ref-resolver/actions/workflows/ci.yml)
[![npm version](https://img.shields.io/npm/v/json-schema-ref-resolver)](https://www.npmjs.com/package/json-schema-ref-resolver)
[![neostandard javascript style](https://img.shields.io/badge/code_style-neostandard-brightgreen?style=flat)](https://github.com/neostandard/neostandard)

__json-schema-ref-resolver__ is a javascript library that resolves references in [JSON schemas](https://json-schema.org/draft/2020-12/json-schema-core#name-introduction).

- [Installation](#installation)
- [Usage](#usage)
- [API](#api)
  - [RefResolver([options])](#refresolveroptions)
  - [addSchema(schema, [schemaId])](#addschemaschema-schemaid)
  - [getSchema(schemaId, [jsonPointer])](#getschemaschemaid-jsonpointer)
  - [getSchemaRefs(schemaId)](#getschemarefsschemaid)
  - [getSchemaDependencies(schemaId)](#getschemadependenciesschemaid)
  - [derefSchema(schemaId)](#derefschemaschemaid)
  - [getDerefSchema(schemaId, [jsonPointer])](#getderefschemaschemaid-jsonpointer)
- [Caveats](#caveats)

<a name="installation"></a>

## Installation

```bash
npm install json-schema-ref-resolver
```

<a name="usage"></a>

## Usage

```javascript
const assert = require('node:assert')
const { RefResolver } = require('json-schema-ref-resolver')

const sourceSchema = {
  $id: 'sourceSchema',
  type: 'object',
  properties: {
    foo: {
      $ref: 'targetSchema#/definitions/bar'
    }
  }
}

const targetSchema = {
  $id: 'targetSchema',
  definitions: {
    bar: {
      type: 'string'
    }
  }
}

const refResolver = new RefResolver()

refResolver.addSchema(sourceSchema)
refResolver.addSchema(targetSchema)

const derefSourceSchema = refResolver.getDerefSchema('sourceSchema')
assert.deepStrictEqual(derefSourceSchema, {
  $id: 'sourceSchema',
  type: 'object',
  properties: {
    foo: {
      type: 'string'
    }
  }
})
```

<a name="api"></a>

## API

<a name="constructor"></a>

#### RefResolver([options])

- __allowEqualDuplicates__ - if set to `false`, an error will be thrown if a schema with the same `$id` is added to the resolver. If set to `true`, the error will be thrown only if the schemas are not equal. Default: `true`.

- __insertRefSymbol__ - if set to `true` resolver inserts a `Symbol.for('json-schema-ref')` instead of the `$ref` property when dereferencing a schema. Default `false`.

- __cloneSchemaWithoutRefs__ - if set to `false` resolver would not clone a schema if it does not have references. That allows to significantly improve performance when dereferencing a schema. If you want to modify a schema after dereferencing, set this option to `true`. Default: `false`.

<a name="add-schema"></a>

#### addSchema(schema, [schemaId])

Adds a json schema to the resolver. If the schema has an `$id` property, it will be used as the schema id. Otherwise, the `schemaId` argument will be used as the schema id. During the addition of the schema, ref resolver will find and add all nested schemas and references.

- `schema` __\<object\>__ - json schema to add to the resolver.
- `schemaId` __\<string\>__ - schema id to use. Will be used only if the schema does not have an `$id` property.

<a name="get-schema"></a>

#### getSchema(schemaId, [jsonPointer])

Returns a json schema by its id. If the `jsonPointer` argument is provided, ref resolver will return the schema at the specified json pointer location.

If shema with the specified id is not found, an error will be thrown. If the `jsonPointer` argument is provided and the schema at the specified location is not found, getSchema will return `null`.

- `schemaId` __\<string\>__ - schema id of the schema to return.
- `jsonPointer` __\<string\>__ - json pointer to the schema location.
- __Returns__ - json schema or `null` if the schema at the specified location is not found.

_Example:_

```javascript
const assert = require('node:assert')
const { RefResolver } = require('json-schema-ref-resolver')

const schema = {
  $id: 'schema',
  type: 'object',
  properties: {
    foo: { type: 'string' }
  }
}

const refResolver = new RefResolver()
refResolver.addSchema(schema)

const rootSchema = refResolver.getSchema(schema.$id)
assert.deepStrictEqual(rootSchema, schema)

const subSchema = refResolver.getSchema(schema.$id, '#/properties/foo')
assert.deepStrictEqual(subSchema, { type: 'string' })
```

`getSchema` can also be used to get a schema by its [json schema anchor](https://json-schema.org/draft/2020-12/json-schema-core#section-8.2.2). To get schema by schema anchor, the `schemaId` argument must be set to the `$id` of the schema that contains the anchor, and the `jsonPointer` argument must be set to the anchor.

_Example:_

```javascript
const assert = require('node:assert')
const { RefResolver } = require('json-schema-ref-resolver')

const schema = {
  $id: 'schema',
  definitions: {
    bar: {
      $id: '#bar',
      type: 'string'
    }
  }
}

const refResolver = new RefResolver()
refResolver.addSchema(schema)

const anchorSchema = refResolver.getSchema(schema.$id, '#bar')
assert.deepStrictEqual(subSchema, {
  $id: '#bar',
  type: 'string'
})
```

<a name="get-schema-refs"></a>

#### getSchemaRefs(schemaId)

Returns all references found in the schema during the addition of the schema to the resolver. If schema with the specified id is not found, an error will be thrown.

- `schemaId` __\<string\>__ - schema id of the schema to return references for.
- __Returns__ - array of objects with the following properties:
  - `schemaId` __\<string\>__ - schema id of the reference.
  - `jsonPointer` __\<string\>__ - json pointer of the reference.

If a reference does not have a schema id part, the schema id of the schema that contains the reference is used as the schema id of the reference.

_Example:_

```javascript
const assert = require('node:assert')

const { RefResolver } = require('json-schema-ref-resolver')

const sourceSchema = {
  $id: 'sourceSchema',
  type: 'object',
  properties: {
    foo: {
      $ref: 'targetSchema#/definitions/bar'
    },
    baz: {
      $ref: 'targetSchema#/definitions/qux'
    }
  }
}

const refResolver = new RefResolver()
refResolver.addSchema(sourceSchema)

const refs = refResolver.getSchemaRefs('sourceSchema')
assert.deepStrictEqual(refs, [
  {
    schemaId: 'targetSchema',
    jsonPointer: '#/definitions/bar'
  },
  {
    schemaId: 'targetSchema',
    jsonPointer: '#/definitions/qux'
  }
])
```

<a name="get-schema-dependencies"></a>

#### getSchemaDependencies(schemaId)

Returns all dependencies including nested dependencies found in the schema during the addition of the schema to the resolver. If schema with the specified id is not found, an error will be thrown.

- `schemaId` __\<string\>__ - schema id of the schema to return dependencies for.
- __Returns__ - an object with all found dependencies. The object keys are schema ids and the values are schema dependencies.

_Example:_

```javascript
const assert = require('node:assert')

const { RefResolver } = require('json-schema-ref-resolver')

const targetSchema1 = {
  $id: 'targetSchema1',
  definitions: {
    bar: { type: 'string' }
  }
}

const targetSchema2 = {
  $id: 'targetSchema2',
  type: 'object',
  properties: {
    qux: { $ref: 'targetSchema1' }
  }
}

const sourceSchema = {
  $id: 'sourceSchema',
  type: 'object',
  properties: {
    foo: { $ref: 'targetSchema2' }
  }
}

const refResolver = new RefResolver()

refResolver.addSchema(sourceSchema)
refResolver.addSchema(targetSchema1)
refResolver.addSchema(targetSchema2)

const dependencies = refResolver.getSchemaDependencies('sourceSchema')
assert.deepStrictEqual(dependencies, { targetSchema1, targetSchema2 })
```

<a name="deref-schema"></a>

#### derefSchema(schemaId)

Dereferences all references in the schema. All dependencies will also be dereferenced. If schema with the specified id is not found, an error will be thrown.

- `schemaId` __\<string\>__ - schema id of the schema to dereference.

__If a json schema has circular references or circular cross-references, dereferenced schema will have js circular references. Be careful when traversing the dereferenced schema.__

_Example_

```javascript
const assert = require('node:assert')
const { RefResolver } = require('json-schema-ref-resolver')

const sourceSchema = {
  $id: 'sourceSchema',
  type: 'object',
  properties: {
    foo: {
      $ref: 'targetSchema#/definitions/bar'
    }
  }
}

const targetSchema = {
  $id: 'targetSchema',
  definitions: {
    bar: {
      type: 'string'
    }
  }
}

const refResolver = new RefResolver()

refResolver.addSchema(sourceSchema)
refResolver.addSchema(targetSchema)

refResolver.derefSchema('sourceSchema')
const derefSourceSchema = refResolver.getDerefSchema('sourceSchema')

assert.deepStrictEqual(derefSourceSchema, {
  $id: 'sourceSchema',
  type: 'object',
  properties: {
    foo: {
      type: 'string'
    }
  }
})
```

<a name="get-deref-schema"></a>

#### getDerefSchema(schemaId, [jsonPointer])

Returns a dereferenced schema by schema id and json pointer. If schema with the specified id is not found, an error will be thrown. If the `jsonPointer` argument is provided, ref resolver will return the schema at the specified json pointer location. If the `jsonPointer` argument is provided and the schema at the specified location is not found, getDerefSchema will return `null`.

If schema was not dereferenced before, it will be dereferenced during the call to `getDerefSchema`.

- `schemaId` __\<string\>__ - schema id of the schema to return.
- `jsonPointer` __\<string\>__ - json pointer to the schema location.
- __Returns__ - dereferenced json schema or `null` if the schema at the specified location is not found.

_Example:_

```javascript
const assert = require('node:assert')
const { RefResolver } = require('json-schema-ref-resolver')

const sourceSchema = {
  $id: 'sourceSchema',
  type: 'object',
  properties: {
    foo: {
      $ref: 'targetSchema#/definitions/bar'
    }
  }
}

const targetSchema = {
  $id: 'targetSchema',
  definitions: {
    bar: {
      type: 'string'
    }
  }
}

const refResolver = new RefResolver()

refResolver.addSchema(sourceSchema)
refResolver.addSchema(targetSchema)

const derefSourceSchema = refResolver.getDerefSchema('sourceSchema')
assert.deepStrictEqual(derefSourceSchema, {
  $id: 'sourceSchema',
  type: 'object',
  properties: {
    foo: {
      type: 'string'
    }
  }
})
```

#### Caveats

- If a reference schema and a source schema have a key with the same name and different values, an error will be thrown during a call to `derefSchema` or `getDerefSchema`.

_Example:_

```javascript
const assert = require('node:assert')
const { RefResolver } = require('json-schema-ref-resolver')

const targetSchema = {
  $id: 'targetSchema',
  definitions: {
    bar: {
      type: 'object',
      properties: {
        foo: { type: 'string' }
      }
    }
  }
}

const sourceSchema = {
  $id: 'sourceSchema',
  type: 'object',
  $ref: 'targetSchema#/definitions/bar'
  properties: {
    foo: { type: 'number' }
  }
}

const refResolver = new RefResolver()
refResolver.addSchema(targetSchema)
refResolver.addSchema(sourceSchema)

refResolver.derefSchema('sourceSchema') // Throws an error
```

## License

Licensed under [MIT](./LICENSE).