From adf024ac07275fef92fd6ded0e6e51d170146d43 Mon Sep 17 00:00:00 2001 From: Mark Fejes Date: Sat, 9 Apr 2022 15:05:16 +0200 Subject: [PATCH] fix: add support for external refs --- package-lock.json | 55 ++++++++++++++------- package.json | 1 + src/parse-schema.ts | 14 +++++- tests/schemas/schema-with-external-ref.yaml | 6 +++ tests/schemas/user.yaml | 9 ++++ tests/src/schema-with-external-ref.test.ts | 23 +++++++++ 6 files changed, 89 insertions(+), 19 deletions(-) create mode 100644 tests/schemas/schema-with-external-ref.yaml create mode 100644 tests/schemas/user.yaml create mode 100644 tests/src/schema-with-external-ref.test.ts diff --git a/package-lock.json b/package-lock.json index e499268..e966696 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,30 +5,22 @@ "requires": true, "dependencies": { "@apidevtools/json-schema-ref-parser": { - "version": "9.0.7", - "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.0.7.tgz", - "integrity": "sha512-QdwOGF1+eeyFh+17v2Tz626WX0nucd1iKOm6JUTUvCZdbolblCOOQCxGrQPY0f7jEhn36PiAWqZnsC2r5vmUWg==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.0.9.tgz", + "integrity": "sha512-GBD2Le9w2+lVFoc4vswGI/TjkNIZSVp7+9xPf+X3uidBfWnAeUWmquteSyt0+VCrhNMWj/FTABISQrD3Z/YA+w==", "requires": { "@jsdevtools/ono": "^7.1.3", + "@types/json-schema": "^7.0.6", "call-me-maybe": "^1.0.1", - "js-yaml": "^3.13.1" + "js-yaml": "^4.1.0" }, "dependencies": { - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "requires": { - "sprintf-js": "~1.0.2" - } - }, "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "argparse": "^2.0.1" } } } @@ -327,6 +319,35 @@ "integrity": "sha512-uxU9Ix+MVszvCTvBucQiIcNEny3oAEFg7EQHSZw2bquCCuqUqEPEczIdv/Uqo1Zv4/wDPZqOI+ulrMk1ncMtjQ==", "requires": { "@apidevtools/json-schema-ref-parser": "9.0.7" + }, + "dependencies": { + "@apidevtools/json-schema-ref-parser": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.0.7.tgz", + "integrity": "sha512-QdwOGF1+eeyFh+17v2Tz626WX0nucd1iKOm6JUTUvCZdbolblCOOQCxGrQPY0f7jEhn36PiAWqZnsC2r5vmUWg==", + "requires": { + "@jsdevtools/ono": "^7.1.3", + "call-me-maybe": "^1.0.1", + "js-yaml": "^3.13.1" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + } } }, "json-schema-to-typescript": { diff --git a/package.json b/package.json index f8ed383..178e25e 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "ajv-formats": "^2.0.0" }, "dependencies": { + "@apidevtools/json-schema-ref-parser": "^9.0.9", "@openapi-contrib/openapi-schema-to-json-schema": "^3.0.4", "ajv": "^8.1.0", "ajv-formats": "^2.0.2", diff --git a/src/parse-schema.ts b/src/parse-schema.ts index 2ce3fe5..5ae38bc 100644 --- a/src/parse-schema.ts +++ b/src/parse-schema.ts @@ -1,6 +1,8 @@ import jsYaml from 'js-yaml' import { JSONSchema } from 'json-schema-to-typescript'; +import $RefParser from '@apidevtools/json-schema-ref-parser'; import { readFileSync } from 'fs'; +import { dirname } from 'path'; const toJsonSchema = require('@openapi-contrib/openapi-schema-to-json-schema'); @@ -12,7 +14,7 @@ export interface ParsedSchema { whitelistedDecoders: string[] | undefined; } -export function parseSchema(inputFilePath: string, schemaType: SchemaType): ParsedSchema { +export async function parseSchema(inputFilePath: string, schemaType: SchemaType): Promise { switch (schemaType) { case 'json': case 'yaml': @@ -22,7 +24,7 @@ export function parseSchema(inputFilePath: string, schemaType: SchemaType): Pars } } -function parseOpenApiSchema(inputFilePath: string, schemaType: 'yaml' | 'json'): ParsedSchema { +async function parseOpenApiSchema(inputFilePath: string, schemaType: 'yaml' | 'json'): Promise { let schema: any; const inputFileContent = readFileSync(inputFilePath, 'utf8'); @@ -33,6 +35,14 @@ function parseOpenApiSchema(inputFilePath: string, schemaType: 'yaml' | 'json'): schema = JSON.parse(inputFileContent); } + // need to change to input file base directory, so relative ref paths can be resolved + const originalDirectory = process.cwd(); + process.chdir(dirname(inputFilePath)); + // resolve external references to original schema + schema = await $RefParser.bundle(schema) + // change back to original directory + process.chdir(originalDirectory); + const properties: Record = {}; const definitions: Record = {}; diff --git a/tests/schemas/schema-with-external-ref.yaml b/tests/schemas/schema-with-external-ref.yaml new file mode 100644 index 0000000..1f37878 --- /dev/null +++ b/tests/schemas/schema-with-external-ref.yaml @@ -0,0 +1,6 @@ +components: + schemas: + UserList: + type: array + items: + $ref: './user.yaml#/definitions/User' \ No newline at end of file diff --git a/tests/schemas/user.yaml b/tests/schemas/user.yaml new file mode 100644 index 0000000..3e04706 --- /dev/null +++ b/tests/schemas/user.yaml @@ -0,0 +1,9 @@ +definitions: + User: + type: object + properties: + id: + type: string + name: + type: string + required: ['id'] \ No newline at end of file diff --git a/tests/src/schema-with-external-ref.test.ts b/tests/src/schema-with-external-ref.test.ts new file mode 100644 index 0000000..1bc4daf --- /dev/null +++ b/tests/src/schema-with-external-ref.test.ts @@ -0,0 +1,23 @@ +import path from "path"; +import fs from "fs"; +import { generate } from "openapi-typescript-validator"; + +describe("schema-with-external-ref", () => { + const name = "schema-with-external-ref"; + const generatedDir = path.join(__dirname, "../generated", name); + const schemaDir = path.join(__dirname, "../schemas"); + + beforeAll(async () => { + if (fs.existsSync(generatedDir)) + fs.rmdirSync(generatedDir, { recursive: true }); + }); + + test('schema with external ref', async () => { + await generate({ + schemaFile: path.join(schemaDir, "schema-with-external-ref.yaml"), + schemaType: "yaml", + directory: generatedDir + }); + }); + +});