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 7.0.0-next.8 to 7.0.0-next.9

2

CHANGELOG.md

@@ -82,2 +82,4 @@ # openapi-typescript

- [#1602](https://github.com/drwpow/openapi-typescript/pull/1602) [`9da96cd`](https://github.com/drwpow/openapi-typescript/commit/9da96cda4eb8f959c4703637d8fc89e1d3532af1) Thanks [@JeanRemiDelteil](https://github.com/JeanRemiDelteil)! - Do not add readonly on Typescript enum when the --immutable option is used.
## 6.7.0

@@ -84,0 +86,0 @@

1

dist/lib/ts.d.ts

@@ -42,3 +42,2 @@ import ts from "typescript";

}[], options?: {
readonly?: boolean;
export?: boolean;

@@ -45,0 +44,0 @@ }): ts.EnumDeclaration;

@@ -130,6 +130,3 @@ import { parseRef } from "@redocly/openapi-core/lib/ref-utils.js";

return ts.factory.createEnumDeclaration(options
? tsModifiers({
readonly: options.readonly ?? false,
export: options.export ?? false,
})
? tsModifiers({ export: options.export ?? false })
: undefined, enumName, members.map((value, i) => tsEnumMember(value, metadata?.[i])));

@@ -143,2 +140,5 @@ }

}
else if (name[0] === "-") {
name = `ValueMinus${name.slice(1)}`;
}
name = name.replace(JS_PROPERTY_INDEX_INVALID_CHARS_RE, "_");

@@ -148,3 +148,6 @@ }

if (typeof value === "number") {
member = ts.factory.createEnumMember(name, ts.factory.createNumericLiteral(value));
const literal = value < 0
? ts.factory.createPrefixUnaryExpression(ts.SyntaxKind.MinusToken, ts.factory.createNumericLiteral(Math.abs(value)))
: ts.factory.createNumericLiteral(value);
member = ts.factory.createEnumMember(name, literal);
}

@@ -151,0 +154,0 @@ else {

@@ -124,2 +124,35 @@ import { escapePointer, parseRef, } from "@redocly/openapi-core/lib/ref-utils.js";

}
function patchDiscriminatorEnum(schema, ref, values, discriminator, discriminatorRef, options) {
const resolvedSchema = resolveRef(schema, ref, {
silent: options.silent ?? false,
});
if (resolvedSchema?.allOf) {
resolvedSchema.allOf.push({
type: "object",
required: [discriminator.propertyName],
properties: {
[discriminator.propertyName]: createDiscriminatorEnum(values),
},
});
return true;
}
else if (typeof resolvedSchema === "object" &&
"type" in resolvedSchema &&
resolvedSchema.type === "object") {
if (!resolvedSchema.properties) {
resolvedSchema.properties = {};
}
if (!resolvedSchema.required) {
resolvedSchema.required = [discriminator.propertyName];
}
else if (!resolvedSchema.required.includes(discriminator.propertyName)) {
resolvedSchema.required.push(discriminator.propertyName);
}
resolvedSchema.properties[discriminator.propertyName] =
createDiscriminatorEnum(values, resolvedSchema.properties[discriminator.propertyName]);
return true;
}
warn(`Discriminator mapping has an invalid schema (neither an object schema nor an allOf array): ${ref} => ${values.join(", ")} (Discriminator: ${discriminatorRef})`, options.silent);
return false;
}
export function scanDiscriminators(schema, options) {

@@ -173,53 +206,38 @@ const objects = {};

const mappedValues = defined ?? [inferred];
const resolvedSchema = resolveRef(schema, mappedRef, {
silent: options.silent ?? false,
});
if (resolvedSchema?.allOf) {
resolvedSchema.allOf.push({
type: "object",
required: [discriminator.propertyName],
properties: {
[discriminator.propertyName]: createDiscriminatorEnum(mappedValues),
},
});
if (patchDiscriminatorEnum(schema, mappedRef, mappedValues, discriminator, ref, options)) {
refsHandled.push(mappedRef);
}
else if (typeof resolvedSchema === "object" &&
"type" in resolvedSchema &&
resolvedSchema.type === "object") {
if (!resolvedSchema.properties) {
resolvedSchema.properties = {};
}
if (!resolvedSchema.required) {
resolvedSchema.required = [discriminator.propertyName];
}
else if (!resolvedSchema.required.includes(discriminator.propertyName)) {
resolvedSchema.required.push(discriminator.propertyName);
}
resolvedSchema.properties[discriminator.propertyName] =
createDiscriminatorEnum(mappedValues, resolvedSchema.properties[discriminator.propertyName]);
refsHandled.push(mappedRef);
}
else {
warn(`Discriminator mapping has an invalid schema (neither an object schema nor an allOf array): ${mappedRef} => ${mappedValues.join(", ")} (Discriminator: ${ref})`, options.silent);
continue;
}
}
});
walk(schema, (obj, path) => {
for (const key of ["oneOf", "anyOf", "allOf"]) {
if (obj && Array.isArray(obj[key])) {
for (const item of obj[key]) {
if ("$ref" in item) {
if (objects[item.$ref]) {
objects[createRef(path)] = {
...objects[item.$ref],
};
if (!obj || !Array.isArray(obj.allOf)) {
return;
}
for (const item of obj.allOf) {
if ("$ref" in item) {
if (!objects[item.$ref]) {
return;
}
const ref = createRef(path);
const discriminator = objects[item.$ref];
const mappedValues = [];
if (discriminator.mapping) {
for (const mappedValue in discriminator.mapping) {
if (discriminator.mapping[mappedValue] === ref) {
mappedValues.push(mappedValue);
}
}
else if (item.discriminator?.propertyName) {
objects[createRef(path)] = { ...item.discriminator };
if (mappedValues.length > 0) {
if (patchDiscriminatorEnum(schema, ref, mappedValues, discriminator, item.$ref, options)) {
refsHandled.push(ref);
}
}
}
objects[ref] = {
...objects[item.$ref],
};
}
else if (item.discriminator?.propertyName) {
objects[createRef(path)] = { ...item.discriminator };
}
}

@@ -226,0 +244,0 @@ });

@@ -45,3 +45,5 @@ import { parseRef } from "@redocly/openapi-core/lib/ref-utils.js";

}));
const enumType = tsEnum(enumName, schemaObject.enum, metadata, { export: true, readonly: options.ctx.immutable });
const enumType = tsEnum(enumName, schemaObject.enum, metadata, {
export: true,
});
options.ctx.injectFooter.push(enumType);

@@ -52,5 +54,12 @@ return ts.factory.createTypeReferenceNode(enumType.name);

}
function collectCompositions(items, required) {
function collectUnionCompositions(items) {
const output = [];
for (const item of items) {
output.push(transformSchemaObject(item, options));
}
return output;
}
function collectAllOfCompositions(items, required) {
const output = [];
for (const item of items) {
let itemType;

@@ -62,8 +71,7 @@ if ("$ref" in item) {

typeof resolved === "object" &&
"properties" in resolved) {
if (!options.ctx.discriminators.refsHandled.includes(item.$ref)) {
const validRequired = (required ?? []).filter((key) => !!resolved.properties[key]);
if (validRequired.length) {
itemType = tsWithRequired(itemType, validRequired, options.ctx.injectFooter);
}
"properties" in resolved &&
!options.ctx.discriminators.refsHandled.includes(item.$ref)) {
const validRequired = (required ?? []).filter((key) => !!resolved.properties[key]);
if (validRequired.length) {
itemType = tsWithRequired(itemType, validRequired, options.ctx.injectFooter);
}

@@ -92,3 +100,3 @@ }

const coreObjectType = transformSchemaObjectCore(schemaObject, options);
const allOfType = collectCompositions(schemaObject.allOf ?? [], schemaObject.required);
const allOfType = collectAllOfCompositions(schemaObject.allOf ?? [], schemaObject.required);
if (coreObjectType || allOfType.length) {

@@ -103,11 +111,11 @@ const allOf = allOfType.length

}
const anyOfType = collectCompositions(schemaObject.anyOf ?? [], schemaObject.required);
const anyOfType = collectUnionCompositions(schemaObject.anyOf ?? []);
if (anyOfType.length) {
finalType = tsUnion([...(finalType ? [finalType] : []), ...anyOfType]);
}
const oneOfType = collectCompositions(schemaObject.oneOf ||
const oneOfType = collectUnionCompositions(schemaObject.oneOf ||
("type" in schemaObject &&
schemaObject.type === "object" &&
schemaObject.enum) ||
[], schemaObject.required);
[]);
if (oneOfType.length) {

@@ -229,3 +237,3 @@ if (oneOfType.every(tsIsPrimitive)) {

const coreObjectType = [];
for (const k of ["oneOf", "allOf", "anyOf"]) {
for (const k of ["allOf", "anyOf"]) {
if (!schemaObject[k]) {

@@ -235,2 +243,3 @@ continue;

const discriminator = !schemaObject.discriminator &&
!options.ctx.discriminators.refsHandled.includes(options.path) &&
options.ctx.discriminators.objects[options.path];

@@ -237,0 +246,0 @@ if (discriminator) {

{
"name": "openapi-typescript",
"description": "Convert OpenAPI 3.0 & 3.1 schemas to TypeScript",
"version": "7.0.0-next.8",
"version": "7.0.0-next.9",
"author": {

@@ -65,3 +65,3 @@ "name": "Drew Powers",

"dependencies": {
"@redocly/openapi-core": "^1.10.3",
"@redocly/openapi-core": "^1.11.0",
"ansi-colors": "^4.1.3",

@@ -74,11 +74,11 @@ "supports-color": "^9.4.0",

"@types/js-yaml": "^4.0.9",
"@types/node": "^20.11.24",
"@types/node": "^20.12.7",
"degit": "^2.8.4",
"del-cli": "^5.1.0",
"esbuild": "^0.20.1",
"esbuild": "^0.20.2",
"execa": "^7.2.0",
"typescript": "^5.3.3",
"vite-node": "^1.3.1",
"vitest": "^1.3.1"
"typescript": "^5.4.5",
"vite-node": "^1.5.0",
"vitest": "^1.5.0"
}
}

@@ -233,3 +233,3 @@ import { parseRef } from "@redocly/openapi-core/lib/ref-utils.js";

metadata?: { name?: string; description?: string }[],
options?: { readonly?: boolean; export?: boolean },
options?: { export?: boolean },
) {

@@ -248,6 +248,3 @@ let enumName = name.replace(JS_ENUM_INVALID_CHARS_RE, (c) => {

/* modifiers */ options
? tsModifiers({
readonly: options.readonly ?? false,
export: options.export ?? false,
})
? tsModifiers({ export: options.export ?? false })
: undefined,

@@ -270,2 +267,4 @@ /* name */ enumName,

name = `Value${name}`.replace(".", "_"); // don't forged decimals;
} else if (name[0] === "-") {
name = `ValueMinus${name.slice(1)}`;
}

@@ -277,6 +276,11 @@ name = name.replace(JS_PROPERTY_INDEX_INVALID_CHARS_RE, "_");

if (typeof value === "number") {
member = ts.factory.createEnumMember(
name,
ts.factory.createNumericLiteral(value),
);
const literal =
value < 0
? ts.factory.createPrefixUnaryExpression(
ts.SyntaxKind.MinusToken,
ts.factory.createNumericLiteral(Math.abs(value)),
)
: ts.factory.createNumericLiteral(value);
member = ts.factory.createEnumMember(name, literal);
} else {

@@ -283,0 +287,0 @@ member = ts.factory.createEnumMember(

@@ -187,2 +187,64 @@ import {

/** Adds or replaces the discriminator enum with the passed `values` in a schema defined by `ref` */
function patchDiscriminatorEnum(
schema: SchemaObject,
ref: string,
values: string[],
discriminator: DiscriminatorObject,
discriminatorRef: string,
options: OpenAPITSOptions,
): boolean {
const resolvedSchema = resolveRef<SchemaObject>(schema, ref, {
silent: options.silent ?? false,
});
if (resolvedSchema?.allOf) {
// if the schema is an allOf, we can append a new schema object to the allOf array
resolvedSchema.allOf.push({
type: "object",
// discriminator enum properties always need to be required
required: [discriminator.propertyName],
properties: {
[discriminator.propertyName]: createDiscriminatorEnum(values),
},
});
return true;
} else if (
typeof resolvedSchema === "object" &&
"type" in resolvedSchema &&
resolvedSchema.type === "object"
) {
// if the schema is an object, we can apply the discriminator enums to its properties
if (!resolvedSchema.properties) {
resolvedSchema.properties = {};
}
// discriminator enum properties always need to be required
if (!resolvedSchema.required) {
resolvedSchema.required = [discriminator.propertyName];
} else if (!resolvedSchema.required.includes(discriminator.propertyName)) {
resolvedSchema.required.push(discriminator.propertyName);
}
// add/replace the discriminator enum property
resolvedSchema.properties[discriminator.propertyName] =
createDiscriminatorEnum(
values,
resolvedSchema.properties[discriminator.propertyName],
);
return true;
}
warn(
`Discriminator mapping has an invalid schema (neither an object schema nor an allOf array): ${ref} => ${values.join(
", ",
)} (Discriminator: ${discriminatorRef})`,
options.silent,
);
return false;
}
type InternalDiscriminatorMapping = Record<

@@ -271,53 +333,14 @@ string,

const mappedValues = defined ?? [inferred!];
const resolvedSchema = resolveRef<SchemaObject>(schema, mappedRef, {
silent: options.silent ?? false,
});
if (resolvedSchema?.allOf) {
// if the schema is an allOf, we can append a new schema object to the allOf array
resolvedSchema.allOf.push({
type: "object",
// discriminator enum properties always need to be required
required: [discriminator.propertyName],
properties: {
[discriminator.propertyName]: createDiscriminatorEnum(mappedValues),
},
});
refsHandled.push(mappedRef);
} else if (
typeof resolvedSchema === "object" &&
"type" in resolvedSchema &&
resolvedSchema.type === "object"
if (
patchDiscriminatorEnum(
schema,
mappedRef,
mappedValues,
discriminator,
ref,
options,
)
) {
// if the schema is an object, we can apply the discriminator enums to its properties
if (!resolvedSchema.properties) {
resolvedSchema.properties = {};
}
// discriminator enum properties always need to be required
if (!resolvedSchema.required) {
resolvedSchema.required = [discriminator.propertyName];
} else if (
!resolvedSchema.required.includes(discriminator.propertyName)
) {
resolvedSchema.required.push(discriminator.propertyName);
}
// add/replace the discriminator enum property
resolvedSchema.properties[discriminator.propertyName] =
createDiscriminatorEnum(
mappedValues,
resolvedSchema.properties[discriminator.propertyName],
);
refsHandled.push(mappedRef);
} else {
warn(
`Discriminator mapping has an invalid schema (neither an object schema nor an allOf array): ${mappedRef} => ${mappedValues.join(
", ",
)} (Discriminator: ${ref})`,
options.silent,
);
continue;
}

@@ -331,15 +354,44 @@ }

walk(schema, (obj, path) => {
for (const key of ["oneOf", "anyOf", "allOf"] as const) {
if (obj && Array.isArray(obj[key])) {
for (const item of (obj as any)[key]) {
if ("$ref" in item) {
if (objects[item.$ref]) {
objects[createRef(path)] = {
...objects[item.$ref],
};
if (!obj || !Array.isArray(obj.allOf)) {
return;
}
for (const item of (obj as any).allOf) {
if ("$ref" in item) {
if (!objects[item.$ref]) {
return;
}
const ref = createRef(path);
const discriminator = objects[item.$ref];
const mappedValues: string[] = [];
if (discriminator.mapping) {
for (const mappedValue in discriminator.mapping) {
if (discriminator.mapping[mappedValue] === ref) {
mappedValues.push(mappedValue);
}
} else if (item.discriminator?.propertyName) {
objects[createRef(path)] = { ...item.discriminator };
}
if (mappedValues.length > 0) {
if (
patchDiscriminatorEnum(
schema,
ref,
mappedValues,
discriminator,
item.$ref,
options,
)
) {
refsHandled.push(ref);
}
}
}
objects[ref] = {
...objects[item.$ref],
};
} else if (item.discriminator?.propertyName) {
objects[createRef(path)] = { ...item.discriminator };
}

@@ -346,0 +398,0 @@ }

@@ -129,3 +129,7 @@ import { parseRef } from "@redocly/openapi-core/lib/ref-utils.js";

metadata,
{ export: true, readonly: options.ctx.immutable },
{
export: true,
// readonly: TS enum do not support the readonly modifier
},
);

@@ -142,4 +146,14 @@ options.ctx.injectFooter.push(enumType);

/** Collect oneOf/allOf/anyOf with Omit<> for discriminators */
function collectCompositions(
/** Collect oneOf/anyOf */
function collectUnionCompositions(items: (SchemaObject | ReferenceObject)[]) {
const output: ts.TypeNode[] = [];
for (const item of items) {
output.push(transformSchemaObject(item, options));
}
return output;
}
/** Collect allOf with Omit<> for discriminators */
function collectAllOfCompositions(
items: (SchemaObject | ReferenceObject)[],

@@ -157,20 +171,21 @@ required?: string[],

const resolved = options.ctx.resolve<SchemaObject>(item.$ref);
// make keys required, if necessary
if (
resolved &&
typeof resolved === "object" &&
"properties" in resolved
"properties" in resolved &&
// we have already handled this item (discriminator property was already added as required)
!options.ctx.discriminators.refsHandled.includes(item.$ref)
) {
// don’t try and make keys required if we have already handled the item (discriminator property was already added as required)
// or the $ref doesn’t have them
if (!options.ctx.discriminators.refsHandled.includes(item.$ref)) {
const validRequired = (required ?? []).filter(
(key) => !!resolved.properties![key],
// add WithRequired<X, Y> if necessary
const validRequired = (required ?? []).filter(
(key) => !!resolved.properties![key],
);
if (validRequired.length) {
itemType = tsWithRequired(
itemType,
validRequired,
options.ctx.injectFooter,
);
if (validRequired.length) {
itemType = tsWithRequired(
itemType,
validRequired,
options.ctx.injectFooter,
);
}
}

@@ -190,2 +205,3 @@ }

}
const discriminator =

@@ -208,3 +224,3 @@ ("$ref" in item && options.ctx.discriminators.objects[item.$ref]) ||

const coreObjectType = transformSchemaObjectCore(schemaObject, options);
const allOfType = collectCompositions(
const allOfType = collectAllOfCompositions(
schemaObject.allOf ?? [],

@@ -224,6 +240,3 @@ schemaObject.required,

// (note: this may seem counterintuitive, but as TypeScript’s unions are not true XORs, they mimic behavior closer to anyOf than oneOf)
const anyOfType = collectCompositions(
schemaObject.anyOf ?? [],
schemaObject.required,
);
const anyOfType = collectUnionCompositions(schemaObject.anyOf ?? []);
if (anyOfType.length) {

@@ -233,3 +246,3 @@ finalType = tsUnion([...(finalType ? [finalType] : []), ...anyOfType]);

// oneOf: union (within intersection with other types, if any)
const oneOfType = collectCompositions(
const oneOfType = collectUnionCompositions(
schemaObject.oneOf ||

@@ -240,3 +253,2 @@ ("type" in schemaObject &&

[],
schemaObject.required,
);

@@ -419,4 +431,4 @@ if (oneOfType.length) {

// discriminatorss: explicit mapping on schema object
for (const k of ["oneOf", "allOf", "anyOf"] as const) {
// discriminators: explicit mapping on schema object
for (const k of ["allOf", "anyOf"] as const) {
if (!schemaObject[k]) {

@@ -428,4 +440,7 @@ continue;

// discriminator meant for children (!schemaObject.discriminator)
// and don't add discriminator properties if we already added/patched
// them (options.ctx.discriminators.refsHandled.includes(options.path!).
const discriminator =
!schemaObject.discriminator &&
!options.ctx.discriminators.refsHandled.includes(options.path!) &&
options.ctx.discriminators.objects[options.path!];

@@ -432,0 +447,0 @@ if (discriminator) {

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