diff --git a/README.md b/README.md index 2825bf3..afff0b3 100644 --- a/README.md +++ b/README.md @@ -23,9 +23,9 @@ The implemented types are: The implemented functions are: -- `getDescriptions`: - - takes in parameters a schema with localized descriptions and optionnaly the locale of the default description (default value is `'en'`) - - returns the localized descriptions of the schema - `getLocalizedDescription`: - - takes in parameters a schema with localized descriptions, the locale for which we want the description and optionnaly the locale of the default description (default value is `'en'`) + - takes in parameters a schema with localized descriptions and the locale for which we want the description (default value is `'en'`) - returns the description for the wanted locale, or `undefined` if not found +- `renderJsonSchema`: + - takes in parameters the locale for which we want the description and a schema with localized descriptions + - returns the `JSONSchema6` equivalent with the selected locale diff --git a/src/constants.ts b/src/constants.ts index f5f6713..874fe60 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1 +1 @@ -export const DEFAULT_LOCALE_DESCRIPTION = 'en' +export const DEFAULT_DESCRIPTION_LOCALE = 'en' diff --git a/src/description.ts b/src/description.ts index f752297..64e470f 100644 --- a/src/description.ts +++ b/src/description.ts @@ -1,21 +1,82 @@ -import { DEFAULT_LOCALE_DESCRIPTION } from './constants' -import { Descriptions, LocalizedJSONSchema } from './types' +import { JSONSchema6, JSONSchema6Definition } from 'json-schema' +import { DEFAULT_DESCRIPTION_LOCALE } from './constants' +import { LocalizedJSONSchema, LocalizedJSONSchemaDefinition } from './types' import { isNotEmpty } from './utils' -export function getDescriptions (schema: LocalizedJSONSchema, localeDescription: string = DEFAULT_LOCALE_DESCRIPTION): Descriptions { +function getDescription (schema: LocalizedJSONSchema, locale: string = DEFAULT_DESCRIPTION_LOCALE): string | undefined { const description = isNotEmpty(schema.description) ? schema.description : undefined - const descriptions = schema.descriptions + return schema.descriptions?.[locale] ?? description +} + +function renderArrayOfJsonSchema (locale: string, array?: LocalizedJSONSchemaDefinition[]): JSONSchema6Definition[] | undefined { + return array?.map(schema => renderJsonSchema(locale, schema)).filter((schema): schema is JSONSchema6Definition => schema != null) +} + +function renderObjectOfJsonSchema (locale: string, object?: { [key: string]: LocalizedJSONSchemaDefinition }): { [key: string]: JSONSchema6Definition } | undefined { + return object == null + ? undefined + : Object.entries(object).reduce((newSchema, [key, schema]) => ({ + ...newSchema, + [key]: renderJsonSchema(locale, schema) + }), {}) +} - if (descriptions == null) { - return description != null ? { [localeDescription]: description } : {} +function renderJsonSchema (locale: string, schema: LocalizedJSONSchema): JSONSchema6 +function renderJsonSchema (locale: string, schema: boolean): boolean +function renderJsonSchema (locale: string, schema: undefined): undefined +function renderJsonSchema (locale: string, schema?: LocalizedJSONSchemaDefinition): JSONSchema6Definition | undefined +function renderJsonSchema (locale: string, schema?: LocalizedJSONSchemaDefinition): JSONSchema6Definition | undefined { + if (schema == null) { + return undefined + } else if (typeof schema === 'boolean') { + return schema } - if (description != null && !Object.keys(descriptions).includes(localeDescription)) { - descriptions[localeDescription] = description + const description = getDescription(schema, locale) + const { + descriptions, + items, + additionalItems, + contains, + properties, + patternProperties, + additionalProperties, + dependencies, + propertyNames, + allOf, + anyOf, + oneOf, + not, + definitions, + ...jsonSchema + } = schema + + const newDependencies = dependencies == null + ? undefined + : Object.entries(dependencies).reduce((newSchema, [key, schema]) => ({ + ...newSchema, + [key]: Array.isArray(schema) ? schema : renderJsonSchema(locale, schema) + }), {}) + + return { + ...jsonSchema, + items: Array.isArray(items) + ? renderArrayOfJsonSchema(locale, items) + : renderJsonSchema(locale, items), + additionalItems: renderJsonSchema(locale, additionalItems), + contains: renderJsonSchema(locale, contains), + properties: renderObjectOfJsonSchema(locale, properties), + patternProperties: renderObjectOfJsonSchema(locale, patternProperties), + additionalProperties: renderJsonSchema(locale, additionalProperties), + dependencies: newDependencies, + propertyNames: renderJsonSchema(locale, propertyNames), + allOf: renderArrayOfJsonSchema(locale, allOf), + anyOf: renderArrayOfJsonSchema(locale, anyOf), + oneOf: renderArrayOfJsonSchema(locale, oneOf), + not: renderJsonSchema(locale, not), + definitions: renderObjectOfJsonSchema(locale, definitions), + description: description ?? jsonSchema.description } - return descriptions } -export function getLocalizedDescription (schema: LocalizedJSONSchema, locale: string, localeDescription?: string): string | undefined { - return getDescriptions(schema, localeDescription)[locale] -} +export { getDescription, renderJsonSchema } diff --git a/src/index.ts b/src/index.ts index d13ac2c..4460f41 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,10 +1,10 @@ -import { getDescriptions, getLocalizedDescription } from './description' +import { renderJsonSchema, getDescription } from './description' import { Descriptions, LocalizedJSONSchema } from './types' export { Descriptions, LocalizedJSONSchema, - getDescriptions, - getLocalizedDescription + getDescription, + renderJsonSchema } diff --git a/src/test/description.test.ts b/src/test/description.test.ts index af7865d..1316e77 100644 --- a/src/test/description.test.ts +++ b/src/test/description.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from '@jest/globals' import { Descriptions, LocalizedJSONSchema } from '../types' -import { getDescriptions, getLocalizedDescription } from '..' +import { renderJsonSchema, getDescription } from '../description' const description: string = 'test description' const englishDescription: string = 'english description' @@ -19,42 +19,92 @@ const schemaWithoutDescription: LocalizedJSONSchema = { const schemaWithoutDescriptions: LocalizedJSONSchema = { description } +const nestedSchemas: LocalizedJSONSchema = { + description, + descriptions, + items: [fullSchema, schemaWithoutDescription], + additionalItems: false, + contains: fullSchema, + properties: { + test1: schemaWithoutDescriptions, + test2: fullSchema + } +} describe('Full schema', () => { - test('Descriptions', () => { - const localizedDescriptions: Descriptions = getDescriptions(fullSchema) - expect(localizedDescriptions).toMatchObject(descriptions) - }) test('Localized description', () => { - const english = getLocalizedDescription(fullSchema, 'en') - const french = getLocalizedDescription(fullSchema, 'fr') + const english = getDescription(fullSchema, 'en') + const french = getDescription(fullSchema, 'fr') expect(english).toMatch(englishDescription) expect(french).toMatch(frenchDescription) }) + test('Render schema', () => { + const englishSchema = renderJsonSchema('en', fullSchema) + const frenchSchema = renderJsonSchema('fr', fullSchema) + expect(englishSchema).toMatchObject({ description: englishDescription }) + expect(frenchSchema).toMatchObject({ description: frenchDescription }) + }) }) describe('Schema without description', () => { - test('Descriptions', () => { - const localizedDescriptions: Descriptions = getDescriptions(schemaWithoutDescription) - expect(localizedDescriptions).toMatchObject(descriptions) - }) test('Localized description', () => { - const english = getLocalizedDescription(schemaWithoutDescription, 'en') - const french = getLocalizedDescription(schemaWithoutDescription, 'fr') + const english = getDescription(schemaWithoutDescription, 'en') + const french = getDescription(schemaWithoutDescription, 'fr') expect(english).toMatch(englishDescription) expect(french).toMatch(frenchDescription) }) + test('Render schema', () => { + const englishSchema = renderJsonSchema('en', schemaWithoutDescription) + const frenchSchema = renderJsonSchema('fr', schemaWithoutDescription) + expect(englishSchema).toMatchObject({ description: englishDescription }) + expect(frenchSchema).toMatchObject({ description: frenchDescription }) + }) }) describe('Schema without descriptions', () => { - test('Descriptions', () => { - const localizedDescriptions: Descriptions = getDescriptions(schemaWithoutDescriptions) - expect(localizedDescriptions).toMatchObject({ en: description }) - }) test('Localized description', () => { - const english = getLocalizedDescription(schemaWithoutDescriptions, 'en') - const french = getLocalizedDescription(schemaWithoutDescriptions, 'fr') + const english = getDescription(schemaWithoutDescriptions, 'en') + const french = getDescription(schemaWithoutDescriptions, 'fr') expect(english).toMatch(description) - expect(french).toBeUndefined() + expect(french).toMatch(description) + }) + test('Render schema', () => { + const englishSchema = renderJsonSchema('en', schemaWithoutDescriptions) + const frenchSchema = renderJsonSchema('fr', schemaWithoutDescriptions) + expect(englishSchema).toMatchObject({ description }) + expect(frenchSchema).toMatchObject({ description }) + }) +}) + +describe('Nested schemas', () => { + test('Localized description', () => { + const english = getDescription(nestedSchemas, 'en') + const french = getDescription(nestedSchemas, 'fr') + expect(english).toMatch(englishDescription) + expect(french).toMatch(frenchDescription) + }) + test('Render schema', () => { + const englishSchema = renderJsonSchema('en', nestedSchemas) + const frenchSchema = renderJsonSchema('fr', nestedSchemas) + expect(englishSchema).toMatchObject({ + description: englishDescription, + items: [{ description: englishDescription }, { description: englishDescription }], + additionalItems: false, + contains: { description: englishDescription }, + properties: { + test1: { description }, + test2: { description: englishDescription } + } + }) + expect(frenchSchema).toMatchObject({ + description: frenchDescription, + items: [{ description: frenchDescription }, { description: frenchDescription }], + additionalItems: false, + contains: { description: frenchDescription }, + properties: { + test1: { description }, + test2: { description: frenchDescription } + } + }) }) }) diff --git a/src/types.ts b/src/types.ts index 2ee7811..ac42500 100644 --- a/src/types.ts +++ b/src/types.ts @@ -4,6 +4,29 @@ export type Descriptions = { [key: string]: string } +export type LocalizedJSONSchemaDefinition = LocalizedJSONSchema | boolean + export interface LocalizedJSONSchema extends JSONSchema6 { descriptions?: Descriptions + items?: LocalizedJSONSchemaDefinition | LocalizedJSONSchemaDefinition[] + additionalItems?: LocalizedJSONSchemaDefinition + contains?: LocalizedJSONSchemaDefinition + properties?: { + [k: string]: LocalizedJSONSchemaDefinition + } + patternProperties?: { + [k: string]: LocalizedJSONSchemaDefinition + } + additionalProperties?: LocalizedJSONSchemaDefinition + dependencies?: { + [k: string]: LocalizedJSONSchemaDefinition | string[] + } + propertyNames?: LocalizedJSONSchemaDefinition + allOf?: LocalizedJSONSchemaDefinition[] + anyOf?: LocalizedJSONSchemaDefinition[] + oneOf?: LocalizedJSONSchemaDefinition[] + not?: LocalizedJSONSchemaDefinition + definitions?: { + [k: string]: LocalizedJSONSchemaDefinition + } }