@scalar/openapi-parser 0.8.10 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/README.md +14 -0
- package/dist/utils/dereference.d.ts +3 -2
- package/dist/utils/dereference.d.ts.map +1 -1
- package/dist/utils/resolveReferences.d.ts +7 -1
- package/dist/utils/resolveReferences.d.ts.map +1 -1
- package/dist/utils/resolveReferences.js +39 -42
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# @scalar/openapi-parser
|
|
2
2
|
|
|
3
|
+
## 0.10.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- fbef0c3: fix(openapi-parser): improve performance
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- fbef0c3: fix: doesn’t validate files with external references
|
|
12
|
+
|
|
13
|
+
## 0.9.0
|
|
14
|
+
|
|
15
|
+
### Minor Changes
|
|
16
|
+
|
|
17
|
+
- 6fef2f3: feat(openapi-parser): support `onDereference` option on `dereference`
|
|
18
|
+
|
|
3
19
|
## 0.8.10
|
|
4
20
|
|
|
5
21
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -63,6 +63,20 @@ const specification = `{
|
|
|
63
63
|
const { schema, errors } = await dereference(specification)
|
|
64
64
|
```
|
|
65
65
|
|
|
66
|
+
### Track references
|
|
67
|
+
|
|
68
|
+
The `dereference` function accepts an `onDereference` callback option that gets called whenever a reference is resolved. This can be useful for tracking which schemas are being dereferenced:
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
import { dereference } from '@scalar/openapi-parser'
|
|
72
|
+
|
|
73
|
+
const { schema, errors } = await dereference(specification, {
|
|
74
|
+
onDereference: ({ schema, ref }) => {
|
|
75
|
+
//
|
|
76
|
+
},
|
|
77
|
+
})
|
|
78
|
+
```
|
|
79
|
+
|
|
66
80
|
### Modify an OpenAPI document
|
|
67
81
|
|
|
68
82
|
```ts
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type { AnyApiDefinitionFormat, DereferenceResult, Filesystem
|
|
2
|
-
|
|
1
|
+
import type { AnyApiDefinitionFormat, DereferenceResult, Filesystem } from '../types';
|
|
2
|
+
import { type ResolveReferencesOptions } from './resolveReferences.js';
|
|
3
|
+
export type DereferenceOptions = ResolveReferencesOptions;
|
|
3
4
|
/**
|
|
4
5
|
* Resolves all references in an OpenAPI document
|
|
5
6
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dereference.d.ts","sourceRoot":"","sources":["../../src/utils/dereference.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,sBAAsB,EACtB,iBAAiB,EACjB,UAAU,
|
|
1
|
+
{"version":3,"file":"dereference.d.ts","sourceRoot":"","sources":["../../src/utils/dereference.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,sBAAsB,EACtB,iBAAiB,EACjB,UAAU,EACX,MAAM,UAAU,CAAA;AAIjB,OAAO,EACL,KAAK,wBAAwB,EAE9B,MAAM,qBAAqB,CAAA;AAE5B,MAAM,MAAM,kBAAkB,GAAG,wBAAwB,CAAA;AAEzD;;GAEG;AACH,wBAAsB,WAAW,CAC/B,KAAK,EAAE,sBAAsB,GAAG,UAAU,EAC1C,OAAO,CAAC,EAAE,kBAAkB,GAC3B,OAAO,CAAC,iBAAiB,CAAC,CAY5B"}
|
|
@@ -5,8 +5,14 @@ export type ResolveReferencesResult = {
|
|
|
5
5
|
errors: ErrorObject[];
|
|
6
6
|
schema: OpenAPI.Document;
|
|
7
7
|
};
|
|
8
|
+
export type ResolveReferencesOptions = ThrowOnErrorOption & {
|
|
9
|
+
onDereference?: (data: {
|
|
10
|
+
schema: AnyObject;
|
|
11
|
+
ref: string;
|
|
12
|
+
}) => void;
|
|
13
|
+
};
|
|
8
14
|
/**
|
|
9
15
|
* Takes a specification and resolves all references.
|
|
10
16
|
*/
|
|
11
|
-
export declare function resolveReferences(input: AnyObject | Filesystem, options?:
|
|
17
|
+
export declare function resolveReferences(input: AnyObject | Filesystem, options?: ResolveReferencesOptions, file?: FilesystemEntry, errors?: ErrorObject[]): ResolveReferencesResult;
|
|
12
18
|
//# sourceMappingURL=resolveReferences.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolveReferences.d.ts","sourceRoot":"","sources":["../../src/utils/resolveReferences.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAA;AAGpD,OAAO,KAAK,EACV,SAAS,EACT,WAAW,EACX,UAAU,EACV,eAAe,EACf,kBAAkB,EACnB,MAAM,UAAU,CAAA;AAejB,MAAM,MAAM,uBAAuB,GAAG;IACpC,KAAK,EAAE,OAAO,CAAA;IACd,MAAM,EAAE,WAAW,EAAE,CAAA;IACrB,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAA;CACzB,CAAA;AAOD;;GAEG;AACH,wBAAgB,iBAAiB,CAE/B,KAAK,EAAE,SAAS,GAAG,UAAU,EAE7B,OAAO,CAAC,EAAE,
|
|
1
|
+
{"version":3,"file":"resolveReferences.d.ts","sourceRoot":"","sources":["../../src/utils/resolveReferences.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAA;AAGpD,OAAO,KAAK,EACV,SAAS,EACT,WAAW,EACX,UAAU,EACV,eAAe,EACf,kBAAkB,EACnB,MAAM,UAAU,CAAA;AAejB,MAAM,MAAM,uBAAuB,GAAG;IACpC,KAAK,EAAE,OAAO,CAAA;IACd,MAAM,EAAE,WAAW,EAAE,CAAA;IACrB,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAA;CACzB,CAAA;AAED,MAAM,MAAM,wBAAwB,GAAG,kBAAkB,GAAG;IAC1D,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,MAAM,EAAE,SAAS,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAA;CACnE,CAAA;AAOD;;GAEG;AACH,wBAAgB,iBAAiB,CAE/B,KAAK,EAAE,SAAS,GAAG,UAAU,EAE7B,OAAO,CAAC,EAAE,wBAAwB,EAElC,IAAI,CAAC,EAAE,eAAe,EAEtB,MAAM,CAAC,EAAE,WAAW,EAAE,GACrB,uBAAuB,CAqGzB"}
|
|
@@ -27,9 +27,6 @@ errors) {
|
|
|
27
27
|
const entrypoint = getEntrypoint(filesystem);
|
|
28
28
|
// Recursively resolve all references
|
|
29
29
|
resolve(file?.specification ?? entrypoint.specification, filesystem, file ?? entrypoint);
|
|
30
|
-
// If we replace references with content, that includes a reference, we can’t deal with that right-away.
|
|
31
|
-
// That’s why we need a second run.
|
|
32
|
-
resolve(file?.specification ?? entrypoint.specification, filesystem, file ?? entrypoint);
|
|
33
30
|
// Remove duplicats (according to message) from errors
|
|
34
31
|
errors = errors.filter((error, index, self) => index ===
|
|
35
32
|
self.findIndex((t) => t.message === error.message && t.code === error.code));
|
|
@@ -43,48 +40,46 @@ errors) {
|
|
|
43
40
|
/**
|
|
44
41
|
* Resolves the circular reference to an object and deletes the $ref properties.
|
|
45
42
|
*/
|
|
46
|
-
function resolve(schema, resolveFilesystem, resolveFile
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
43
|
+
function resolve(schema, resolveFilesystem, resolveFile,
|
|
44
|
+
// references to resolved object
|
|
45
|
+
resolved = new WeakSet()) {
|
|
46
|
+
let result = { errors: [] };
|
|
47
|
+
if (schema === null || resolved.has(schema))
|
|
48
|
+
return result;
|
|
49
|
+
resolved.add(schema);
|
|
50
|
+
function resolveExternal(externalFile) {
|
|
51
|
+
resolve(externalFile.specification, resolveFilesystem, externalFile, resolved);
|
|
52
|
+
return externalFile;
|
|
53
|
+
}
|
|
54
|
+
// Ignore parts without a reference
|
|
55
|
+
while (schema.$ref !== undefined) {
|
|
56
|
+
// Find the referenced content
|
|
57
|
+
const target = resolveUri(schema.$ref, options, resolveFile, resolveFilesystem, resolveExternal, errors);
|
|
58
|
+
// invalid
|
|
59
|
+
if (typeof target !== 'object' || target === null)
|
|
60
|
+
break;
|
|
61
|
+
options?.onDereference?.({ schema, ref: schema.$ref });
|
|
62
|
+
// Get rid of the reference
|
|
63
|
+
delete schema.$ref;
|
|
64
|
+
for (const key of Object.keys(target)) {
|
|
65
|
+
if (schema[key] === undefined) {
|
|
66
|
+
schema[key] = target[key];
|
|
65
67
|
}
|
|
66
68
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
+
}
|
|
70
|
+
// Iterate over the whole object
|
|
71
|
+
for (const value of Object.values(schema)) {
|
|
72
|
+
if (typeof value === 'object' && value !== null) {
|
|
73
|
+
result = resolve(value, resolveFilesystem, resolveFile, resolved);
|
|
69
74
|
}
|
|
70
|
-
}
|
|
71
|
-
return
|
|
72
|
-
errors: result?.errors ?? [],
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
// TODO: Is there a better way? :D
|
|
77
|
-
function isCircular(schema) {
|
|
78
|
-
try {
|
|
79
|
-
JSON.stringify(schema);
|
|
80
|
-
return false;
|
|
81
|
-
}
|
|
82
|
-
catch (error) {
|
|
83
|
-
return true;
|
|
75
|
+
}
|
|
76
|
+
return result;
|
|
84
77
|
}
|
|
85
78
|
}
|
|
86
79
|
/**
|
|
87
80
|
* Resolves a URI to a part of the specification
|
|
81
|
+
*
|
|
82
|
+
* The output is not necessarily dereferenced
|
|
88
83
|
*/
|
|
89
84
|
function resolveUri(
|
|
90
85
|
// 'foobar.json#/foo/bar'
|
|
@@ -92,7 +87,9 @@ uri, options,
|
|
|
92
87
|
// { filename: './foobar.json '}
|
|
93
88
|
file,
|
|
94
89
|
// [ { filename: './foobar.json '} ]
|
|
95
|
-
filesystem,
|
|
90
|
+
filesystem,
|
|
91
|
+
// a function to resolve references in external file
|
|
92
|
+
resolve, errors) {
|
|
96
93
|
// Ignore invalid URIs
|
|
97
94
|
if (typeof uri !== 'string') {
|
|
98
95
|
if (options?.throwOnError) {
|
|
@@ -123,13 +120,13 @@ filesystem, errors) {
|
|
|
123
120
|
});
|
|
124
121
|
return;
|
|
125
122
|
}
|
|
126
|
-
const result = resolveReferences(filesystem, options, externalReference, errors);
|
|
127
123
|
// $ref: 'other-file.yaml'
|
|
128
124
|
if (path === undefined) {
|
|
129
|
-
return
|
|
125
|
+
return externalReference.specification;
|
|
130
126
|
}
|
|
131
127
|
// $ref: 'other-file.yaml#/foo/bar'
|
|
132
|
-
|
|
128
|
+
// resolve refs first before accessing properties directly
|
|
129
|
+
return resolveUri(`#${path}`, options, resolve(externalReference), filesystem, resolve, errors);
|
|
133
130
|
}
|
|
134
131
|
// Pointers
|
|
135
132
|
const segments = getSegmentsFromPath(path);
|