openapi-ts-json-schema
Advanced tools
Comparing version 0.9.2 to 0.10.0
@@ -1,10 +0,2 @@ | ||
import type { SchemaPatcher, ReturnPayload, Plugin } from './types'; | ||
export declare function openapiToTsJsonSchema({ openApiSchema: openApiSchemaRelative, definitionPathsToGenerateFrom, schemaPatcher, outputPath: providedOutputPath, plugins, silent, refHandling, }: { | ||
openApiSchema: string; | ||
definitionPathsToGenerateFrom: string[]; | ||
schemaPatcher?: SchemaPatcher; | ||
outputPath?: string; | ||
plugins?: ReturnType<Plugin>[]; | ||
silent?: boolean; | ||
refHandling?: 'inline' | 'import' | 'keep'; | ||
}): Promise<ReturnPayload>; | ||
import type { ReturnPayload, Options } from './types'; | ||
export declare function openapiToTsJsonSchema(options: Options): Promise<ReturnPayload>; |
@@ -12,3 +12,13 @@ "use strict"; | ||
const utils_1 = require("./utils"); | ||
async function openapiToTsJsonSchema({ openApiSchema: openApiSchemaRelative, definitionPathsToGenerateFrom, schemaPatcher, outputPath: providedOutputPath, plugins = [], silent, refHandling = 'import', }) { | ||
async function openapiToTsJsonSchema(options) { | ||
const { plugins = [] } = options; | ||
// Execute plugins onInit method | ||
for (const { onInit } of plugins) { | ||
if (onInit) { | ||
await onInit({ | ||
options, | ||
}); | ||
} | ||
} | ||
const { openApiSchema: openApiSchemaRelative, definitionPathsToGenerateFrom, schemaPatcher, outputPath: providedOutputPath, silent, refHandling = 'import', $idMapper = ({ id }) => id, } = options; | ||
if (definitionPathsToGenerateFrom.length === 0 && !silent) { | ||
@@ -37,12 +47,13 @@ console.log(`[openapi-ts-json-schema] ⚠️ No schemas will be generated since definitionPathsToGenerateFrom option is empty`); | ||
onDereference: (ref, inlinedSchema) => { | ||
const id = (0, utils_1.refToId)(ref); | ||
// Keep track of inlined refs | ||
if (!inlinedRefs.has(ref)) { | ||
if (!inlinedRefs.has(id)) { | ||
// Make a shallow copy of the ref schema to save it from the mutations below | ||
inlinedRefs.set(ref, { ...inlinedSchema }); | ||
inlinedRefs.set(id, { ...inlinedSchema }); | ||
/** | ||
* "import" refHandling support: | ||
* mark inlined ref objects with a "REF_SYMBOL" to retrieve their | ||
* mark inlined ref objects with a "SCHEMA_ID_SYMBOL" to retrieve their | ||
* original $ref value once inlined | ||
*/ | ||
inlinedSchema[utils_1.REF_SYMBOL] = ref; | ||
inlinedSchema[utils_1.SCHEMA_ID_SYMBOL] = id; | ||
/** | ||
@@ -73,5 +84,6 @@ * "inline" refHandling support: | ||
if (refHandling === 'import' || refHandling === 'keep') { | ||
for (const [ref, schema] of inlinedRefs) { | ||
for (const [id, schema] of inlinedRefs) { | ||
(0, utils_1.addSchemaToMetaData)({ | ||
ref, | ||
id, | ||
$id: $idMapper({ id }), | ||
schemaMetaDataMap, | ||
@@ -91,3 +103,3 @@ schema, | ||
// Create expected OpenAPI ref | ||
const ref = (0, utils_1.pathToRef)({ | ||
const id = (0, utils_1.makeId)({ | ||
schemaRelativeDirName: definitionPath, | ||
@@ -97,10 +109,26 @@ schemaName, | ||
(0, utils_1.addSchemaToMetaData)({ | ||
ref, | ||
id, | ||
$id: $idMapper({ id }), | ||
schemaMetaDataMap, | ||
schema: definitionSchemas[schemaName], | ||
outputPath, | ||
isRef: inlinedRefs.has(ref), | ||
isRef: inlinedRefs.has(id), | ||
}); | ||
} | ||
} | ||
const returnPayload = { | ||
outputPath, | ||
metaData: { schemas: schemaMetaDataMap }, | ||
}; | ||
// Execute plugins onBeforeGeneration method | ||
for (const { onBeforeGeneration } of plugins) { | ||
if (onBeforeGeneration) { | ||
await onBeforeGeneration({ | ||
...returnPayload, | ||
options, | ||
utils: { makeRelativeModulePath: utils_1.makeRelativeModulePath, formatTypeScript: utils_1.formatTypeScript, saveFile: utils_1.saveFile }, | ||
}); | ||
} | ||
} | ||
// Generate schemas | ||
await (0, utils_1.makeTsJsonSchemaFiles)({ | ||
@@ -110,14 +138,4 @@ refHandling, | ||
schemaPatcher, | ||
$idMapper, | ||
}); | ||
const returnPayload = { | ||
outputPath, | ||
metaData: { schemas: schemaMetaDataMap }, | ||
}; | ||
// Execute plugins | ||
for (const plugin of plugins) { | ||
await plugin({ | ||
...returnPayload, | ||
utils: { makeRelativeModulePath: utils_1.makeRelativeModulePath, formatTypeScript: utils_1.formatTypeScript, saveFile: utils_1.saveFile }, | ||
}); | ||
} | ||
if (!silent) { | ||
@@ -124,0 +142,0 @@ console.log(`[openapi-ts-json-schema] ✅ JSON schema models generated at ${outputPath}`); |
import type { Plugin } from '../types'; | ||
declare const fastifyIntegrationPlugin: Plugin<{ | ||
sharedSchemasFilter?: ({ id }: { | ||
type PluginOptions = { | ||
schemaFilter?: (input: { | ||
id: string; | ||
isRef: boolean; | ||
}) => boolean; | ||
} | void>; | ||
}; | ||
declare const fastifyIntegrationPlugin: Plugin<PluginOptions | void>; | ||
export default fastifyIntegrationPlugin; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const OUTPUT_FILE_NAME = 'fastify-integration.ts'; | ||
const fastifyIntegrationPlugin = ({ sharedSchemasFilter = () => false } = {}) => async ({ outputPath, metaData, utils }) => { | ||
// Derive the schema data necessary to generate the declarations | ||
const allSchemas = [...metaData.schemas] | ||
.map(([id, schema]) => schema) | ||
.map(({ absoluteImportPath, uniqueName, id, isRef }) => { | ||
return { | ||
importPath: utils.makeRelativeModulePath({ | ||
fromDirectory: outputPath, | ||
to: absoluteImportPath, | ||
}), | ||
uniqueName, | ||
id, | ||
isRef, | ||
}; | ||
}); | ||
// Separate schemas used as $refs from the others | ||
const refSchemas = allSchemas.filter((schema) => schema.isRef); | ||
const nonRefSchemas = allSchemas.filter((schema) => !schema.isRef); | ||
const sharedSchemas = nonRefSchemas.filter(({ id }) => sharedSchemasFilter({ id })); | ||
let output = '// File autogenerated with "openapi-ts-json-schema". Do not edit :)'; | ||
// Generate JSON schemas import statements | ||
output += '\n'; | ||
[...refSchemas, ...sharedSchemas].forEach((schema) => { | ||
output += `\n import ${schema.uniqueName} from "${schema.importPath}";`; | ||
}); | ||
// Generate JSON schema objects with $id prop | ||
output += '\n\n'; | ||
[...refSchemas, ...sharedSchemas].forEach((schema) => { | ||
output += `\n const ${schema.uniqueName}WithId = {...${schema.uniqueName}, $id: "${schema.id}"} as const;`; | ||
}); | ||
// RefSchemas type: generate TS tuple TS type containing the types of all $ref JSON schema | ||
output += `\n\n | ||
// Allows json-schema-to-ts to hydrate $refs via the "references" option | ||
export type RefSchemas = [ | ||
${refSchemas | ||
.map((schema) => `typeof ${schema.uniqueName}WithId`) | ||
.join(',')} | ||
];`; | ||
// refSchemas: generate an array of all $ref JSON schema to be registered with `fastify.addSchema` | ||
output += `\n\n | ||
// $ref JSON schemas to be registered with "fastify.addSchema" | ||
export const refSchemas = [ | ||
${refSchemas.map((schema) => `${schema.uniqueName}WithId`).join(',')} | ||
];`; | ||
// sharedSchemas: generate an array of user-defined schemas to be registered with `fastify.addSchema` | ||
output += `\n\n | ||
// Extra JSON schemas to be registered with "fastify.addSchema" | ||
export const sharedSchemas = [ | ||
${sharedSchemas.map((schema) => `${schema.uniqueName}WithId`).join(',')} | ||
];`; | ||
// Format and save file | ||
const formattedOutput = await utils.formatTypeScript(output); | ||
await utils.saveFile({ | ||
path: [outputPath, OUTPUT_FILE_NAME], | ||
data: formattedOutput, | ||
}); | ||
const OPEN_API_COMPONENTS_SCHEMAS_PATH = '/components/schemas/'; | ||
const defaultSchemaFilter = ({ id }) => { | ||
return id.startsWith(OPEN_API_COMPONENTS_SCHEMAS_PATH); | ||
}; | ||
const fastifyIntegrationPlugin = ({ schemaFilter = defaultSchemaFilter, } = {}) => ({ | ||
onInit: async ({ options }) => { | ||
// Force "keep" refHandling | ||
options.refHandling = 'keep'; | ||
options.$idMapper = ({ id }) => id; | ||
}, | ||
onBeforeGeneration: async ({ outputPath, metaData, options, utils }) => { | ||
// Derive the schema data necessary to generate the declarations | ||
const allSchemas = [...metaData.schemas] | ||
.map(([id, schema]) => schema) | ||
.map(({ absoluteImportPath, uniqueName, id, isRef }) => { | ||
return { | ||
importPath: utils.makeRelativeModulePath({ | ||
fromDirectory: outputPath, | ||
to: absoluteImportPath, | ||
}), | ||
uniqueName, | ||
id, | ||
isRef, | ||
}; | ||
}); | ||
// @TODO: Shall we include refs of the filtered schemas? | ||
const exportedSchemas = allSchemas.filter(({ id, isRef }) => schemaFilter({ id, isRef })); | ||
let output = '// File autogenerated by "openapi-ts-json-schema". Do not edit :)'; | ||
// Generate JSON schemas import statements | ||
exportedSchemas.forEach((schema) => { | ||
output += `\n import ${schema.uniqueName} from "${schema.importPath}";`; | ||
}); | ||
// RefSchemas type: generate TS tuple TS type containing the types of all $ref JSON schema | ||
output += `\n\n | ||
// RefSchemas type: tuple of $ref schema types to enable json-schema-to-ts hydrate $refs via "references" option | ||
export type RefSchemas = [ | ||
${exportedSchemas | ||
.map((schema) => `typeof ${schema.uniqueName}`) | ||
.join(',')} | ||
];`; | ||
// schemas: generate an array of all exported JSON schema to be registered with `fastify.addSchema` | ||
output += `\n\n | ||
// schemas: array of JSON schemas to be registered with "fastify.addSchema" | ||
export const schemas = [ | ||
${exportedSchemas.map((schema) => `${schema.uniqueName}`).join(',')} | ||
];`; | ||
// Format and save file | ||
const formattedOutput = await utils.formatTypeScript(output); | ||
await utils.saveFile({ | ||
path: [outputPath, OUTPUT_FILE_NAME], | ||
data: formattedOutput, | ||
}); | ||
}, | ||
}); | ||
exports.default = fastifyIntegrationPlugin; |
@@ -8,6 +8,21 @@ import type { JSONSchema4, JSONSchema6, JSONSchema7 } from 'json-schema'; | ||
}) => void; | ||
export type RefHandling = 'import' | 'inline' | 'keep'; | ||
export type $idMapper = (input: { | ||
id: string; | ||
}) => string; | ||
import type { makeRelativeModulePath, formatTypeScript, saveFile } from './utils'; | ||
export type Options = { | ||
openApiSchema: string; | ||
definitionPathsToGenerateFrom: string[]; | ||
schemaPatcher?: SchemaPatcher; | ||
outputPath?: string; | ||
plugins?: ReturnType<Plugin>[]; | ||
silent?: boolean; | ||
refHandling?: RefHandling; | ||
$idMapper?: $idMapper; | ||
}; | ||
/** | ||
* Meta data for representing a specific openApi definition | ||
* @property `id` - JSON schema Compound Schema Document `$id`. Eg `"/components/schemas/MySchema"` | ||
* @property `id` - Internal unique schema identifier. Eg `"/components/schemas/MySchema"` | ||
* @property `$id` - JSON schema Compound Schema Document `$id`. Eg `"/components/schemas/MySchema"` | ||
* @property `isRef` - True if schemas is used as `$ref` | ||
@@ -23,2 +38,3 @@ * @property `uniqueName` - Unique JavaScript identifier used as import name. Eg: `"componentsSchemasMySchema"` | ||
id: string; | ||
$id: string; | ||
isRef: boolean; | ||
@@ -39,3 +55,7 @@ uniqueName: string; | ||
}; | ||
type PluginInput = ReturnPayload & { | ||
type OnInitInput = { | ||
options: Options; | ||
}; | ||
type OnBeforeGenerationInput = ReturnPayload & { | ||
options: Options; | ||
utils: { | ||
@@ -47,3 +67,6 @@ makeRelativeModulePath: typeof makeRelativeModulePath; | ||
}; | ||
export type Plugin<Options = void> = (options: Options) => (input: PluginInput) => Promise<void>; | ||
export type Plugin<PluginOptions = void> = (options: PluginOptions) => { | ||
onInit?: (input: OnInitInput) => Promise<void>; | ||
onBeforeGeneration?: (input: OnBeforeGenerationInput) => Promise<void>; | ||
}; | ||
export {}; |
import type { SchemaMetaDataMap, JSONSchema } from '../types'; | ||
export declare function addSchemaToMetaData({ ref, schemaMetaDataMap, schema, isRef, outputPath, }: { | ||
ref: string; | ||
export declare function addSchemaToMetaData({ id, $id, schemaMetaDataMap, schema, isRef, outputPath, }: { | ||
id: string; | ||
$id: string; | ||
schemaMetaDataMap: SchemaMetaDataMap; | ||
@@ -5,0 +6,0 @@ schema: JSONSchema; |
@@ -14,9 +14,8 @@ "use strict"; | ||
*/ | ||
function addSchemaToMetaData({ ref, schemaMetaDataMap, schema, isRef, | ||
function addSchemaToMetaData({ id, $id, schemaMetaDataMap, schema, isRef, | ||
// Options | ||
outputPath, }) { | ||
// Do not override existing meta info of inlined schemas | ||
if (!schemaMetaDataMap.has(ref)) { | ||
const refPath = (0, _1.parseRef)(ref); | ||
const { schemaRelativeDirName, schemaName } = (0, _1.refToPath)(ref); | ||
if (!schemaMetaDataMap.has(id)) { | ||
const { schemaRelativeDirName, schemaName } = (0, _1.parseId)(id); | ||
const absoluteDirName = node_path_1.default.join(outputPath, schemaRelativeDirName); | ||
@@ -26,4 +25,5 @@ const schemaFileName = (0, _1.filenamify)(schemaName); | ||
const metaInfo = { | ||
id: `/${refPath}`, | ||
uniqueName: (0, namify_1.default)(refPath), | ||
id, | ||
$id, | ||
uniqueName: (0, namify_1.default)(id), | ||
isRef, | ||
@@ -35,5 +35,5 @@ originalSchema: schema, | ||
}; | ||
schemaMetaDataMap.set(ref, metaInfo); | ||
schemaMetaDataMap.set(id, metaInfo); | ||
} | ||
} | ||
exports.addSchemaToMetaData = addSchemaToMetaData; |
@@ -6,6 +6,6 @@ export { patchJsonSchema } from './makeTsJsonSchema/patchJsonSchema'; | ||
export { makeTsJsonSchemaFiles } from './makeTsJsonSchemaFiles'; | ||
export { parseRef } from './parseRef'; | ||
export { refToPath } from './refToPath'; | ||
export { pathToRef } from './pathToRef'; | ||
export { REF_SYMBOL, PLACEHOLDER_REGEX, refToPlaceholder, } from './refReplacementUtils'; | ||
export { parseId } from './parseId'; | ||
export { refToId } from './refToId'; | ||
export { makeId } from './makeId'; | ||
export { SCHEMA_ID_SYMBOL, PLACEHOLDER_REGEX, idToPlaceholder, } from './refReplacementUtils'; | ||
export { replaceInlinedRefsWithStringPlaceholder } from './makeTsJsonSchema/replaceInlinedRefsWithStringPlaceholder'; | ||
@@ -12,0 +12,0 @@ export { replacePlaceholdersWithImportedSchemas } from './makeTsJsonSchema/replacePlaceholdersWithImportedSchemas'; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.saveFile = exports.formatTypeScript = exports.makeRelativeModulePath = exports.clearFolder = exports.filenamify = exports.isObject = exports.addSchemaToMetaData = exports.replacePlaceholdersWithImportedSchemas = exports.replaceInlinedRefsWithStringPlaceholder = exports.refToPlaceholder = exports.PLACEHOLDER_REGEX = exports.REF_SYMBOL = exports.pathToRef = exports.refToPath = exports.parseRef = exports.makeTsJsonSchemaFiles = exports.convertOpenApiToJsonSchema = exports.convertOpenApiPathsParameters = exports.makeTsJsonSchema = exports.patchJsonSchema = void 0; | ||
exports.saveFile = exports.formatTypeScript = exports.makeRelativeModulePath = exports.clearFolder = exports.filenamify = exports.isObject = exports.addSchemaToMetaData = exports.replacePlaceholdersWithImportedSchemas = exports.replaceInlinedRefsWithStringPlaceholder = exports.idToPlaceholder = exports.PLACEHOLDER_REGEX = exports.SCHEMA_ID_SYMBOL = exports.makeId = exports.refToId = exports.parseId = exports.makeTsJsonSchemaFiles = exports.convertOpenApiToJsonSchema = exports.convertOpenApiPathsParameters = exports.makeTsJsonSchema = exports.patchJsonSchema = void 0; | ||
var patchJsonSchema_1 = require("./makeTsJsonSchema/patchJsonSchema"); | ||
@@ -14,12 +14,12 @@ Object.defineProperty(exports, "patchJsonSchema", { enumerable: true, get: function () { return patchJsonSchema_1.patchJsonSchema; } }); | ||
Object.defineProperty(exports, "makeTsJsonSchemaFiles", { enumerable: true, get: function () { return makeTsJsonSchemaFiles_1.makeTsJsonSchemaFiles; } }); | ||
var parseRef_1 = require("./parseRef"); | ||
Object.defineProperty(exports, "parseRef", { enumerable: true, get: function () { return parseRef_1.parseRef; } }); | ||
var refToPath_1 = require("./refToPath"); | ||
Object.defineProperty(exports, "refToPath", { enumerable: true, get: function () { return refToPath_1.refToPath; } }); | ||
var pathToRef_1 = require("./pathToRef"); | ||
Object.defineProperty(exports, "pathToRef", { enumerable: true, get: function () { return pathToRef_1.pathToRef; } }); | ||
var parseId_1 = require("./parseId"); | ||
Object.defineProperty(exports, "parseId", { enumerable: true, get: function () { return parseId_1.parseId; } }); | ||
var refToId_1 = require("./refToId"); | ||
Object.defineProperty(exports, "refToId", { enumerable: true, get: function () { return refToId_1.refToId; } }); | ||
var makeId_1 = require("./makeId"); | ||
Object.defineProperty(exports, "makeId", { enumerable: true, get: function () { return makeId_1.makeId; } }); | ||
var refReplacementUtils_1 = require("./refReplacementUtils"); | ||
Object.defineProperty(exports, "REF_SYMBOL", { enumerable: true, get: function () { return refReplacementUtils_1.REF_SYMBOL; } }); | ||
Object.defineProperty(exports, "SCHEMA_ID_SYMBOL", { enumerable: true, get: function () { return refReplacementUtils_1.SCHEMA_ID_SYMBOL; } }); | ||
Object.defineProperty(exports, "PLACEHOLDER_REGEX", { enumerable: true, get: function () { return refReplacementUtils_1.PLACEHOLDER_REGEX; } }); | ||
Object.defineProperty(exports, "refToPlaceholder", { enumerable: true, get: function () { return refReplacementUtils_1.refToPlaceholder; } }); | ||
Object.defineProperty(exports, "idToPlaceholder", { enumerable: true, get: function () { return refReplacementUtils_1.idToPlaceholder; } }); | ||
var replaceInlinedRefsWithStringPlaceholder_1 = require("./makeTsJsonSchema/replaceInlinedRefsWithStringPlaceholder"); | ||
@@ -26,0 +26,0 @@ Object.defineProperty(exports, "replaceInlinedRefsWithStringPlaceholder", { enumerable: true, get: function () { return replaceInlinedRefsWithStringPlaceholder_1.replaceInlinedRefsWithStringPlaceholder; } }); |
@@ -1,7 +0,8 @@ | ||
import type { SchemaMetaDataMap, SchemaMetaData, SchemaPatcher } from '../../types'; | ||
export declare function makeTsJsonSchema({ metaData, schemaMetaDataMap, refHandling, schemaPatcher, }: { | ||
import type { SchemaMetaDataMap, SchemaMetaData, SchemaPatcher, RefHandling, $idMapper } from '../../types'; | ||
export declare function makeTsJsonSchema({ metaData, schemaMetaDataMap, refHandling, schemaPatcher, $idMapper, }: { | ||
metaData: SchemaMetaData; | ||
schemaMetaDataMap: SchemaMetaDataMap; | ||
refHandling: 'inline' | 'import' | 'keep'; | ||
refHandling: RefHandling; | ||
schemaPatcher?: SchemaPatcher; | ||
$idMapper: $idMapper; | ||
}): Promise<string>; |
@@ -11,9 +11,10 @@ "use strict"; | ||
const __1 = require("../"); | ||
async function makeTsJsonSchema({ metaData, schemaMetaDataMap, refHandling, schemaPatcher, }) { | ||
const { originalSchema, absoluteDirName } = metaData; | ||
async function makeTsJsonSchema({ metaData, schemaMetaDataMap, refHandling, schemaPatcher, $idMapper, }) { | ||
const { originalSchema, absoluteDirName, $id, isRef } = metaData; | ||
const schemaWith$id = { $id, ...originalSchema }; | ||
// "inline" refHandling doesn't need replacing inlined refs | ||
const schemaWithPlaceholders = refHandling === 'import' || refHandling === 'keep' | ||
? (0, replaceInlinedRefsWithStringPlaceholder_1.replaceInlinedRefsWithStringPlaceholder)(originalSchema) | ||
: originalSchema; | ||
// Check if this schema is just the reference to another schema | ||
? (0, replaceInlinedRefsWithStringPlaceholder_1.replaceInlinedRefsWithStringPlaceholder)(schemaWith$id) | ||
: schemaWith$id; | ||
// Check if this schema is just a reference to another schema | ||
const isAlias = typeof schemaWithPlaceholders === 'string'; | ||
@@ -28,10 +29,12 @@ const patchedSchema = isAlias | ||
const stringifiedSchema = (0, comment_json_1.stringify)(patchedSchema, (0, makeCircularRefReplacer_1.makeCircularRefReplacer)(), 2); | ||
/** | ||
* Schemas being just a placeholder are nothing but an alias | ||
* of the definition found in the placeholder | ||
*/ | ||
let tsSchema = isAlias && refHandling === 'import' | ||
? `export default ` + stringifiedSchema + ';' | ||
: `export default ` + stringifiedSchema + ' as const;'; | ||
let tsSchema = ` | ||
const schema = ${stringifiedSchema} as const; | ||
export default schema;`; | ||
if (refHandling === 'import') { | ||
// Alias schema handling is a bit rough, right now | ||
if (isAlias) { | ||
tsSchema = ` | ||
const schema = {$id: "${$id}", ...${stringifiedSchema}} as const; | ||
export default schema;`; | ||
} | ||
tsSchema = (0, replacePlaceholdersWithImportedSchemas_1.replacePlaceholdersWithImportedSchemas)({ | ||
@@ -41,2 +44,3 @@ schemaAsText: tsSchema, | ||
schemaMetaDataMap, | ||
isRef, | ||
}); | ||
@@ -47,2 +51,3 @@ } | ||
schemaAsText: tsSchema, | ||
refMapper: $idMapper, | ||
}); | ||
@@ -49,0 +54,0 @@ } |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.makeCircularRefReplacer = void 0; | ||
const getRef_1 = require("./getRef"); | ||
const getId_1 = require("./getId"); | ||
/** | ||
@@ -23,3 +23,3 @@ * JSON.stringify replacer | ||
if (ancestors.includes(value)) { | ||
const ref = (0, getRef_1.getRef)(value); | ||
const id = (0, getId_1.getId)(value); | ||
return { | ||
@@ -30,3 +30,3 @@ // Drop an inline comment about recursion interruption | ||
type: 'LineComment', | ||
value: ` Circular recursion interrupted (${ref})`, | ||
value: ` Circular recursion interrupted. Schema id: "${id}"`, | ||
}, | ||
@@ -33,0 +33,0 @@ ], |
import type { JSONSchema, JSONSchemaWithPlaceholders } from '../../types'; | ||
/** | ||
* Iterate a JSON schema to replace inlined ref schema objects | ||
* (marked with a REF_SYMBOL property holding the original $ref value) | ||
* with a string placeholder with a reference to the original $ref value ("_OTJS-START_#/ref/value_OTJS-END_") | ||
* (marked with a SCHEMA_ID_SYMBOL property holding the original $ref value) | ||
* with a string placeholder with a reference to the original $ref value ("_OTJS-START_/id/value_OTJS-END_") | ||
*/ | ||
export declare function replaceInlinedRefsWithStringPlaceholder(schema: JSONSchema): JSONSchemaWithPlaceholders; |
@@ -9,22 +9,22 @@ "use strict"; | ||
const __1 = require(".."); | ||
const getRef_1 = require("./getRef"); | ||
const getId_1 = require("./getId"); | ||
/** | ||
* Get any JSON schema node and: | ||
* - Return ref placeholder is the entity is an inlined ref schema objects (with REF_SYMBOL prop) | ||
* - Return ref placeholder is the entity is an inlined ref schema objects (with SCHEMA_ID_SYMBOL prop) | ||
* - Return provided node in all other cases | ||
*/ | ||
function replaceInlinedSchemaWithPlaceholder(node) { | ||
const ref = (0, getRef_1.getRef)(node); | ||
if (ref === undefined) { | ||
const id = (0, getId_1.getId)(node); | ||
if (id === undefined) { | ||
return node; | ||
} | ||
return (0, __1.refToPlaceholder)(ref); | ||
return (0, __1.idToPlaceholder)(id); | ||
} | ||
/** | ||
* Iterate a JSON schema to replace inlined ref schema objects | ||
* (marked with a REF_SYMBOL property holding the original $ref value) | ||
* with a string placeholder with a reference to the original $ref value ("_OTJS-START_#/ref/value_OTJS-END_") | ||
* (marked with a SCHEMA_ID_SYMBOL property holding the original $ref value) | ||
* with a string placeholder with a reference to the original $ref value ("_OTJS-START_/id/value_OTJS-END_") | ||
*/ | ||
function replaceInlinedRefsWithStringPlaceholder(schema) { | ||
if ((0, getRef_1.getRef)(schema)) { | ||
if ((0, getId_1.getId)(schema)) { | ||
return replaceInlinedSchemaWithPlaceholder(schema); | ||
@@ -31,0 +31,0 @@ } |
@@ -5,6 +5,7 @@ import type { SchemaMetaDataMap } from '../../types'; | ||
*/ | ||
export declare function replacePlaceholdersWithImportedSchemas({ schemaAsText, absoluteDirName, schemaMetaDataMap, }: { | ||
export declare function replacePlaceholdersWithImportedSchemas({ schemaAsText, absoluteDirName, schemaMetaDataMap, isRef, }: { | ||
schemaAsText: string; | ||
absoluteDirName: string; | ||
schemaMetaDataMap: SchemaMetaDataMap; | ||
isRef: boolean; | ||
}): string; |
@@ -8,7 +8,7 @@ "use strict"; | ||
*/ | ||
function replacePlaceholdersWithImportedSchemas({ schemaAsText, absoluteDirName, schemaMetaDataMap, }) { | ||
function replacePlaceholdersWithImportedSchemas({ schemaAsText, absoluteDirName, schemaMetaDataMap, isRef, }) { | ||
const importStatements = new Set(); | ||
// Replace placeholder occurrences with the relevant imported schema name | ||
let schema = schemaAsText.replaceAll(__1.PLACEHOLDER_REGEX, (_match, ref) => { | ||
const importedSchema = schemaMetaDataMap.get(ref); | ||
let output = schemaAsText.replaceAll(__1.PLACEHOLDER_REGEX, (_match, id) => { | ||
const importedSchema = schemaMetaDataMap.get(id); | ||
/* c8 ignore start */ | ||
@@ -25,3 +25,3 @@ if (!importedSchema) { | ||
const { uniqueName } = importedSchema; | ||
importStatements.add(`import ${uniqueName} from "${importedSchemaRelativePath}"`); | ||
importStatements.add(`import {without$id as ${uniqueName}} from "${importedSchemaRelativePath}"`); | ||
return uniqueName; | ||
@@ -31,9 +31,18 @@ }); | ||
// Empty line between imports and schema 💅 | ||
schema = '\n' + schema; | ||
output = '\n' + output; | ||
importStatements.forEach((entry) => { | ||
schema = entry + '\n' + schema; | ||
output = entry + '\n' + output; | ||
}); | ||
} | ||
return schema; | ||
/** | ||
* Schemas imported as refs by other schemas should be | ||
* imported via this export since | ||
* JSON schema allows only root level $id | ||
*/ | ||
if (isRef) { | ||
output = output + '\n\n' + `const { $id, ...without$id } = schema;`; | ||
output = output + '\n' + `export { without$id };`; | ||
} | ||
return output; | ||
} | ||
exports.replacePlaceholdersWithImportedSchemas = replacePlaceholdersWithImportedSchemas; |
/** | ||
* Replace Refs placeholders with original ref objects | ||
*/ | ||
export declare function replacePlaceholdersWithRefs({ schemaAsText, }: { | ||
export declare function replacePlaceholdersWithRefs({ schemaAsText, refMapper, }: { | ||
schemaAsText: string; | ||
refMapper: (input: { | ||
id: string; | ||
}) => string; | ||
}): string; |
@@ -8,9 +8,9 @@ "use strict"; | ||
*/ | ||
function replacePlaceholdersWithRefs({ schemaAsText, }) { | ||
function replacePlaceholdersWithRefs({ schemaAsText, refMapper, }) { | ||
// Replace placeholder occurrences with a JSON schema $ref object | ||
let schema = schemaAsText.replaceAll(__1.PLACEHOLDER_REGEX, (_match, ref) => { | ||
return `{ $ref: "${ref}" }`; | ||
let output = schemaAsText.replaceAll(__1.PLACEHOLDER_REGEX, (_match, id) => { | ||
return `{ $ref: "${refMapper({ id })}" }`; | ||
}); | ||
return schema; | ||
return output; | ||
} | ||
exports.replacePlaceholdersWithRefs = replacePlaceholdersWithRefs; |
@@ -1,9 +0,10 @@ | ||
import type { SchemaMetaDataMap, SchemaPatcher } from '../types'; | ||
import type { SchemaMetaDataMap, SchemaPatcher, RefHandling, $idMapper } from '../types'; | ||
/** | ||
* Save TS JSON schema files with the expected naming conventions | ||
*/ | ||
export declare function makeTsJsonSchemaFiles({ schemaMetaDataMap, refHandling, schemaPatcher, }: { | ||
export declare function makeTsJsonSchemaFiles({ schemaMetaDataMap, refHandling, schemaPatcher, $idMapper, }: { | ||
schemaMetaDataMap: SchemaMetaDataMap; | ||
refHandling: 'inline' | 'import' | 'keep'; | ||
refHandling: RefHandling; | ||
schemaPatcher?: SchemaPatcher; | ||
$idMapper: $idMapper; | ||
}): Promise<void>; |
@@ -8,3 +8,3 @@ "use strict"; | ||
*/ | ||
async function makeTsJsonSchemaFiles({ schemaMetaDataMap, refHandling, schemaPatcher, }) { | ||
async function makeTsJsonSchemaFiles({ schemaMetaDataMap, refHandling, schemaPatcher, $idMapper, }) { | ||
for (const [_, metaData] of schemaMetaDataMap) { | ||
@@ -16,2 +16,3 @@ const tsSchema = await (0, _1.makeTsJsonSchema)({ | ||
schemaPatcher, | ||
$idMapper, | ||
}); | ||
@@ -18,0 +19,0 @@ const { absolutePath } = metaData; |
@@ -1,6 +0,6 @@ | ||
export declare const REF_SYMBOL: unique symbol; | ||
export declare const SCHEMA_ID_SYMBOL: unique symbol; | ||
export declare const PLACEHOLDER_REGEX: RegExp; | ||
/** | ||
* Generate a string placeholder containing the ref value to be retrieved later | ||
* Generate a string placeholder containing the internal schema id value to be retrieved later | ||
*/ | ||
export declare function refToPlaceholder(ref: string): string; | ||
export declare function idToPlaceholder(id: string): string; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.refToPlaceholder = exports.PLACEHOLDER_REGEX = exports.REF_SYMBOL = void 0; | ||
exports.REF_SYMBOL = Symbol('ref'); | ||
const REF_MARKER_START = '_OTJS-START_'; | ||
const REF_MARKER_END = '_OTJS-END_'; | ||
exports.PLACEHOLDER_REGEX = new RegExp(`["']${REF_MARKER_START}(?<ref>.+)${REF_MARKER_END}["']`, 'g'); | ||
exports.idToPlaceholder = exports.PLACEHOLDER_REGEX = exports.SCHEMA_ID_SYMBOL = void 0; | ||
exports.SCHEMA_ID_SYMBOL = Symbol('id'); | ||
const SCHEMA_ID_MARKER_START = '_OTJS-START_'; | ||
const SCHEMA_ID_MARKER_END = '_OTJS-END_'; | ||
exports.PLACEHOLDER_REGEX = new RegExp(`["']${SCHEMA_ID_MARKER_START}(?<id>.+)${SCHEMA_ID_MARKER_END}["']`, 'g'); | ||
/** | ||
* Generate a string placeholder containing the ref value to be retrieved later | ||
* Generate a string placeholder containing the internal schema id value to be retrieved later | ||
*/ | ||
function refToPlaceholder(ref) { | ||
return REF_MARKER_START + ref + REF_MARKER_END; | ||
function idToPlaceholder(id) { | ||
return SCHEMA_ID_MARKER_START + id + SCHEMA_ID_MARKER_END; | ||
} | ||
exports.refToPlaceholder = refToPlaceholder; | ||
exports.idToPlaceholder = idToPlaceholder; |
{ | ||
"name": "openapi-ts-json-schema", | ||
"version": "0.9.2", | ||
"version": "0.10.0", | ||
"description": "OpenAPI to JSON schema generator with TypeScript in mind", | ||
@@ -13,2 +13,4 @@ "main": "./dist/index.js", | ||
"test": "vitest --config ./vitest.config.mts --dir ./test", | ||
"pretest": "npm run test:build", | ||
"test:build": "npm --prefix ./examples/fastify-integration-plugin run generate-schemas", | ||
"prepare": "npx simple-git-hooks && npm run test -- --run && npm run source:check && npm run build", | ||
@@ -15,0 +17,0 @@ "tag": "node ./scripts/tag.js", |
@@ -71,2 +71,3 @@ # openapi-ts-json-schema | ||
| **refHandling** | `"import" \| "inline" \| "keep"` | `"import"`: generate and import `$ref` schemas.<br/>`"inline"`: inline `$ref` schemas.<br/>`"keep"`: keep `$ref` values. | `"import"` | | ||
| **$idMapper** | `(params: { id: string }) => string` | Customize generated schemas `$id`s and `$ref`s | - | | ||
| **schemaPatcher** | `(params: { schema: JSONSchema }) => void` | Dynamically patch generated JSON schemas. The provided function will be invoked against every single JSON schema node. | - | | ||
@@ -114,6 +115,8 @@ | **outputPath** | `string` | Path where the generated schemas will be saved. Defaults to `/schemas-autogenerated` in the same directory of `openApiSchema`. | - | | ||
schemas: Map< | ||
// OpenAPI ref. Eg: "#/components/schemas/MySchema" | ||
// Schema internal id. Eg: "/components/schemas/MySchema" | ||
string, | ||
{ | ||
id: string; | ||
// Internal unique schema identifier. Eg `"/components/schemas/MySchema"` | ||
$id: string; | ||
// JSON schema Compound Schema Document `$id`. Eg: `"/components/schemas/MySchema"` | ||
@@ -152,3 +155,2 @@ uniqueName: string; | ||
- Find a way to merge multiple different OpenApi definitions consistently | ||
- Consider adding a way to customize the values of the generated JSON schema ids. This could be beneficial even in case of multiple schemas being merged with plugins | ||
- Consider implementing an option to inline circular $refs with a configurable nesting level | ||
@@ -155,0 +157,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
59690
1053
161