json-schema#JSONSchema7 TypeScript Examples
The following examples show how to use
json-schema#JSONSchema7.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: extend-config-schema.ts From serverless-plugin with MIT License | 6 votes |
schemaCronCR: JSONSchema7 = {
type: 'object',
properties: {
registry: { type: 'string' },
registryId: { type: 'string' },
imageName: { type: 'string' },
tag: { type: 'string' },
events: {
type: 'array',
items: {
type: 'string',
},
},
account: { type: 'string' },
retry: {
type: 'object',
properties: {
attempts: { type: 'number' },
interval: { type: 'number' },
},
},
dlq: { type: 'string' },
dlqId: { type: 'string' },
dlqAccountId: { type: 'string' },
dlqAccount: { type: 'string' },
},
required: ['events', 'account', 'imageName', 'tag', 'registry'],
}
Example #2
Source File: extend-config-schema.ts From serverless-plugin with MIT License | 6 votes |
schemaCronYMQ: JSONSchema7 = {
type: 'object',
properties: {
queue: { type: 'string' },
queueId: { type: 'string' },
queueAccount: { type: 'string' },
account: { type: 'string' },
retry: {
type: 'object',
properties: {
attempts: { type: 'number' },
interval: { type: 'number' },
},
},
},
required: ['queue', 'account', 'queueAccount'],
}
Example #3
Source File: transform.ts From farrow with MIT License | 6 votes |
transform = (input: FieldDescriptor): JSONSchema7 => {
if (isSchemaCtor(input)) {
const schemaCtor = toSchemaCtor(input)
const formatResult = formatSchema(schemaCtor)
return transformResult(formatResult)
// eslint-disable-next-line no-else-return
} else {
const schemaCtor = toSchemaCtor(input.__type)
const formatResult = formatSchema(schemaCtor)
return {
...transformResult(formatResult),
description: input.description,
}
}
}
Example #4
Source File: extend-config-schema.ts From serverless-plugin with MIT License | 6 votes |
schemaCronS3: JSONSchema7 = {
type: 'object',
properties: {
bucket: { type: 'string' },
account: { type: 'string' },
events: {
type: 'array',
items: {
type: 'string',
},
},
prefix: { type: 'string' },
suffix: { type: 'string' },
retry: {
type: 'object',
properties: {
attempts: { type: 'number' },
interval: { type: 'number' },
},
},
dlq: { type: 'string' },
dlqId: { type: 'string' },
dlqAccountId: { type: 'string' },
dlqAccount: { type: 'string' },
},
required: ['bucket', 'account', 'events'],
}
Example #5
Source File: useTemplateGeneration.ts From template-based-generator-template with GNU General Public License v3.0 | 6 votes |
export function useTemplateGeneration(configFormData: IConfiguration | undefined, fileName = 'input.md') {
const [template, templateSetter] = useState('');
const [result, resultSetter] = useState<Array<IOutputWIthMetadata<any[]>>>([]);
const [templateData, templateDataSetter] = useState<ITemplateData | undefined>();
const [errorMessage, errorMessageSetter] = useState('');
const [configSchema, configSchemaSetter] = useState<JSONSchema7 | undefined>();
const [rerender, rerenderHookTrigger] = useTrigger();
const parseAndGenerateFromTemplate = useDebouncedFn(
(templateStringToParse: string): void => {
const vFile = new VFile({ path: fileName, value: templateStringToParse });
let newErrorMessage = '';
try {
const templateData = templateFileToNLCSTNodes(vFile);
configSchemaSetter(getConfigSchemaFromTemplate(templateData));
if (configFormData === undefined) {
throw new Error('模板参数不正确');
}
templateDataSetter(templateData);
resultSetter(randomOutlineToArrayWithMetadataCompiler(templateData, configFormData));
} catch (e) {
newErrorMessage += (e as Error).message;
}
// newErrorMessage += reporter(vFile);
errorMessageSetter(newErrorMessage);
},
500,
undefined,
[configFormData],
);
useEffect(() => {
parseAndGenerateFromTemplate(template);
}, [template, rerenderHookTrigger]);
return [rerender, template, templateSetter, result, configSchema, errorMessage, templateData] as const;
}
Example #6
Source File: index.ts From template-based-generator-template with GNU General Public License v3.0 | 6 votes |
/**
* 为 UI 制作待填参数表单
*/
export function getConfigSchemaFromTemplate(templateData: ITemplateData): JSONSchema7 {
const slots = collectSlots(templateData);
const configSchemaBase: JSONSchema7 = {
title: '模板参数',
description: '生成流程所需的参数',
type: 'object',
required: [],
properties: {
sub: {
title: '模板槽位',
description: '填入{{槽位}}中的内容',
type: 'object',
required: [],
properties: {},
},
},
};
for (const slot of slots) {
(configSchemaBase.properties!.sub as JSONSchema7).properties![slot] = {
type: 'string',
title: slot,
};
}
return configSchemaBase;
}
Example #7
Source File: extend-config-schema.ts From serverless-plugin with MIT License | 6 votes |
schemaCronTrigger: JSONSchema7 = {
type: 'object',
properties: {
expression: { type: 'string' },
account: { type: 'string' },
retry: {
type: 'object',
properties: {
attempts: { type: 'number' },
interval: { type: 'number' },
},
},
dlq: { type: 'string' },
dlqId: { type: 'string' },
dlqAccountId: { type: 'string' },
dlqAccount: { type: 'string' },
},
required: ['expression', 'account'],
}
Example #8
Source File: transformDMMF.ts From prisma-json-schema-generator with MIT License | 6 votes |
export function transformDMMF(
dmmf: DMMF.Document,
transformOptions: TransformOptions = {},
): JSONSchema7 {
// TODO: Remove default values as soon as prisma version < 3.10.0 doesn't have to be supported anymore
const { models = [], enums = [], types = [] } = dmmf.datamodel
const initialJSON = getInitialJSON()
const { schemaId } = transformOptions
const modelDefinitionsMap = models.map(
getJSONSchemaModel({ enums }, transformOptions),
)
const typeDefinitionsMap = types.map(
getJSONSchemaModel({ enums }, transformOptions),
)
const modelPropertyDefinitionsMap = models.map(
getPropertyDefinition(transformOptions),
)
const definitions = Object.fromEntries([
...modelDefinitionsMap,
...typeDefinitionsMap,
])
const properties = Object.fromEntries(modelPropertyDefinitionsMap)
return {
...(schemaId ? { $id: schemaId } : null),
...initialJSON,
definitions,
properties,
}
}
Example #9
Source File: Widgets.tsx From sapio-studio with Mozilla Public License 2.0 | 6 votes |
export function PathOnly(
props:
| {
schema: JSONSchema7;
name: string;
formData: string | null;
value: string | null;
}
| any
) {
const [val, set_val] = React.useState(props.value);
React.useEffect(() => {
props.onChange(val);
}, [val]);
return (
<div>
<Typography>{props.value ?? 'None Selected'}</Typography>
<Button
onClick={async () => {
const new_val = await window.electron.select_filename();
if (new_val) set_val(new_val);
}}
>
{props.name ?? 'Select File'}
</Button>
</div>
);
}
Example #10
Source File: meta.test.ts From zod-to-json-schema with ISC License | 6 votes |
describe("Meta data", () => {
it("should be possible to use description", () => {
const $z = z.string().describe("My neat string");
const $j = zodToJsonSchema($z);
const $e: JSONSchema7 = {
$schema: "http://json-schema.org/draft-07/schema#",
type: "string",
description: "My neat string",
};
expect($j).toStrictEqual($e);
});
});
Example #11
Source File: properties.ts From prisma-json-schema-generator with MIT License | 6 votes |
function getItemsByDMMFType(
field: DMMF.Field,
transformOptions: TransformOptions,
): JSONSchema7['items'] {
return (isScalarType(field) && !field.isList) || isEnumType(field)
? undefined
: isScalarType(field) && field.isList
? { type: getJSONSchemaScalar(field.type) }
: getJSONSchemaForPropertyReference(field, transformOptions)
}
Example #12
Source File: properties.ts From prisma-json-schema-generator with MIT License | 6 votes |
function getJSONSchemaType(field: DMMF.Field): JSONSchema7['type'] {
const { isList, isRequired } = field
const scalarFieldType =
isScalarType(field) && !isList
? getJSONSchemaScalar(field.type)
: field.isList
? 'array'
: isEnumType(field)
? 'string'
: 'object'
const isFieldUnion = Array.isArray(scalarFieldType)
return isRequired || isList
? scalarFieldType
: isFieldUnion
? Array.from(new Set([...scalarFieldType, 'null']))
: [scalarFieldType, 'null']
}
Example #13
Source File: properties.ts From prisma-json-schema-generator with MIT License | 6 votes |
function getDefaultValue(field: DMMF.Field): JSONSchema7['default'] {
const fieldDefault = field.default
if (!field.hasDefaultValue) {
return null
}
if (field.kind === 'enum') {
return typeof fieldDefault === 'string' ? fieldDefault : null
}
if (!isScalarType(field)) {
return null
}
switch (field.type) {
case 'String':
case 'BigInt':
case 'DateTime':
return typeof fieldDefault === 'string' ? fieldDefault : null
case 'Int':
case 'Float':
case 'Decimal':
return typeof fieldDefault === 'number' ? fieldDefault : null
case 'Boolean':
return typeof fieldDefault === 'boolean' ? fieldDefault : null
case 'Json':
case 'Bytes':
return null
default:
return assertNever(field.type)
}
}
Example #14
Source File: properties.ts From prisma-json-schema-generator with MIT License | 6 votes |
function getJSONSchemaForPropertyReference(
field: DMMF.Field,
{ schemaId }: TransformOptions,
): JSONSchema7 {
const notNullable = field.isRequired || field.isList
assertFieldTypeIsString(field.type)
const typeRef = `${DEFINITIONS_ROOT}${field.type}`
const ref = { $ref: schemaId ? `${schemaId}${typeRef}` : typeRef }
return notNullable ? ref : { anyOf: [ref, { type: 'null' }] }
}
Example #15
Source File: UTXODetail.tsx From sapio-studio with Mozilla Public License 2.0 | 5 votes |
name_schema: JSONSchema7 = {
title: 'Name for this Update',
type: 'string',
}
Example #16
Source File: extend-config-schema.ts From serverless-plugin with MIT License | 5 votes |
schemaResources: JSONSchema7 = {
type: 'object',
patternProperties: {
'^.*$': {
oneOf: [
{
type: 'object',
properties: {
type: {
enum: ['yc::ServiceAccount'],
},
roles: {
type: 'array',
items: {
type: 'string',
},
},
},
},
{
type: 'object',
properties: {
type: {
enum: ['yc::MessageQueue'],
},
name: { type: 'string' },
},
},
{
type: 'object',
properties: {
type: {
enum: ['yc::ObjectStorageBucket'],
},
name: { type: 'string' },
},
},
{
type: 'object',
properties: {
type: {
enum: ['yc::ContainerRegistry'],
},
name: { type: 'string' },
},
},
],
},
},
}
Example #17
Source File: jsonSchema.ts From prisma-json-schema-generator with MIT License | 5 votes |
getInitialJSON = (): JSONSchema7 => ({
$schema: 'http://json-schema.org/draft-07/schema#',
definitions: {},
type: 'object',
})
Example #18
Source File: index.ts From json-schema-yup-transform with MIT License | 5 votes |
convertToYup = (
schema: JSONSchema7,
config?: yupTransformer.Config
): Yup.ObjectSchema<object> | undefined => {
config && yupTransformer.setConfiguration(config);
const normalizedSchema = normalize(schema);
return yupTransformer.default(normalizedSchema);
}
Example #19
Source File: Settings.tsx From baleen3 with Apache License 2.0 | 5 votes |
Settings: React.FC<SettingsProps> = ({
open,
title,
settings = {},
schema,
onClose,
onSubmit,
editable,
}: SettingsProps) => {
const handleSubmit = (result: ISubmitEvent<object>): void => {
if (onSubmit !== undefined) {
onSubmit(result.formData)
}
onClose()
}
const [jsonSchema, setJsonSchema] = useState<JSONSchema7>({})
const [uiSchema, setUiSchema] = useState<object>({})
useEffect(() => {
try {
setJsonSchema(JSON.parse(schema.jsonSchema) as JSONSchema7)
if ((schema as SettingsSchemaExtended).uiSchema !== undefined) {
setUiSchema(
JSON.parse((schema as SettingsSchemaExtended).uiSchema) as UiSchema
)
}
} catch (e) {
if (e instanceof Error) {
throw new Error(`Error parsing json Schema\n${e.message}`)
} else {
throw e
}
}
}, [schema])
const readonly = !editable
return (
<Dialog open={open} onClose={onClose} disableBackdropClick>
<DialogTitle>{title}</DialogTitle>
<DialogContent>
<Form
disabled={readonly}
liveValidate={readonly}
schema={jsonSchema}
formData={settings}
onSubmit={handleSubmit}
FieldTemplate={FieldTemplate}
widgets={widgets}
uiSchema={uiSchema}
>
<Divider mb={3} variant="fullWidth" />
<DialogActions>
{readonly ? (
<Button type="submit" color="primary" onClick={onClose}>
Done
</Button>
) : (
<>
<Button variant="text" onClick={onClose}>
Cancel
</Button>
<Button type="submit" color="primary">
Save
</Button>
</>
)}
</DialogActions>
</Form>
</DialogContent>
</Dialog>
)
}
Example #20
Source File: sapio.ts From sapio-studio with Mozilla Public License 2.0 | 4 votes |
async list_contracts(workspace_name: string): Promise<Result<API>> {
const workspace = await SapioWorkspace.new(workspace_name);
const res = await SapioCompiler.command([
'contract',
'list',
'--workspace',
workspace.workspace_location(),
]);
if ('err' in res) return res;
const contracts = res.ok;
const lines: Array<[string, string]> = contracts
.trim()
.split(/\r?\n/)
.map((line: string) => {
const v: string[] = line.split(' -- ')!;
equal(v.length, 2);
return v as [string, string];
});
const apis_p = Promise.all(
lines.map(([name, key]: [string, string]): Promise<JSONSchema7> => {
if (memo_apis.has(key)) {
return Promise.resolve(memo_apis.get(key));
} else {
return SapioCompiler.command([
'contract',
'api',
'--key',
key,
'--workspace',
workspace.workspace_location(),
]).then((v) => {
if ('err' in v) return v;
const api = JSON.parse(v.ok);
memo_apis.set(key, api);
return api;
});
}
})
);
const logos_p = Promise.all(
lines.map(
([name, key]: [string, string]): Promise<Result<string>> => {
if (memo_logos.has(key)) {
return Promise.resolve(memo_logos.get(key));
} else {
return SapioCompiler.command([
'contract',
'logo',
'--key',
key,
'--workspace',
workspace.workspace_location(),
])
.then((logo: Result<string>) => {
return 'ok' in logo
? { ok: logo.ok.trim() }
: logo;
})
.then((logo: Result<string>) => {
if ('err' in logo) return logo;
memo_logos.set(key, logo);
return logo;
});
}
}
)
);
const [apis, logos] = await Promise.all([apis_p, logos_p]);
const results: API = {};
equal(lines.length, apis.length);
equal(lines.length, logos.length);
for (let i = 0; i < lines.length; ++i) {
const [name, key] = lines[i]!;
const api = apis[i]!;
const logo = logos[i]!;
if ('err' in logo) return logo;
results[key] = {
name,
key,
api,
logo: logo.ok,
};
}
return { ok: results };
}
Example #21
Source File: transform.ts From farrow with MIT License | 4 votes |
transformResult = (formatResult: FormatResult): JSONSchema7 => {
const transformType = (input: FormatType): JSONSchema7 => {
switch (input.type) {
case 'Scalar': {
return transformScalarType(input)
}
case 'Object': {
return transformObjectType(input)
}
case 'Union': {
return transformUnionType(input)
}
case 'Intersect': {
return transformIntersectType(input)
}
case 'Struct': {
return transformStructType(input)
}
case 'Record': {
return transformRecordType(input)
}
case 'List': {
return transformListType(input)
}
case 'Tuple': {
return transformTupleType(input)
}
case 'Literal': {
return transformLiteralType(input)
}
case 'Nullable': {
return transformNullableType(input)
}
case 'Strict': {
return transformStrictType(input)
}
case 'NonStrict': {
return transformNonStrictType(input)
}
case 'ReadOnly': {
return transformReadOnlyType(input)
}
case 'ReadOnlyDeep': {
return transformReadOnlyDeepType(input)
}
// for eslint
default: {
throw new Error(`Unknown format type: ${input}`)
}
}
}
const transformScalarType = (input: FormatScalarType): JSONSchema7 => {
switch (input.valueName) {
case 'String':
return {
type: 'string',
}
case 'ID':
return {
type: 'integer',
}
case 'Number':
return {
type: 'number',
}
case 'Int':
return {
type: 'integer',
}
case 'Float':
return {
type: 'number',
}
case 'Boolean':
return {
type: 'boolean',
}
case 'Date':
return {
type: 'string',
}
case 'Unknown':
return {}
case 'Any':
return {}
case 'Json':
return {}
default:
throw new Error(`Unknown Scalar Type name: ${input.valueName}`)
}
}
const transformObjectType = (input: FormatObjectType): JSONSchema7 => {
const fields = transformFieldsType(input.fields)
return {
...fields,
type: 'object',
}
}
type Properties = {
[key: string]: JSONSchema7Definition
}
const transformFieldsType = (input: FormatFields): JSONSchema7 => {
const properties: Properties = {}
for (const name in input) {
properties[name] = transformFieldType(input[name])
}
return {
properties,
}
}
const transformFieldType = (input: FormatField): JSONSchema7 => {
return {
...findSchema(input.typeId),
description: input.description,
}
}
const transformUnionType = (input: FormatUnionType): JSONSchema7 => {
const items: JSONSchema7[] = input.itemTypes.map(({ typeId }) => findSchema(typeId))
return {
oneOf: items,
}
}
const transformIntersectType = (input: FormatIntersectType): JSONSchema7 => {
const items: JSONSchema7[] = input.itemTypes.map(({ typeId }) => findSchema(typeId))
const properties: Properties = {}
for (const item of items) {
if (item.properties) {
for (const key in item.properties) {
properties[key] = item.properties[key]
}
}
}
return {
type: 'object',
properties,
}
}
const transformStructType = (input: FormatStructType): JSONSchema7 => {
const fields = transformFieldsType(input.fields)
return {
type: 'object',
...fields,
}
}
const transformRecordType = (input: FormatRecordType): JSONSchema7 => {
const item = findSchema(input.valueTypeId)
return {
type: 'object',
additionalProperties: item,
}
}
const transformListType = (input: FormatListType): JSONSchema7 => {
const item = findSchema(input.itemTypeId)
return {
type: 'array',
additionalItems: item,
}
}
const transformTupleType = (input: FormatTupleType): JSONSchema7 => {
const items = input.itemTypes.map(({ typeId }) => findSchema(typeId))
return {
type: 'array',
items,
}
}
const transformLiteralType = (input: FormatLiteralType): JSONSchema7 => {
return {
const: [input.value!],
}
}
const transformNullableType = (input: FormatNullableType): JSONSchema7 => {
const item = findSchema(input.itemTypeId)
return {
anyOf: [
item,
{
const: [null],
},
],
}
}
const transformStrictType = (input: FormatStrictType): JSONSchema7 => {
const item = findSchema(input.itemTypeId)
return item
}
const transformNonStrictType = (input: FormatNonStrictType): JSONSchema7 => {
const item = findSchema(input.itemTypeId)
return item
}
const transformReadOnlyType = (input: FormatReadOnlyType): JSONSchema7 => {
const item = findSchema(input.itemTypeId)
return item
}
const transformReadOnlyDeepType = (input: FormatReadonlyDeepType): JSONSchema7 => {
const item = findSchema(input.itemTypeId)
return item
}
const schemas = new Map<string, JSONSchema7>()
const findSchema = (typeId: number): JSONSchema7 => {
const schema = schemas.get(typeId.toString())
if (!schema) {
const item = findType(typeId)
const schema = transformType(item)
schemas.set(`${typeId}`, schema)
}
return {
$ref: `#/definitions/${typeId}`,
}
}
const findType = (typeId: number): FormatType => {
for (const key in formatResult.types) {
if (key === `${typeId}`) {
return formatResult.types[key]
}
}
throw new Error(`Unknown typeId: ${typeId}`)
}
for (const id in formatResult.types) {
if (!schemas.has(id)) {
schemas.set(id, {
$id: id,
...transformType(formatResult.types[id]),
})
}
}
const definitions = Object.fromEntries(schemas)
return {
$id: '/farrow/schema',
definitions,
...findSchema(formatResult.typeId),
}
}
Example #22
Source File: ActionsPage.tsx From backstage with Apache License 2.0 | 4 votes |
ActionsPage = () => {
const api = useApi(scaffolderApiRef);
const classes = useStyles();
const { loading, value, error } = useAsync(async () => {
return api.listActions();
});
if (loading) {
return <Progress />;
}
if (error) {
return (
<ErrorPage
statusMessage="Failed to load installed actions"
status="500"
/>
);
}
const formatRows = (input: JSONSchema7) => {
const properties = input.properties;
if (!properties) {
return undefined;
}
return Object.entries(properties).map(entry => {
const [key] = entry;
const props = entry[1] as unknown as JSONSchema7;
const codeClassname = classNames(classes.code, {
[classes.codeRequired]: input.required?.includes(key),
});
return (
<TableRow key={key}>
<TableCell>
<div className={codeClassname}>{key}</div>
</TableCell>
<TableCell>{props.title}</TableCell>
<TableCell>{props.description}</TableCell>
<TableCell>
<span className={classes.code}>{props.type}</span>
</TableCell>
</TableRow>
);
});
};
const renderTable = (input: JSONSchema7) => {
if (!input.properties) {
return undefined;
}
return (
<TableContainer component={Paper}>
<Table size="small">
<TableHead>
<TableRow>
<TableCell>Name</TableCell>
<TableCell>Title</TableCell>
<TableCell>Description</TableCell>
<TableCell>Type</TableCell>
</TableRow>
</TableHead>
<TableBody>{formatRows(input)}</TableBody>
</Table>
</TableContainer>
);
};
const renderTables = (name: string, input?: JSONSchema7Definition[]) => {
if (!input) {
return undefined;
}
return (
<>
<Typography variant="h6">{name}</Typography>
{input.map((i, index) => (
<div key={index}>{renderTable(i as unknown as JSONSchema7)}</div>
))}
</>
);
};
const items = value?.map(action => {
if (action.id.startsWith('legacy:')) {
return undefined;
}
const oneOf = renderTables('oneOf', action.schema?.input?.oneOf);
return (
<Box pb={4} key={action.id}>
<Typography variant="h4" className={classes.code}>
{action.id}
</Typography>
<Typography>{action.description}</Typography>
{action.schema?.input && (
<Box pb={2}>
<Typography variant="h5">Input</Typography>
{renderTable(action.schema.input)}
{oneOf}
</Box>
)}
{action.schema?.output && (
<Box pb={2}>
<Typography variant="h5">Output</Typography>
{renderTable(action.schema.output)}
</Box>
)}
</Box>
);
});
return (
<Page themeId="home">
<Header
pageTitleOverride="Create a New Component"
title="Installed actions"
subtitle="This is the collection of all installed actions"
/>
<Content>{items}</Content>
</Page>
);
}
Example #23
Source File: references.test.ts From zod-to-json-schema with ISC License | 4 votes |
describe("Pathing", () => {
it("should handle recurring properties with paths", () => {
const addressSchema = z.object({
street: z.string(),
number: z.number(),
city: z.string(),
});
const someAddresses = z.object({
address1: addressSchema,
address2: addressSchema,
lotsOfAddresses: z.array(addressSchema),
});
const jsonSchema = {
$schema: "http://json-schema.org/draft-07/schema#",
type: "object",
properties: {
address1: {
type: "object",
properties: {
street: { type: "string" },
number: { type: "number" },
city: { type: "string" },
},
additionalProperties: false,
required: ["street", "number", "city"],
},
address2: { $ref: "#/properties/address1" },
lotsOfAddresses: {
type: "array",
items: { $ref: "#/properties/address1" },
},
},
additionalProperties: false,
required: ["address1", "address2", "lotsOfAddresses"],
};
const parsedSchema = zodToJsonSchema(someAddresses);
expect(parsedSchema).toStrictEqual(jsonSchema);
expect(ajv.validateSchema(parsedSchema!)).toEqual(true);
});
it("Should properly reference union participants", () => {
const participant = z.object({ str: z.string() });
const schema = z.object({
union: z.union([participant, z.string()]),
part: participant,
});
const expectedJsonSchema = {
$schema: "http://json-schema.org/draft-07/schema#",
type: "object",
properties: {
union: {
anyOf: [
{
type: "object",
properties: {
str: {
type: "string",
},
},
additionalProperties: false,
required: ["str"],
},
{
type: "string",
},
],
},
part: {
$ref: "#/properties/union/anyOf/0",
},
},
additionalProperties: false,
required: ["union", "part"],
};
const parsedSchema = zodToJsonSchema(schema);
expect(parsedSchema).toStrictEqual(expectedJsonSchema);
expect(ajv.validateSchema(parsedSchema!)).toEqual(true);
const resolvedSchema = deref(expectedJsonSchema);
expect(resolvedSchema.properties.part).toBe(
resolvedSchema.properties.union.anyOf[0]
);
});
it("Should be able to handle recursive schemas", () => {
type Category = {
name: string;
subcategories: Category[];
};
// cast to z.ZodSchema<Category>
// @ts-ignore
const categorySchema: z.ZodSchema<Category> = z.lazy(() =>
z.object({
name: z.string(),
subcategories: z.array(categorySchema),
})
);
const parsedSchema = zodToJsonSchema(categorySchema);
const expectedJsonSchema = {
$schema: "http://json-schema.org/draft-07/schema#",
type: "object",
properties: {
name: {
type: "string",
},
subcategories: {
type: "array",
items: {
$ref: "#/",
},
},
},
required: ["name", "subcategories"],
additionalProperties: false,
};
expect(parsedSchema).toStrictEqual(expectedJsonSchema);
expect(ajv.validateSchema(parsedSchema!)).toEqual(true);
const resolvedSchema = deref(parsedSchema);
expect(resolvedSchema.properties.subcategories.items).toBe(resolvedSchema);
});
it("Should be able to handle complex & nested recursive schemas", () => {
type Category = {
name: string;
inner: {
subcategories?: Record<string, Category> | null;
};
};
// cast to z.ZodSchema<Category>
// @ts-ignore
const categorySchema: z.ZodSchema<Category> = z.lazy(() =>
z.object({
name: z.string(),
inner: z.object({
subcategories: z.record(categorySchema).nullable().optional(),
}),
})
);
const inObjectSchema = z.object({
category: categorySchema,
});
const parsedSchema = zodToJsonSchema(inObjectSchema);
const expectedJsonSchema = {
$schema: "http://json-schema.org/draft-07/schema#",
type: "object",
additionalProperties: false,
required: ["category"],
properties: {
category: {
type: "object",
properties: {
name: {
type: "string",
},
inner: {
type: "object",
additionalProperties: false,
properties: {
subcategories: {
anyOf: [
{
type: "object",
additionalProperties: {
$ref: "#/properties/category",
},
},
{
type: "null",
},
],
},
},
},
},
required: ["name", "inner"],
additionalProperties: false,
},
},
};
expect(parsedSchema).toStrictEqual(expectedJsonSchema);
expect(ajv.validateSchema(parsedSchema!)).toEqual(true);
});
it("should work with relative references", () => {
const recurringSchema = z.string();
const objectSchema = z.object({
foo: recurringSchema,
bar: recurringSchema,
});
const jsonSchema = zodToJsonSchema(objectSchema, {
$refStrategy: "relative",
});
const exptectedResult: JSONSchema7 = {
$schema: "http://json-schema.org/draft-07/schema#",
type: "object",
properties: {
foo: {
type: "string",
},
bar: {
$ref: "1/foo",
},
},
required: ["foo", "bar"],
additionalProperties: false,
};
expect(jsonSchema).toStrictEqual(exptectedResult);
});
it("should be possible to override the base path", () => {
const recurringSchema = z.string();
const objectSchema = z.object({
foo: recurringSchema,
bar: recurringSchema,
});
const jsonSchema = zodToJsonSchema(objectSchema, {
basePath: ["#", "lol", "xD"],
});
const exptectedResult: JSONSchema7 = {
$schema: "http://json-schema.org/draft-07/schema#",
type: "object",
properties: {
foo: {
type: "string",
},
bar: {
$ref: "#/lol/xD/properties/foo",
},
},
required: ["foo", "bar"],
additionalProperties: false,
};
expect(jsonSchema).toStrictEqual(exptectedResult);
});
it("should be possible to opt out of $ref building", () => {
const recurringSchema = z.string();
const objectSchema = z.object({
foo: recurringSchema,
bar: recurringSchema,
});
const jsonSchema = zodToJsonSchema(objectSchema, {
$refStrategy: "none",
});
const exptectedResult: JSONSchema7 = {
$schema: "http://json-schema.org/draft-07/schema#",
type: "object",
properties: {
foo: {
type: "string",
},
bar: {
type: "string",
},
},
required: ["foo", "bar"],
additionalProperties: false,
};
expect(jsonSchema).toStrictEqual(exptectedResult);
});
it("When opting out of ref building and using recursive schemas, should warn and default to any", () => {
global.console = { ...global.console, warn: jest.fn() };
type Category = {
name: string;
subcategories: Category[];
};
// cast to z.ZodSchema<Category>
// @ts-ignore
const categorySchema: z.ZodSchema<Category> = z.lazy(() =>
z.object({
name: z.string(),
subcategories: z.array(categorySchema),
})
);
const parsedSchema = zodToJsonSchema(categorySchema, {
$refStrategy: "none",
});
const expectedJsonSchema = {
$schema: "http://json-schema.org/draft-07/schema#",
type: "object",
properties: {
name: {
type: "string",
},
subcategories: {
type: "array",
items: {},
},
},
required: ["name", "subcategories"],
additionalProperties: false,
};
expect(parsedSchema).toStrictEqual(expectedJsonSchema);
expect(console.warn).toBeCalledWith(
"Recursive reference detected at #/properties/subcategories/items! Defaulting to any"
);
});
it("should be possible to override get proper references even when picking optional definitions path $defs", () => {
const recurringSchema = z.string();
const objectSchema = z.object({
foo: recurringSchema,
bar: recurringSchema,
});
const jsonSchema = zodToJsonSchema(objectSchema, {
name: "hello",
definitionPath: "$defs",
});
const exptectedResult = {
$schema: "http://json-schema.org/draft-07/schema#",
$ref: "#/$defs/hello",
$defs: {
hello: {
type: "object",
properties: {
foo: {
type: "string",
},
bar: {
$ref: "#/$defs/hello/properties/foo",
},
},
required: ["foo", "bar"],
additionalProperties: false,
},
},
};
expect(jsonSchema).toStrictEqual(exptectedResult);
});
it("should be possible to override get proper references even when picking optional definitions path definitions", () => {
const recurringSchema = z.string();
const objectSchema = z.object({
foo: recurringSchema,
bar: recurringSchema,
});
const jsonSchema = zodToJsonSchema(objectSchema, {
name: "hello",
definitionPath: "definitions",
});
const exptectedResult = {
$schema: "http://json-schema.org/draft-07/schema#",
$ref: "#/definitions/hello",
definitions: {
hello: {
type: "object",
properties: {
foo: {
type: "string",
},
bar: {
$ref: "#/definitions/hello/properties/foo",
},
},
required: ["foo", "bar"],
additionalProperties: false,
},
},
};
expect(jsonSchema).toStrictEqual(exptectedResult);
});
});