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 6.5.0 to 6.5.1

6

CHANGELOG.md
# openapi-typescript
## 6.5.1
### Patch Changes
- [#1308](https://github.com/drwpow/openapi-typescript/pull/1308) [`ebb73b6`](https://github.com/drwpow/openapi-typescript/commit/ebb73b68c3a2f9a8c8193888735f9c0b7855722f) Thanks [@drwpow](https://github.com/drwpow)! - Fix bugs with remote $refs, add `cwd` option for JSON schema parsing
## 6.5.0

@@ -4,0 +10,0 @@

26

dist/index.js

@@ -25,2 +25,3 @@ import { URL } from "node:url";

alphabetize: options.alphabetize ?? false,
cwd: options.cwd ?? new URL(`file://${process.cwd()}/`),
defaultNonNullable: options.defaultNonNullable ?? false,

@@ -40,5 +41,20 @@ discriminators: {},

};
const isInlineSchema = typeof schema !== "string" && schema instanceof URL === false;
const allSchemas = {};
const schemaURL = typeof schema === "string" ? resolveSchema(schema) : schema;
let rootURL = schemaURL;
const isInlineSchema = typeof schema !== "string" && schema instanceof URL === false;
if (isInlineSchema) {
if (ctx.cwd) {
if (ctx.cwd instanceof URL) {
rootURL = ctx.cwd;
}
else if (typeof ctx.cwd === "string") {
rootURL = new URL(ctx.cwd, `file://${process.cwd()}/`);
}
rootURL = new URL("root.yaml", rootURL);
}
else {
rootURL = new URL(VIRTUAL_JSON_URL);
}
}
await load(schemaURL, {

@@ -48,3 +64,3 @@ ...ctx,

schemas: allSchemas,
rootURL: isInlineSchema ? new URL(VIRTUAL_JSON_URL) : schemaURL,
rootURL,
urlCache: new Set(),

@@ -170,2 +186,6 @@ httpHeaders: options.httpHeaders,

}
if ("in" in schemaObject) {
subschemaOutput += indent(`${escObjKey(name)}: ${transformParameterObject(schemaObject, { path: `${path}${name}`, ctx: { ...ctx, indentLv } })};\n`, indentLv);
continue;
}
subschemaOutput += indent(`${escObjKey(name)}: ${transformSchemaObject(schemaObject, { path: `${path}${name}`, ctx: { ...ctx, indentLv } })};\n`, indentLv);

@@ -178,3 +198,3 @@ }

case "SchemaObject": {
subschemaOutput = transformSchemaObject(subschema.schema, { path, ctx: { ...ctx, indentLv } });
subschemaOutput = `${transformSchemaObject(subschema.schema, { path, ctx: { ...ctx, indentLv } })};`;
break;

@@ -181,0 +201,0 @@ }

37

dist/load.js

@@ -7,3 +7,3 @@ import fs from "node:fs";

import { parseRef, error, makeTSIndex, walk, isRemoteURL, isFilepath } from "./utils.js";
const EXT_RE = /\.(yaml|yml|json)$/i;
const EXT_RE = /\.(yaml|yml|json)#?\/?/i;
export const VIRTUAL_JSON_URL = `file:///_json`;

@@ -54,3 +54,3 @@ function parseYAML(schema) {

catch (err) {
error(`Cannot parse key: ${k} into JSON format. Continuing with the next HTTP header that is specified`);
error(`Can’t parse key: ${k} into JSON format. Continuing with the next HTTP header that is specified`);
}

@@ -65,6 +65,8 @@ }

const hint = options.hint ?? "OpenAPI3";
if (schema.href !== options.rootURL.href)
if (schema.href !== options.rootURL.href) {
schemaID = relativePath(options.rootURL, schema);
if (options.urlCache.has(schemaID))
}
if (options.urlCache.has(schemaID)) {
return options.schemas;
}
options.urlCache.add(schemaID);

@@ -102,3 +104,3 @@ const ext = path.extname(schema.pathname).toLowerCase();

const contents = fs.readFileSync(schema, "utf8");
if (ext === ".yaml" || ext === ".yml")
if (ext === ".yaml" || ext === ".yml") {
options.schemas[schemaID] = {

@@ -108,3 +110,4 @@ hint,

};
else if (ext === ".json")
}
else if (ext === ".json") {
options.schemas[schemaID] = {

@@ -114,2 +117,3 @@ hint,

};
}
}

@@ -183,15 +187,4 @@ }

const hint = isRemoteFullSchema ? "OpenAPI3" : getHint({ path: hintPath, external: !!ref.filename, startFrom: options.hint });
if (schema instanceof URL) {
const nextURL = new URL(ref.filename, schema);
const nextID = relativePath(schema, nextURL);
if (options.urlCache.has(nextID))
return;
refPromises.push(load(nextURL, { ...options, hint }));
node.$ref = node.$ref.replace(ref.filename, nextID);
return;
}
if (isRemoteURL(ref.filename) || isFilepath(ref.filename)) {
const nextURL = new URL(ref.filename.startsWith("//") ? `https://${ref.filename}` : ref.filename);
if (options.urlCache.has(nextURL.href))
return;
refPromises.push(load(nextURL, { ...options, hint }));

@@ -202,7 +195,9 @@ node.$ref = node.$ref.replace(ref.filename, nextURL.href);

if (options.rootURL.href === VIRTUAL_JSON_URL) {
error(`Can’t resolve "${ref.filename}" from dynamic JSON. Load this schema from a URL instead.`);
error(`Can’t resolve "${ref.filename}" from dynamic JSON. Either load this schema from a filepath/URL, or set the \`cwd\` option: \`openapiTS(schema, { cwd: '/path/to/cwd' })\`.`);
process.exit(1);
}
error(`Can’t resolve "${ref.filename}"`);
process.exit(1);
const nextURL = new URL(ref.filename, schema instanceof URL ? schema : options.rootURL);
const nextID = relativePath(schema instanceof URL ? schema : options.rootURL, nextURL);
refPromises.push(load(nextURL, { ...options, hint }));
node.$ref = node.$ref.replace(ref.filename, nextID);
});

@@ -269,2 +264,4 @@ await Promise.all(refPromises);

return getHintFromResponseObject(path, external);
case "SchemaMap":
return "SchemaObject";
default:

@@ -271,0 +268,0 @@ return startFrom;

/// <reference types="node" resolution-mode="require"/>
import type { URL } from "node:url";
import type { PathLike } from "node:fs";
import type { RequestInfo, RequestInit, Response } from "undici";

@@ -308,3 +308,3 @@ import type { TransformSchemaObjectOptions } from "./transform/schema-object.js";

emptyObjectsUnknown?: boolean;
cwd?: URL;
cwd?: PathLike;
defaultNonNullable?: boolean;

@@ -363,2 +363,3 @@ transform?: (schemaObject: SchemaObject, options: TransformSchemaObjectOptions) => string | undefined;

alphabetize: boolean;
cwd?: PathLike;
emptyObjectsUnknown: boolean;

@@ -365,0 +366,0 @@ defaultNonNullable: boolean;

{
"name": "openapi-typescript",
"description": "Generate TypeScript types from Swagger OpenAPI specs",
"version": "6.5.0",
"description": "Generate runtime-free TypeScript types from Swagger OpenAPI specs",
"version": "6.5.1",
"author": {

@@ -53,6 +53,6 @@ "name": "Drew Powers",

"@types/js-yaml": "^4.0.5",
"@types/node": "^20.4.9",
"@types/node": "^20.5.0",
"degit": "^2.8.4",
"del-cli": "^5.0.0",
"esbuild": "^0.19.0",
"esbuild": "^0.19.2",
"execa": "^7.2.0",

@@ -59,0 +59,0 @@ "vite": "^4.4.9",

@@ -7,3 +7,3 @@ <img src="../../docs/public/assets/openapi-ts.svg" alt="openapi-typescript" width="200" height="40" />

**Features**
## Features

@@ -15,8 +15,20 @@ - ✅ Supports OpenAPI 3.0 and 3.1 (including advanced features like <a href="https://spec.openapis.org/oas/v3.1.0#discriminator-object" target="_blank" rel="noopener noreferrer">discriminators</a>)

**Examples**
## Examples
👀 [See examples](./examples/)
## Usage
## Setup
This library requires the latest version of <a href="https://nodejs.org/en" target="_blank" rel="noopener noreferrer">Node.js</a> installed (20.x or higher recommended). With that present, run the following in your project:
```bash
npm i -D openapi-typescript
```
> ✨ **Tip**
>
> Enabling [noUncheckedIndexedAccess](https://www.typescriptlang.org/tsconfig#noUncheckedIndexedAccess) in `tsconfig.json` can go along way to improve type safety ([read more](/advanced#enable-nouncheckedindexaccess-in-your-tsconfigjson))
## Basic usage
First, generate a local type file by running `npx openapi-typescript`:

@@ -23,0 +35,0 @@

@@ -1,2 +0,2 @@

import type { GlobalContext, OpenAPI3, OpenAPITSOptions, SchemaObject, Subschema } from "./types.js";
import type { GlobalContext, OpenAPI3, OpenAPITSOptions, ParameterObject, SchemaObject, Subschema } from "./types.js";
import type { Readable } from "node:stream";

@@ -43,2 +43,3 @@ import { URL } from "node:url";

alphabetize: options.alphabetize ?? false,
cwd: options.cwd ?? new URL(`file://${process.cwd()}/`),
defaultNonNullable: options.defaultNonNullable ?? false,

@@ -59,8 +60,22 @@ discriminators: {},

// note: we may be loading many large schemas into memory at once; take care to reuse references without cloning
const isInlineSchema = typeof schema !== "string" && schema instanceof URL === false; // eslint-disable-line @typescript-eslint/no-unnecessary-boolean-literal-compare
// 1. load schema (and subschemas)
const allSchemas: { [id: string]: Subschema } = {};
const schemaURL: URL = typeof schema === "string" ? resolveSchema(schema) : (schema as URL);
let rootURL: URL = schemaURL;
// 1a. if passed as in-memory JSON, handle `cwd` option
const isInlineSchema = typeof schema !== "string" && schema instanceof URL === false; // eslint-disable-line @typescript-eslint/no-unnecessary-boolean-literal-compare
if (isInlineSchema) {
if (ctx.cwd) {
if (ctx.cwd instanceof URL) {
rootURL = ctx.cwd;
} else if (typeof ctx.cwd === "string") {
rootURL = new URL(ctx.cwd, `file://${process.cwd()}/`);
}
rootURL = new URL("root.yaml", rootURL); // give the root schema an arbitrary filename ("root.yaml")
} else {
rootURL = new URL(VIRTUAL_JSON_URL); // otherwise, set virtual filename (which prevents resolutions)
}
}
await load(schemaURL, {

@@ -70,3 +85,3 @@ ...ctx,

schemas: allSchemas,
rootURL: isInlineSchema ? new URL(VIRTUAL_JSON_URL) : schemaURL, // if an inline schema is passed, use virtual URL
rootURL,
urlCache: new Set(),

@@ -191,3 +206,3 @@ httpHeaders: options.httpHeaders,

// This might be a Path Item Object; only way to test is if top-level contains a method (not allowed on Schema Object)
// Test for Path Item Object
if (!("type" in schemaObject) && !("$ref" in schemaObject)) {

@@ -201,2 +216,7 @@ for (const method of ["get", "put", "post", "delete", "options", "head", "patch", "trace"] as Method[]) {

}
// Test for Parameter
if ("in" in schemaObject) {
subschemaOutput += indent(`${escObjKey(name)}: ${transformParameterObject(schemaObject as ParameterObject, { path: `${path}${name}`, ctx: { ...ctx, indentLv } })};\n`, indentLv);
continue;
}

@@ -212,3 +232,3 @@ // Otherwise, this is a Schema Object

case "SchemaObject": {
subschemaOutput = transformSchemaObject(subschema.schema, { path, ctx: { ...ctx, indentLv } });
subschemaOutput = `${transformSchemaObject(subschema.schema, { path, ctx: { ...ctx, indentLv } })};`;
break;

@@ -215,0 +235,0 @@ }

@@ -14,3 +14,3 @@ import type { ComponentsObject, Fetch, GlobalContext, OpenAPI3, OperationObject, ParameterObject, PathItemObject, ReferenceObject, RequestBodyObject, ResponseObject, SchemaObject, Subschema } from "./types.js";

const EXT_RE = /\.(yaml|yml|json)$/i;
const EXT_RE = /\.(yaml|yml|json)#?\/?/i;
export const VIRTUAL_JSON_URL = `file:///_json`; // fake URL reserved for dynamic JSON

@@ -73,3 +73,3 @@

} catch (err) {
error(`Cannot parse key: ${k} into JSON format. Continuing with the next HTTP header that is specified`);
error(`Can’t parse key: ${k} into JSON format. Continuing with the next HTTP header that is specified`);
}

@@ -104,5 +104,9 @@ }

// normalize ID
if (schema.href !== options.rootURL.href) schemaID = relativePath(options.rootURL, schema);
if (schema.href !== options.rootURL.href) {
schemaID = relativePath(options.rootURL, schema);
}
if (options.urlCache.has(schemaID)) return options.schemas; // exit early if already indexed
if (options.urlCache.has(schemaID)) {
return options.schemas; // exit early if already indexed
}
options.urlCache.add(schemaID);

@@ -144,3 +148,3 @@

const contents = fs.readFileSync(schema, "utf8");
if (ext === ".yaml" || ext === ".yml")
if (ext === ".yaml" || ext === ".yml") {
options.schemas[schemaID] = {

@@ -150,3 +154,3 @@ hint,

};
else if (ext === ".json")
} else if (ext === ".json") {
options.schemas[schemaID] = {

@@ -156,2 +160,3 @@ hint,

};
}
}

@@ -234,15 +239,4 @@ }

// if root schema is remote and this is a relative reference, treat as remote
if (schema instanceof URL) {
const nextURL = new URL(ref.filename, schema);
const nextID = relativePath(schema, nextURL);
if (options.urlCache.has(nextID)) return;
refPromises.push(load(nextURL, { ...options, hint }));
node.$ref = node.$ref.replace(ref.filename, nextID);
return;
}
// otherwise, if $ref is remote use that
if (isRemoteURL(ref.filename) || isFilepath(ref.filename)) {
const nextURL = new URL(ref.filename.startsWith("//") ? `https://${ref.filename}` : ref.filename);
if (options.urlCache.has(nextURL.href)) return;
refPromises.push(load(nextURL, { ...options, hint }));

@@ -252,9 +246,13 @@ node.$ref = node.$ref.replace(ref.filename, nextURL.href);

}
// if this is dynamic JSON, we have no idea how to resolve external URLs, so throw here
// if this is dynamic JSON (with no cwd), we have no idea how to resolve external URLs, so throw here
if (options.rootURL.href === VIRTUAL_JSON_URL) {
error(`Can’t resolve "${ref.filename}" from dynamic JSON. Load this schema from a URL instead.`);
error(`Can’t resolve "${ref.filename}" from dynamic JSON. Either load this schema from a filepath/URL, or set the \`cwd\` option: \`openapiTS(schema, { cwd: '/path/to/cwd' })\`.`);
process.exit(1);
}
error(`Can’t resolve "${ref.filename}"`);
process.exit(1);
const nextURL = new URL(ref.filename, schema instanceof URL ? schema : options.rootURL);
const nextID = relativePath(schema instanceof URL ? schema : options.rootURL, nextURL);
refPromises.push(load(nextURL, { ...options, hint }));
node.$ref = node.$ref.replace(ref.filename, nextID);
});

@@ -333,3 +331,8 @@ await Promise.all(refPromises);

/** given a path array (an array of indices), what type of object is this? */
/**
* Hinting
* A remote `$ref` may point to anything—A full OpenAPI schema, partial OpenAPI schema, Schema Object, Parameter Object, etc.
* The only way to parse its contents correctly is to trace the path from the root schema and infer the type it should be.
* “Hinting” is the process of tracing its lineage back to the root schema to invoke the correct transformations on it.
*/
export function getHint({ path, external, startFrom }: GetHintOptions): Subschema["hint"] | undefined {

@@ -344,2 +347,4 @@ if (startFrom && startFrom !== "OpenAPI3") {

return getHintFromResponseObject(path, external);
case "SchemaMap":
return "SchemaObject";
default:

@@ -346,0 +351,0 @@ return startFrom;

@@ -1,2 +0,2 @@

import type { URL } from "node:url";
import type { PathLike } from "node:fs";
import type { RequestInfo, RequestInit, Response } from "undici";

@@ -617,3 +617,3 @@ import type { TransformSchemaObjectOptions } from "./transform/schema-object.js";

/** Specify current working directory (cwd) to resolve remote schemas on disk (not needed for remote URL schemas) */
cwd?: URL;
cwd?: PathLike;
/** Should schema objects with a default value not be considered optional? */

@@ -689,2 +689,3 @@ defaultNonNullable?: boolean;

alphabetize: boolean;
cwd?: PathLike;
emptyObjectsUnknown: boolean;

@@ -691,0 +692,0 @@ defaultNonNullable: boolean;

@@ -5,3 +5,4 @@ {

"sourceRoot": ".",
"outDir": "dist"
"outDir": "dist",
"types": ["vitest/globals"]
},

@@ -8,0 +9,0 @@ "include": ["scripts", "src", "test", "*.ts"],

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