diff --git a/README.md b/README.md index 452f67c..1106fb2 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,13 @@ +**Note** + +Forked from https://github.com/Q42/openapi-typescript-validator to +include support for remote $ref, from this +[PR](https://github.com/Q42/openapi-typescript-validator/pull/12). +Migrate to upstream when remote $ref support will be included there. + + # openapi-typescript-validator + Generate typescript with `ajv >= 8.0.0` validation based on openapi schemas - [What does this do?](#what-does-this-do) diff --git a/package-lock.json b/package-lock.json index 226c529..7b194a1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,17 +1,18 @@ { "name": "openapi-typescript-validator", - "version": "4.0.0", + "version": "4.0.0~remoteref", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "openapi-typescript-validator", - "version": "4.0.0", + "version": "4.0.1", "license": "MIT", "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", + "ajv": "^8.0.0", + "ajv-formats": "^2.0.0", "js-yaml": "^4.0.0", "json-schema-to-typescript": "^11.0.2", "lodash.keyby": "^4.6.0" @@ -28,6 +29,17 @@ "ajv-formats": "^2.0.0" } }, + "node_modules/@apidevtools/json-schema-ref-parser": { + "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==", + "dependencies": { + "@jsdevtools/ono": "^7.1.3", + "@types/json-schema": "^7.0.6", + "call-me-maybe": "^1.0.1", + "js-yaml": "^4.1.0" + } + }, "node_modules/@bcherny/json-schema-ref-parser": { "version": "9.0.9", "resolved": "https://registry.npmjs.org/@bcherny/json-schema-ref-parser/-/json-schema-ref-parser-9.0.9.tgz", @@ -591,6 +603,17 @@ } }, "dependencies": { + "@apidevtools/json-schema-ref-parser": { + "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": "^4.1.0" + } + }, "@bcherny/json-schema-ref-parser": { "version": "9.0.9", "resolved": "https://registry.npmjs.org/@bcherny/json-schema-ref-parser/-/json-schema-ref-parser-9.0.9.tgz", diff --git a/package.json b/package.json index d2fb377..815ef87 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "openapi-typescript-validator", - "version": "4.0.0", + "version": "4.0.0~remoteref", "description": "Generate typescript with ajv validation based on openapi schemas", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -38,6 +38,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.0.0", "ajv-formats": "^2.0.0", 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 + }); + }); + +});