New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

openapi-typescript

Package Overview
Dependencies
Maintainers
1
Versions
145
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

openapi-typescript - npm Package Compare versions

Comparing version 4.0.1 to 4.0.2

21

dist/cjs/index.js

@@ -33,2 +33,3 @@ "use strict";

const parser_typescript_1 = __importDefault(require("prettier/parser-typescript"));
const url_1 = require("url");
const load_1 = __importStar(require("./load"));

@@ -57,2 +58,3 @@ const utils_1 = require("./utils");

let external = {};
const allSchemas = {};
if (typeof schema === "string") {

@@ -62,14 +64,13 @@ const schemaURL = load_1.resolveSchema(schema);

console.log(kleur_1.yellow(`🔭 Loading spec from ${kleur_1.bold(schemaURL.href)}…`));
const schemas = {};
await load_1.default(schemaURL, {
...ctx,
schemas,
schemas: allSchemas,
rootURL: schemaURL,
});
for (const k of Object.keys(schemas)) {
for (const k of Object.keys(allSchemas)) {
if (k === schemaURL.href) {
rootSchema = schemas[k];
rootSchema = allSchemas[k];
}
else {
external[k] = schemas[k];
external[k] = allSchemas[k];
}

@@ -79,3 +80,11 @@ }

else {
rootSchema = schema;
await load_1.default(schema, { ...ctx, schemas: allSchemas, rootURL: new url_1.URL(load_1.VIRTUAL_JSON_URL) });
for (const k of Object.keys(allSchemas)) {
if (k === load_1.VIRTUAL_JSON_URL) {
rootSchema = allSchemas[k];
}
else {
external[k] = allSchemas[k];
}
}
}

@@ -82,0 +91,0 @@ let output = exports.WARNING_MESSAGE;

@@ -5,12 +5,14 @@ /// <reference types="node" />

declare type PartialSchema = Record<string, any>;
declare type SchemaMap = {
[url: string]: PartialSchema;
};
export declare const VIRTUAL_JSON_URL = "file:///_json";
export declare function resolveSchema(url: string): URL;
interface LoadOptions extends GlobalContext {
rootURL: URL;
schemas: {
[url: string]: PartialSchema;
};
schemas: SchemaMap;
}
export default function load(schemaURL: URL, options: LoadOptions): Promise<{
export default function load(schema: URL | PartialSchema, options: LoadOptions): Promise<{
[url: string]: PartialSchema;
}>;
export {};

@@ -25,3 +25,3 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.resolveSchema = void 0;
exports.resolveSchema = exports.VIRTUAL_JSON_URL = void 0;
const fs_1 = __importDefault(require("fs"));

@@ -31,5 +31,7 @@ const path_1 = __importDefault(require("path"));

const node_fetch_1 = __importStar(require("node-fetch"));
const slash_1 = __importDefault(require("slash"));
const mime_1 = __importDefault(require("mime"));
const js_yaml_1 = __importDefault(require("js-yaml"));
const utils_1 = require("./utils");
exports.VIRTUAL_JSON_URL = `file:///_json`;
function parseSchema(schema, type) {

@@ -60,3 +62,5 @@ if (type === "YAML") {

}
const localPath = path_1.default.isAbsolute(url) ? new url_1.URL("", `file://${url}`) : new url_1.URL(url, `file://${process.cwd()}/`);
const localPath = path_1.default.isAbsolute(url)
? new url_1.URL("", `file://${slash_1.default(url)}`)
: new url_1.URL(url, `file://${slash_1.default(process.cwd())}/`);
if (!fs_1.default.existsSync(localPath)) {

@@ -72,41 +76,50 @@ throw new Error(`Could not locate ${url}`);

let urlCache = new Set();
async function load(schemaURL, options) {
if (urlCache.has(schemaURL.href))
return options.schemas;
urlCache.add(schemaURL.href);
async function load(schema, options) {
const isJSON = schema instanceof url_1.URL === false;
let schemaID = isJSON ? new url_1.URL(exports.VIRTUAL_JSON_URL).href : schema.href;
const schemas = options.schemas;
let contents = "";
let contentType = "";
if (isFile(schemaURL)) {
contents = await fs_1.default.promises.readFile(schemaURL, "utf8");
contentType = mime_1.default.getType(schemaURL.href) || "";
if (isJSON) {
schemas[schemaID] = schema;
}
else {
const headers = new node_fetch_1.Headers();
if (options.auth)
headers.set("Authorization", options.auth);
const res = await node_fetch_1.default(schemaURL.href, { method: "GET", headers });
contentType = res.headers.get("Content-Type") || "";
contents = await res.text();
}
const isYAML = contentType === "application/openapi+yaml" || contentType === "text/yaml";
const isJSON = contentType === "application/json" ||
contentType === "application/json5" ||
contentType === "application/openapi+json";
if (isYAML) {
schemas[schemaURL.href] = parseSchema(contents, "YAML");
}
else if (isJSON) {
schemas[schemaURL.href] = parseSchema(contents, "JSON");
}
else {
try {
schemas[schemaURL.href] = parseSchema(contents, "JSON");
if (urlCache.has(schemaID))
return options.schemas;
urlCache.add(schemaID);
let contents = "";
let contentType = "";
const schemaURL = schema;
if (isFile(schemaURL)) {
contents = await fs_1.default.promises.readFile(schemaURL, "utf8");
contentType = mime_1.default.getType(schemaID) || "";
}
catch (err1) {
else {
const headers = new node_fetch_1.Headers();
headers.set("User-Agent", "openapi-typescript");
if (options.auth)
headers.set("Authorization", options.auth);
const res = await node_fetch_1.default(schemaID, { method: "GET", headers });
contentType = res.headers.get("Content-Type") || "";
contents = await res.text();
}
const isYAML = contentType === "application/openapi+yaml" || contentType === "text/yaml";
const isJSON = contentType === "application/json" ||
contentType === "application/json5" ||
contentType === "application/openapi+json";
if (isYAML) {
schemas[schemaID] = parseSchema(contents, "YAML");
}
else if (isJSON) {
schemas[schemaID] = parseSchema(contents, "JSON");
}
else {
try {
schemas[schemaURL.href] = parseSchema(contents, "YAML");
schemas[schemaID] = parseSchema(contents, "JSON");
}
catch (err2) {
throw new Error(`Unknown format${contentType ? `: "${contentType}"` : ""}. Only YAML or JSON supported.`);
catch (err1) {
try {
schemas[schemaID] = parseSchema(contents, "YAML");
}
catch (err2) {
throw new Error(`Unknown format${contentType ? `: "${contentType}"` : ""}. Only YAML or JSON supported.`);
}
}

@@ -116,3 +129,3 @@ }

const refPromises = [];
schemas[schemaURL.href] = JSON.parse(JSON.stringify(schemas[schemaURL.href]), (k, v) => {
schemas[schemaID] = JSON.parse(JSON.stringify(schemas[schemaID]), (k, v) => {
if (k !== "$ref" || typeof v !== "string")

@@ -122,3 +135,7 @@ return v;

if (refURL) {
const nextURL = refURL.startsWith("http://") || refURL.startsWith("https://") ? new url_1.URL(refURL) : new url_1.URL(refURL, schemaURL);
const isRemoteURL = refURL.startsWith("http://") || refURL.startsWith("https://");
if (isJSON && !isRemoteURL) {
throw new Error(`Can’t load URL "${refURL}" from dynamic JSON. Load this schema from a URL instead.`);
}
const nextURL = isRemoteURL ? new url_1.URL(refURL) : new url_1.URL(slash_1.default(refURL), schema);
refPromises.push(load(nextURL, options).then((subschemas) => {

@@ -134,3 +151,3 @@ for (const subschemaURL of Object.keys(subschemas)) {

await Promise.all(refPromises);
if (schemaURL.href === options.rootURL.href) {
if (schemaID === options.rootURL.href) {
for (const subschemaURL of Object.keys(schemas)) {

@@ -137,0 +154,0 @@ schemas[subschemaURL] = JSON.parse(JSON.stringify(schemas[subschemaURL]), (k, v) => {

@@ -6,2 +6,3 @@ import { GlobalContext } from "../types";

export declare function transformSchemaObjMap(obj: Record<string, any>, options: TransformSchemaObjOptions): string;
export declare function addRequiredProps(properties: Record<string, any>, required: Set<string>): string[];
export declare function transformAnyOf(anyOf: any, options: TransformSchemaObjOptions): string;

@@ -8,0 +9,0 @@ export declare function transformOneOf(oneOf: any, options: TransformSchemaObjOptions): string;

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.transformSchemaObj = exports.transformOneOf = exports.transformAnyOf = exports.transformSchemaObjMap = void 0;
exports.transformSchemaObj = exports.transformOneOf = exports.transformAnyOf = exports.addRequiredProps = exports.transformSchemaObjMap = void 0;
const utils_1 = require("../utils");

@@ -25,2 +25,14 @@ function hasDefaultValue(node) {

exports.transformSchemaObjMap = transformSchemaObjMap;
function addRequiredProps(properties, required) {
const missingRequired = [...required].filter((r) => !(r in properties));
if (missingRequired.length == 0) {
return [];
}
let output = "";
for (const r of missingRequired) {
output += `${r}: unknown;\n`;
}
return [`{\n${output}}`];
}
exports.addRequiredProps = addRequiredProps;
function transformAnyOf(anyOf, options) {

@@ -82,6 +94,8 @@ const schemas = anyOf.filter((s) => {

const isAnyOfOrOneOfOrAllOf = "anyOf" in node || "oneOf" in node || "allOf" in node;
const missingRequired = addRequiredProps(node.properties || {}, node.required || []);
if (!isAnyOfOrOneOfOrAllOf &&
(!node.properties || !Object.keys(node.properties).length) &&
!node.additionalProperties) {
output += `{ ${readonly}[key: string]: any }`;
const emptyObj = `{ ${readonly}[key: string]: unknown }`;
output += utils_1.tsIntersectionOf([emptyObj, ...missingRequired]);
break;

@@ -118,2 +132,3 @@ }

...(properties ? [`{\n${properties}\n}`] : []),
...missingRequired,
...(additionalProperties ? [additionalProperties] : []),

@@ -120,0 +135,0 @@ ]);

@@ -5,3 +5,4 @@ import path from "path";

import parserTypescript from "prettier/parser-typescript";
import load, { resolveSchema } from "./load";
import { URL } from "url";
import load, { resolveSchema, VIRTUAL_JSON_URL } from "./load";
import { swaggerVersion } from "./utils";

@@ -29,2 +30,3 @@ import { transformAll } from "./transform/index";

let external = {};
const allSchemas = {};
if (typeof schema === "string") {

@@ -34,14 +36,13 @@ const schemaURL = resolveSchema(schema);

console.log(yellow(`🔭 Loading spec from ${bold(schemaURL.href)}…`));
const schemas = {};
await load(schemaURL, {
...ctx,
schemas,
schemas: allSchemas,
rootURL: schemaURL,
});
for (const k of Object.keys(schemas)) {
for (const k of Object.keys(allSchemas)) {
if (k === schemaURL.href) {
rootSchema = schemas[k];
rootSchema = allSchemas[k];
}
else {
external[k] = schemas[k];
external[k] = allSchemas[k];
}

@@ -51,3 +52,11 @@ }

else {
rootSchema = schema;
await load(schema, { ...ctx, schemas: allSchemas, rootURL: new URL(VIRTUAL_JSON_URL) });
for (const k of Object.keys(allSchemas)) {
if (k === VIRTUAL_JSON_URL) {
rootSchema = allSchemas[k];
}
else {
external[k] = allSchemas[k];
}
}
}

@@ -54,0 +63,0 @@ let output = WARNING_MESSAGE;

@@ -5,12 +5,14 @@ /// <reference types="node" />

declare type PartialSchema = Record<string, any>;
declare type SchemaMap = {
[url: string]: PartialSchema;
};
export declare const VIRTUAL_JSON_URL = "file:///_json";
export declare function resolveSchema(url: string): URL;
interface LoadOptions extends GlobalContext {
rootURL: URL;
schemas: {
[url: string]: PartialSchema;
};
schemas: SchemaMap;
}
export default function load(schemaURL: URL, options: LoadOptions): Promise<{
export default function load(schema: URL | PartialSchema, options: LoadOptions): Promise<{
[url: string]: PartialSchema;
}>;
export {};

@@ -5,5 +5,7 @@ import fs from "fs";

import fetch, { Headers } from "node-fetch";
import slash from "slash";
import mime from "mime";
import yaml from "js-yaml";
import { parseRef } from "./utils";
export const VIRTUAL_JSON_URL = `file:///_json`;
function parseSchema(schema, type) {

@@ -34,3 +36,5 @@ if (type === "YAML") {

}
const localPath = path.isAbsolute(url) ? new URL("", `file://${url}`) : new URL(url, `file://${process.cwd()}/`);
const localPath = path.isAbsolute(url)
? new URL("", `file://${slash(url)}`)
: new URL(url, `file://${slash(process.cwd())}/`);
if (!fs.existsSync(localPath)) {

@@ -45,41 +49,50 @@ throw new Error(`Could not locate ${url}`);

let urlCache = new Set();
export default async function load(schemaURL, options) {
if (urlCache.has(schemaURL.href))
return options.schemas;
urlCache.add(schemaURL.href);
export default async function load(schema, options) {
const isJSON = schema instanceof URL === false;
let schemaID = isJSON ? new URL(VIRTUAL_JSON_URL).href : schema.href;
const schemas = options.schemas;
let contents = "";
let contentType = "";
if (isFile(schemaURL)) {
contents = await fs.promises.readFile(schemaURL, "utf8");
contentType = mime.getType(schemaURL.href) || "";
if (isJSON) {
schemas[schemaID] = schema;
}
else {
const headers = new Headers();
if (options.auth)
headers.set("Authorization", options.auth);
const res = await fetch(schemaURL.href, { method: "GET", headers });
contentType = res.headers.get("Content-Type") || "";
contents = await res.text();
}
const isYAML = contentType === "application/openapi+yaml" || contentType === "text/yaml";
const isJSON = contentType === "application/json" ||
contentType === "application/json5" ||
contentType === "application/openapi+json";
if (isYAML) {
schemas[schemaURL.href] = parseSchema(contents, "YAML");
}
else if (isJSON) {
schemas[schemaURL.href] = parseSchema(contents, "JSON");
}
else {
try {
schemas[schemaURL.href] = parseSchema(contents, "JSON");
if (urlCache.has(schemaID))
return options.schemas;
urlCache.add(schemaID);
let contents = "";
let contentType = "";
const schemaURL = schema;
if (isFile(schemaURL)) {
contents = await fs.promises.readFile(schemaURL, "utf8");
contentType = mime.getType(schemaID) || "";
}
catch (err1) {
else {
const headers = new Headers();
headers.set("User-Agent", "openapi-typescript");
if (options.auth)
headers.set("Authorization", options.auth);
const res = await fetch(schemaID, { method: "GET", headers });
contentType = res.headers.get("Content-Type") || "";
contents = await res.text();
}
const isYAML = contentType === "application/openapi+yaml" || contentType === "text/yaml";
const isJSON = contentType === "application/json" ||
contentType === "application/json5" ||
contentType === "application/openapi+json";
if (isYAML) {
schemas[schemaID] = parseSchema(contents, "YAML");
}
else if (isJSON) {
schemas[schemaID] = parseSchema(contents, "JSON");
}
else {
try {
schemas[schemaURL.href] = parseSchema(contents, "YAML");
schemas[schemaID] = parseSchema(contents, "JSON");
}
catch (err2) {
throw new Error(`Unknown format${contentType ? `: "${contentType}"` : ""}. Only YAML or JSON supported.`);
catch (err1) {
try {
schemas[schemaID] = parseSchema(contents, "YAML");
}
catch (err2) {
throw new Error(`Unknown format${contentType ? `: "${contentType}"` : ""}. Only YAML or JSON supported.`);
}
}

@@ -89,3 +102,3 @@ }

const refPromises = [];
schemas[schemaURL.href] = JSON.parse(JSON.stringify(schemas[schemaURL.href]), (k, v) => {
schemas[schemaID] = JSON.parse(JSON.stringify(schemas[schemaID]), (k, v) => {
if (k !== "$ref" || typeof v !== "string")

@@ -95,3 +108,7 @@ return v;

if (refURL) {
const nextURL = refURL.startsWith("http://") || refURL.startsWith("https://") ? new URL(refURL) : new URL(refURL, schemaURL);
const isRemoteURL = refURL.startsWith("http://") || refURL.startsWith("https://");
if (isJSON && !isRemoteURL) {
throw new Error(`Can’t load URL "${refURL}" from dynamic JSON. Load this schema from a URL instead.`);
}
const nextURL = isRemoteURL ? new URL(refURL) : new URL(slash(refURL), schema);
refPromises.push(load(nextURL, options).then((subschemas) => {

@@ -107,3 +124,3 @@ for (const subschemaURL of Object.keys(subschemas)) {

await Promise.all(refPromises);
if (schemaURL.href === options.rootURL.href) {
if (schemaID === options.rootURL.href) {
for (const subschemaURL of Object.keys(schemas)) {

@@ -110,0 +127,0 @@ schemas[subschemaURL] = JSON.parse(JSON.stringify(schemas[subschemaURL]), (k, v) => {

@@ -6,2 +6,3 @@ import { GlobalContext } from "../types";

export declare function transformSchemaObjMap(obj: Record<string, any>, options: TransformSchemaObjOptions): string;
export declare function addRequiredProps(properties: Record<string, any>, required: Set<string>): string[];
export declare function transformAnyOf(anyOf: any, options: TransformSchemaObjOptions): string;

@@ -8,0 +9,0 @@ export declare function transformOneOf(oneOf: any, options: TransformSchemaObjOptions): string;

@@ -21,2 +21,13 @@ import { comment, nodeType, tsArrayOf, tsIntersectionOf, tsPartial, tsReadonly, tsTupleOf, tsUnionOf } from "../utils";

}
export function addRequiredProps(properties, required) {
const missingRequired = [...required].filter((r) => !(r in properties));
if (missingRequired.length == 0) {
return [];
}
let output = "";
for (const r of missingRequired) {
output += `${r}: unknown;\n`;
}
return [`{\n${output}}`];
}
export function transformAnyOf(anyOf, options) {

@@ -75,6 +86,8 @@ const schemas = anyOf.filter((s) => {

const isAnyOfOrOneOfOrAllOf = "anyOf" in node || "oneOf" in node || "allOf" in node;
const missingRequired = addRequiredProps(node.properties || {}, node.required || []);
if (!isAnyOfOrOneOfOrAllOf &&
(!node.properties || !Object.keys(node.properties).length) &&
!node.additionalProperties) {
output += `{ ${readonly}[key: string]: any }`;
const emptyObj = `{ ${readonly}[key: string]: unknown }`;
output += tsIntersectionOf([emptyObj, ...missingRequired]);
break;

@@ -111,2 +124,3 @@ }

...(properties ? [`{\n${properties}\n}`] : []),
...missingRequired,
...(additionalProperties ? [additionalProperties] : []),

@@ -113,0 +127,0 @@ ]);

{
"name": "openapi-typescript",
"description": "Generate TypeScript types from Swagger OpenAPI specs",
"version": "4.0.1",
"version": "4.0.2",
"engines": {
"node": ">= 10.0.0"
"node": ">= 12.0.0"
},

@@ -47,8 +47,8 @@ "author": "drew@pow.rs",

"build": "rm -rf dist && tsc --build tsconfig.json && tsc --build tsconfig.cjs.json",
"format": "yarn prettier -w .",
"lint": "eslint --ignore-path .gitignore --ext .js,.ts src",
"format": "npm run prettier -w .",
"lint": "eslint .",
"prepare": "npm run build",
"pregenerate": "npm run build",
"test": "npm run build && jest --no-cache --test-timeout=10000",
"test:coverage": "npm run build && jest --no-cache --test-timeout=10000 --coverage && codecov",
"test": "npm run build && jest --no-cache",
"test:coverage": "npm run build && jest --no-cache --coverage && codecov",
"typecheck": "tsc --noEmit",

@@ -65,2 +65,3 @@ "version": "npm run build"

"prettier": "^2.3.1",
"slash": "^3.0.0",
"tiny-glob": "^0.2.9"

@@ -67,0 +68,0 @@ },

@@ -6,3 +6,3 @@ [![version(scoped)](https://img.shields.io/npm/v/openapi-typescript.svg)](https://www.npmjs.com/package/openapi-typescript)

<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-36-orange.svg?style=flat-square)](#contributors-)
[![All Contributors](https://img.shields.io/badge/all_contributors-38-orange.svg?style=flat-square)](#contributors-)
<!-- ALL-CONTRIBUTORS-BADGE:END -->

@@ -245,2 +245,4 @@

<td align="center"><a href="https://github.com/sharmarajdaksh"><img src="https://avatars.githubusercontent.com/u/33689528?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dakshraj Sharma</b></sub></a><br /><a href="https://github.com/drwpow/openapi-typescript/commits?author=sharmarajdaksh" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/shuluster"><img src="https://avatars.githubusercontent.com/u/1707910?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Shaosu Liu</b></sub></a><br /><a href="https://github.com/drwpow/openapi-typescript/commits?author=shuluster" title="Code">💻</a></td>
<td align="center"><a href="https://vytenis.kuciauskas.lt"><img src="https://avatars.githubusercontent.com/u/468006?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Vytenis</b></sub></a><br /><a href="https://github.com/drwpow/openapi-typescript/commits?author=FDiskas" title="Code">💻</a></td>
</tr>

@@ -247,0 +249,0 @@ </table>

@@ -5,3 +5,4 @@ import path from "path";

import parserTypescript from "prettier/parser-typescript";
import load, { resolveSchema } from "./load";
import { URL } from "url";
import load, { resolveSchema, VIRTUAL_JSON_URL } from "./load";
import { swaggerVersion } from "./utils";

@@ -39,20 +40,27 @@ import { transformAll } from "./transform/index";

let external: Record<string, Record<string, any>> = {};
const allSchemas: Record<string, Record<string, any>> = {};
if (typeof schema === "string") {
const schemaURL = resolveSchema(schema);
if (options.silent === false) console.log(yellow(`🔭 Loading spec from ${bold(schemaURL.href)}…`));
const schemas: Record<string, Record<string, any>> = {};
await load(schemaURL, {
...ctx,
schemas,
schemas: allSchemas,
rootURL: schemaURL, // as it crawls schemas recursively, it needs to know which is the root to resolve everything relative to
});
for (const k of Object.keys(schemas)) {
for (const k of Object.keys(allSchemas)) {
if (k === schemaURL.href) {
rootSchema = schemas[k];
rootSchema = allSchemas[k];
} else {
external[k] = schemas[k];
external[k] = allSchemas[k];
}
}
} else {
rootSchema = schema;
await load(schema, { ...ctx, schemas: allSchemas, rootURL: new URL(VIRTUAL_JSON_URL) });
for (const k of Object.keys(allSchemas)) {
if (k === VIRTUAL_JSON_URL) {
rootSchema = allSchemas[k];
} else {
external[k] = allSchemas[k];
}
}
}

@@ -59,0 +67,0 @@

@@ -5,2 +5,3 @@ import fs from "fs";

import fetch, { Headers } from "node-fetch";
import slash from "slash";
import mime from "mime";

@@ -12,3 +13,6 @@ import yaml from "js-yaml";

type PartialSchema = Record<string, any>; // not a very accurate type, but this is easier to deal with before we know we’re dealing with a valid spec
type SchemaMap = { [url: string]: PartialSchema };
export const VIRTUAL_JSON_URL = `file:///_json`; // fake URL reserved for dynamic JSON
function parseSchema(schema: any, type: "YAML" | "JSON") {

@@ -41,3 +45,5 @@ if (type === "YAML") {

// option 2: local
const localPath = path.isAbsolute(url) ? new URL("", `file://${url}`) : new URL(url, `file://${process.cwd()}/`); // if absolute path is provided use that; otherwise search cwd\
const localPath = path.isAbsolute(url)
? new URL("", `file://${slash(url)}`)
: new URL(url, `file://${slash(process.cwd())}/`); // if absolute path is provided use that; otherwise search cwd\
if (!fs.existsSync(localPath)) {

@@ -53,3 +59,3 @@ throw new Error(`Could not locate ${url}`);

rootURL: URL;
schemas: { [url: string]: PartialSchema };
schemas: SchemaMap;
}

@@ -61,42 +67,57 @@

/** Load a schema from local path or remote URL */
export default async function load(schemaURL: URL, options: LoadOptions): Promise<{ [url: string]: PartialSchema }> {
if (urlCache.has(schemaURL.href)) return options.schemas; // exit early if this has already been scanned
urlCache.add(schemaURL.href); // add URL to cache
export default async function load(
schema: URL | PartialSchema,
options: LoadOptions
): Promise<{ [url: string]: PartialSchema }> {
const isJSON = schema instanceof URL === false; // if this is dynamically-passed-in JSON, we’ll have to change a few things
let schemaID = isJSON ? new URL(VIRTUAL_JSON_URL).href : schema.href;
const schemas = options.schemas;
let contents = "";
let contentType = "";
if (isFile(schemaURL)) {
// load local
contents = await fs.promises.readFile(schemaURL, "utf8");
contentType = mime.getType(schemaURL.href) || "";
} else {
// load remote
const headers = new Headers();
if (options.auth) headers.set("Authorization", options.auth);
const res = await fetch(schemaURL.href, { method: "GET", headers });
contentType = res.headers.get("Content-Type") || "";
contents = await res.text();
// scenario 1: load schema from dynamic JSON
if (isJSON) {
schemas[schemaID] = schema;
}
// scenario 2: fetch schema from URL (local or remote)
else {
if (urlCache.has(schemaID)) return options.schemas; // exit early if this has already been scanned
urlCache.add(schemaID); // add URL to cache
const isYAML = contentType === "application/openapi+yaml" || contentType === "text/yaml";
const isJSON =
contentType === "application/json" ||
contentType === "application/json5" ||
contentType === "application/openapi+json";
if (isYAML) {
schemas[schemaURL.href] = parseSchema(contents, "YAML");
} else if (isJSON) {
schemas[schemaURL.href] = parseSchema(contents, "JSON");
} else {
// if contentType is unknown, guess
try {
schemas[schemaURL.href] = parseSchema(contents, "JSON");
} catch (err1) {
let contents = "";
let contentType = "";
const schemaURL = schema as URL; // helps TypeScript
if (isFile(schemaURL)) {
// load local
contents = await fs.promises.readFile(schemaURL, "utf8");
contentType = mime.getType(schemaID) || "";
} else {
// load remote
const headers = new Headers();
headers.set("User-Agent", "openapi-typescript");
if (options.auth) headers.set("Authorization", options.auth);
const res = await fetch(schemaID, { method: "GET", headers });
contentType = res.headers.get("Content-Type") || "";
contents = await res.text();
}
const isYAML = contentType === "application/openapi+yaml" || contentType === "text/yaml";
const isJSON =
contentType === "application/json" ||
contentType === "application/json5" ||
contentType === "application/openapi+json";
if (isYAML) {
schemas[schemaID] = parseSchema(contents, "YAML");
} else if (isJSON) {
schemas[schemaID] = parseSchema(contents, "JSON");
} else {
// if contentType is unknown, guess
try {
schemas[schemaURL.href] = parseSchema(contents, "YAML");
} catch (err2) {
throw new Error(`Unknown format${contentType ? `: "${contentType}"` : ""}. Only YAML or JSON supported.`); // give up: unknown type
schemas[schemaID] = parseSchema(contents, "JSON");
} catch (err1) {
try {
schemas[schemaID] = parseSchema(contents, "YAML");
} catch (err2) {
throw new Error(`Unknown format${contentType ? `: "${contentType}"` : ""}. Only YAML or JSON supported.`); // give up: unknown type
}
}

@@ -108,3 +129,3 @@ }

const refPromises: Promise<any>[] = [];
schemas[schemaURL.href] = JSON.parse(JSON.stringify(schemas[schemaURL.href]), (k, v) => {
schemas[schemaID] = JSON.parse(JSON.stringify(schemas[schemaID]), (k, v) => {
if (k !== "$ref" || typeof v !== "string") return v;

@@ -115,4 +136,10 @@

// load $refs (only if new) and merge subschemas with top-level schema
const nextURL =
refURL.startsWith("http://") || refURL.startsWith("https://") ? new URL(refURL) : new URL(refURL, schemaURL);
const isRemoteURL = refURL.startsWith("http://") || refURL.startsWith("https://");
// if this is dynamic JSON, we have no idea how to resolve relative URLs, so throw here
if (isJSON && !isRemoteURL) {
throw new Error(`Can’t load URL "${refURL}" from dynamic JSON. Load this schema from a URL instead.`);
}
const nextURL = isRemoteURL ? new URL(refURL) : new URL(slash(refURL), schema as URL);
refPromises.push(

@@ -132,3 +159,3 @@ load(nextURL, options).then((subschemas) => {

// transform $refs once, at the root schema, after all have been scanned & downloaded (much easier to do here when we have the context)
if (schemaURL.href === options.rootURL.href) {
if (schemaID === options.rootURL.href) {
for (const subschemaURL of Object.keys(schemas)) {

@@ -135,0 +162,0 @@ // transform $refs in schema

@@ -40,2 +40,15 @@ import { GlobalContext } from "../types";

/** make sure all required fields exist **/
export function addRequiredProps(properties: Record<string, any>, required: Set<string>): string[] {
const missingRequired = [...required].filter((r: string) => !(r in properties));
if (missingRequired.length == 0) {
return [];
}
let output = "";
for (const r of missingRequired) {
output += `${r}: unknown;\n`;
}
return [`{\n${output}}`];
}
/** transform anyOf */

@@ -103,3 +116,3 @@ export function transformAnyOf(anyOf: any, options: TransformSchemaObjOptions): string {

const isAnyOfOrOneOfOrAllOf = "anyOf" in node || "oneOf" in node || "allOf" in node;
const missingRequired = addRequiredProps(node.properties || {}, node.required || []);
// if empty object, then return generic map type

@@ -111,3 +124,5 @@ if (

) {
output += `{ ${readonly}[key: string]: any }`;
const emptyObj = `{ ${readonly}[key: string]: unknown }`;
output += tsIntersectionOf([emptyObj, ...missingRequired]);
break;

@@ -150,2 +165,3 @@ }

...(properties ? [`{\n${properties}\n}`] : []), // then properties (line breaks are important!)
...missingRequired, // add required that are missing from properties
...(additionalProperties ? [additionalProperties] : []), // then additional properties

@@ -152,0 +168,0 @@ ]);

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc