Skip to content

Commit a9d63e5

Browse files
authored
Merge pull request #4 from layer5io/utkarsh-pro/feature/resolve-ref
Add support for resolving "$ref" in the CLI
2 parents 445c5fc + 947170e commit a9d63e5

File tree

6 files changed

+172
-17
lines changed

6 files changed

+172
-17
lines changed

README.md

+12-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ This is a very basic node based CLI for converting OpenAPI schema to JSON Schema
44

55

66
```
7-
Usage: openapi-jsonschema [options]
7+
Usage: kubeopenapi-jsonschema [options]
88
99
Options:
1010
-t, --type [type] set type of input, can be either yaml or json (default: "yaml")
@@ -14,6 +14,7 @@ Options:
1414
-o [output-format] output format (default: "json")
1515
--o-filter [output-filter] output filter query
1616
--silent skip output (default: false)
17+
--resolve [resolve-filter] root of the OpenAPI spec to resolve the $ref. It is important to note that this jsonpath MUST evaluate to one object (default: "")
1718
-h, --help display help for command
1819
```
1920

@@ -22,9 +23,18 @@ Options:
2223
Download the binaries from the github releases. Only linux-x64, darwin-x64 and windows-x64 binaries are released
2324

2425
```bash
25-
openapi-jsonschema --location ./istio.yaml -t yaml --filter '$[?(@.kind=="CustomResourceDefinition" && @.spec.names.kind=="EnvoyFilter")]..validation.openAPIV3Schema.properties.spec' -o yaml --o-filter '$[0]'
26+
kubeopenapi-jsonschema --location ./k8s.json -f '$.definitions' -t json --o-filter '$[0][?(@["x-kubernetes-group-version-kind"][0].kind=="Deployment")].properties.spec' --resolve "$"
2627
```
2728

29+
The above will consume kubernetes open API schema and will produce schema for Kubernetes `Deployment`
30+
31+
32+
```bash
33+
kubeopenapi-jsonschema --location ./istio.yaml -t yaml --filter '$[?(@.kind=="CustomResourceDefinition")]..schema.openAPIV3Schema.properties.spec' --o-filter '$'
34+
```
35+
36+
The above will consume istio CRD manifest and will produce schema for all of the CustomResourceDefinition objects
37+
2838
<div>&nbsp;</div>
2939

3040
## Join the service mesh community!

helper/output.js

+6-4
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,17 @@ const jp = require("jsonpath");
44
/**
55
* Output takes in the data that needs to be printed and
66
* an output format
7-
* @param {*} data
7+
* @param {Promise<any>} data
88
* @param {"json" | "yaml"} format output format
99
*/
1010
function Output(data, format = "json", filter = "$", silent = false) {
1111
if (silent) return;
1212

13-
data = jp.query(data, filter);
14-
if (format === "yaml") return console.log(dump(data));
15-
if (format === "json") return console.log(JSON.stringify(data, null, 2));
13+
data.then(data => {
14+
data = jp.query(data, filter);
15+
if (format === "yaml") return console.log(dump(data));
16+
if (format === "json") return console.log(JSON.stringify(data, null, 2));
17+
})
1618
}
1719

1820
module.exports = Output;

helper/toJSONSchema.js

+35-9
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ const { readFileSync, writeFileSync } = require("fs");
55
const { tmpdir } = require("os");
66
const path = require("path");
77
const jp = require("jsonpath");
8+
const { Resolver } = require("@stoplight/json-ref-resolver");
89

910
/**
1011
* convertAllSchemasToJSONSchema takes in the OpenAPIV3 Schemas in an array
@@ -23,17 +24,39 @@ function convertAllSchemasToJSONSchema(schemas) {
2324
* readSchema will read schema file from the given location, it expects
2425
* the schema to be in JSON format
2526
*
26-
* readSchema will also apply the given jsonpath filter to the read schema
27-
* and will return only the filtered JSONs
27+
* readSchema will also resolve the references if a resolveQuery is passed
2828
* @param {string} location
29-
* @param {string} query jsonpath based query
30-
* @returns {any[]}
29+
* @param {string} resolveQuery jsonpath based query - must resolve to EXACTLY one match or else is ignored
30+
* @returns {Promise<any[]>}
3131
*/
32-
function readSchema(location, query) {
32+
async function readSchema(location, resolveQuery) {
3333
const data = readFileSync(location, "utf-8");
3434
const parsed = JSON.parse(data);
3535

36-
return jp.query(parsed, query);
36+
if (resolveQuery) {
37+
const inner = jp.query(parsed, resolveQuery);
38+
39+
if (inner.length !== 1) return parsed;
40+
41+
const resolver = new Resolver();
42+
const resolved = await resolver.resolve(inner[0], {});
43+
44+
if (resolved.errors.length) console.error(resolved.errors);
45+
46+
return resolved.result;
47+
}
48+
49+
return parsed;
50+
}
51+
52+
/**
53+
* filterSchemas takes in an array of schemas and will return an array of filtered schemas
54+
* @param {Array<any>} schemas - OpenAPI schema in JSON format
55+
* @param {string} query jsonpath based query to filter out the data
56+
* @returns {Array<any>}
57+
*/
58+
function filterSchemas(schemas, query) {
59+
return jp.query(schemas, query);
3760
}
3861

3962
/**
@@ -72,16 +95,19 @@ function setupFiles(location, type) {
7295
* @param {string} location location of the schemas in open api v3 format
7396
* @param {"yaml" | "json"} type encoding in which the openapi schema is present
7497
* @param {string} query jsonpath query to filter the read schemas
98+
* @param {string} resolve jsonpath query to reach to the root of the openAPI spec
7599
*/
76-
function ToJSONSchema(location, type = "yaml", query = "") {
100+
async function ToJSONSchema(location, type = "yaml", query = "", resolve = "") {
77101
if (type !== "yaml" && type !== "json")
78102
throw Error('invalid type received: can be either "yaml" or "json"');
79103

80104
const source = setupFiles(location, type);
81105

82-
const schemas = readSchema(source, query);
106+
const schemas = await readSchema(source, resolve);
107+
108+
const filtered = filterSchemas(schemas, query);
83109

84-
return convertAllSchemasToJSONSchema(schemas);
110+
return convertAllSchemasToJSONSchema(filtered);
85111
}
86112

87113
module.exports = ToJSONSchema;

index.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ program
1515
.option("--kubernetes", "enable kubernetes specific filters", false)
1616
.option("-o [output-format]", "output format", "json")
1717
.option("--o-filter [output-filter]", "output filter query")
18-
.option("--silent", "skip output", false);
18+
.option("--silent", "skip output", false)
19+
.option("--resolve [resolve-filter]", "root of the OpenAPI spec to resolve the $ref", "")
1920

2021
program.parse(process.argv);
2122

@@ -25,7 +26,8 @@ Output(
2526
ToJSONSchema(
2627
options.location,
2728
options.type,
28-
CreateQuery(options.filter, options.kubernetes)
29+
CreateQuery(options.filter, options.kubernetes),
30+
options.resolve,
2931
),
3032
options.o,
3133
options.oFilter,

package-lock.json

+114
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
"license": "MIT",
1111
"dependencies": {
1212
"@openapi-contrib/openapi-schema-to-json-schema": "^3.1.1",
13+
"@stoplight/json-ref-resolver": "^3.1.3",
1314
"commander": "^7.2.0",
1415
"js-yaml": "^4.1.0",
1516
"jsonpath": "^1.1.1"

0 commit comments

Comments
 (0)