From a45b2e32a04df403c5b183dd7b8b36c19e0873e2 Mon Sep 17 00:00:00 2001 From: Claire Saba Date: Thu, 8 Feb 2024 17:01:01 +0100 Subject: [PATCH 01/13] refactor(constants): rename constant and function parameters --- src/constants.ts | 2 +- src/description.ts | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) 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..11a2f44 100644 --- a/src/description.ts +++ b/src/description.ts @@ -1,21 +1,21 @@ -import { DEFAULT_LOCALE_DESCRIPTION } from './constants' +import { DEFAULT_DESCRIPTION_LOCALE } from './constants' import { Descriptions, LocalizedJSONSchema } from './types' import { isNotEmpty } from './utils' -export function getDescriptions (schema: LocalizedJSONSchema, localeDescription: string = DEFAULT_LOCALE_DESCRIPTION): Descriptions { +export function getDescriptions (schema: LocalizedJSONSchema, descriptionLocale: string = DEFAULT_DESCRIPTION_LOCALE): Descriptions { const description = isNotEmpty(schema.description) ? schema.description : undefined const descriptions = schema.descriptions if (descriptions == null) { - return description != null ? { [localeDescription]: description } : {} + return description != null ? { [descriptionLocale]: description } : {} } - if (description != null && !Object.keys(descriptions).includes(localeDescription)) { - descriptions[localeDescription] = description + if (description != null && !Object.keys(descriptions).includes(descriptionLocale)) { + descriptions[descriptionLocale] = description } return descriptions } -export function getLocalizedDescription (schema: LocalizedJSONSchema, locale: string, localeDescription?: string): string | undefined { - return getDescriptions(schema, localeDescription)[locale] +export function getLocalizedDescription (schema: LocalizedJSONSchema, locale: string, descriptionLocale?: string): string | undefined { + return getDescriptions(schema, descriptionLocale)[locale] } From 063de58115e1d48d6d10ecb4aa884bb774f7ba4c Mon Sep 17 00:00:00 2001 From: Claire Saba Date: Thu, 8 Feb 2024 17:02:44 +0100 Subject: [PATCH 02/13] feat(description): add function to recursively convert localized schema to standard JSON schema --- src/description.ts | 31 +++++++++++++++++++++++++++++- src/index.ts | 5 +++-- src/types.ts | 47 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 3 deletions(-) diff --git a/src/description.ts b/src/description.ts index 11a2f44..9443d97 100644 --- a/src/description.ts +++ b/src/description.ts @@ -1,5 +1,6 @@ +import { JSONSchema6 } from 'json-schema' import { DEFAULT_DESCRIPTION_LOCALE } from './constants' -import { Descriptions, LocalizedJSONSchema } from './types' +import { Descriptions, LocalizedJSONSchema, LocalizedSchemaTypes, getValueTypeWithKey } from './types' import { isNotEmpty } from './utils' export function getDescriptions (schema: LocalizedJSONSchema, descriptionLocale: string = DEFAULT_DESCRIPTION_LOCALE): Descriptions { @@ -19,3 +20,31 @@ export function getDescriptions (schema: LocalizedJSONSchema, descriptionLocale: export function getLocalizedDescription (schema: LocalizedJSONSchema, locale: string, descriptionLocale?: string): string | undefined { return getDescriptions(schema, descriptionLocale)[locale] } + +function convertJsonSchemaInObject (object: { [key: string]: unknown }, locale: string, descriptionLocale?: string): { [key: string]: unknown } { + return Object.entries(object).reduce((json, [key, value]) => { + if (value == null) { + return { ...json } + } + const valueType = getValueTypeWithKey(key, value) + if (valueType === LocalizedSchemaTypes.LOCALIZED_SCHEMA) { + return { ...json, [key]: convertToJsonSchema(value as LocalizedJSONSchema, locale, descriptionLocale) } + } + if (Array.isArray(value) && valueType === LocalizedSchemaTypes.ARRAY_OF_LOCALIZED_SCHEMA) { + return { ...json, [key]: value.map(schema => convertToJsonSchema(schema, locale, descriptionLocale)) } + } + if (valueType === LocalizedSchemaTypes.OBJECT_OF_LOCALIZED_SCHEMA) { + return { ...json, [key]: convertJsonSchemaInObject({ ...value }, locale, descriptionLocale) } + } + return { ...json, [key]: value } + }, {}) +} + +export function convertToJsonSchema (schema: LocalizedJSONSchema, locale: string, descriptionLocale?: string): JSONSchema6 { + const description = getLocalizedDescription(schema, locale, descriptionLocale) + const { descriptions, ...jsonSchema } = schema + return { + ...convertJsonSchemaInObject(jsonSchema, locale, descriptionLocale), + description: description ?? jsonSchema.description + } +} diff --git a/src/index.ts b/src/index.ts index d13ac2c..5df3e2d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,4 @@ -import { getDescriptions, getLocalizedDescription } from './description' +import { convertToJsonSchema, getDescriptions, getLocalizedDescription } from './description' import { Descriptions, LocalizedJSONSchema } from './types' export { @@ -6,5 +6,6 @@ export { LocalizedJSONSchema, getDescriptions, - getLocalizedDescription + getLocalizedDescription, + convertToJsonSchema } diff --git a/src/types.ts b/src/types.ts index 2ee7811..25a574a 100644 --- a/src/types.ts +++ b/src/types.ts @@ -4,6 +4,53 @@ 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 + } +} + +export enum LocalizedSchemaTypes { + ARRAY_OF_LOCALIZED_SCHEMA = 'ARRAY_OF_LOCALIZED_SCHEMA', + OBJECT_OF_LOCALIZED_SCHEMA = 'OBJECT_OF_LOCALIZED_SCHEMA', + LOCALIZED_SCHEMA = 'LOCALIZED_SCHEMA' +} +export function getValueTypeWithKey (key: string, value: unknown): string { + if (value == null) { + return typeof value + } + if (typeof value === 'object') { + if (Array.isArray(value) && ['items', 'allOf', 'anyOf', 'oneOf'].includes(key)) { + return LocalizedSchemaTypes.ARRAY_OF_LOCALIZED_SCHEMA + } + if (['properties', 'patternProperties', 'dependencies', 'definitions'].includes(key)) { + return LocalizedSchemaTypes.OBJECT_OF_LOCALIZED_SCHEMA + } + if (['items', 'additionalItems', 'contains', 'additionalProperties', 'propertyNames', 'not'].includes(key) || Object.keys(value).includes('descriptions')) { + return LocalizedSchemaTypes.LOCALIZED_SCHEMA + } + return 'object' + } + return typeof value } From de32785875152035c4cb8eaf0e20e34d1883099c Mon Sep 17 00:00:00 2001 From: Claire Saba Date: Thu, 8 Feb 2024 17:03:05 +0100 Subject: [PATCH 03/13] test(description): add test for convert function --- src/test/description.test.ts | 68 +++++++++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/src/test/description.test.ts b/src/test/description.test.ts index af7865d..1df330a 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 { convertToJsonSchema, getDescriptions, getLocalizedDescription } from '../description' const description: string = 'test description' const englishDescription: string = 'english description' @@ -19,6 +19,17 @@ 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', () => { @@ -31,6 +42,12 @@ describe('Full schema', () => { expect(english).toMatch(englishDescription) expect(french).toMatch(frenchDescription) }) + test('Convert schema', () => { + const englishSchema = convertToJsonSchema(fullSchema, 'en') + const frenchSchema = convertToJsonSchema(fullSchema, 'fr') + expect(englishSchema).toMatchObject({ description: englishDescription }) + expect(frenchSchema).toMatchObject({ description: frenchDescription }) + }) }) describe('Schema without description', () => { @@ -44,6 +61,12 @@ describe('Schema without description', () => { expect(english).toMatch(englishDescription) expect(french).toMatch(frenchDescription) }) + test('Convert schema', () => { + const englishSchema = convertToJsonSchema(schemaWithoutDescription, 'en') + const frenchSchema = convertToJsonSchema(schemaWithoutDescription, 'fr') + expect(englishSchema).toMatchObject({ description: englishDescription }) + expect(frenchSchema).toMatchObject({ description: frenchDescription }) + }) }) describe('Schema without descriptions', () => { @@ -57,4 +80,47 @@ describe('Schema without descriptions', () => { expect(english).toMatch(description) expect(french).toBeUndefined() }) + test('Convert schema', () => { + const englishSchema = convertToJsonSchema(schemaWithoutDescriptions, 'en') + const frenchSchema = convertToJsonSchema(schemaWithoutDescriptions, 'fr') + expect(englishSchema).toMatchObject({ description }) + expect(frenchSchema).toMatchObject({ description }) + }) +}) + +describe('Nested schemas', () => { + test('Descriptions', () => { + const localizedDescriptions: Descriptions = getDescriptions(nestedSchemas) + expect(localizedDescriptions).toMatchObject(descriptions) + }) + test('Localized description', () => { + const english = getLocalizedDescription(nestedSchemas, 'en') + const french = getLocalizedDescription(nestedSchemas, 'fr') + expect(english).toMatch(englishDescription) + expect(french).toMatch(frenchDescription) + }) + test('Convert schema', () => { + const englishSchema = convertToJsonSchema(nestedSchemas, 'en') + const frenchSchema = convertToJsonSchema(nestedSchemas, 'fr') + 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 } + } + }) + }) }) From e1c1ff8eafcf69755c9af86b97b714aa473af69d Mon Sep 17 00:00:00 2001 From: Claire Saba Date: Thu, 8 Feb 2024 17:26:02 +0100 Subject: [PATCH 04/13] refactor(description): rename convertToJsonSchema to renderJsonSchema --- src/description.ts | 6 +++--- src/index.ts | 4 ++-- src/test/description.test.ts | 18 +++++++++--------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/description.ts b/src/description.ts index 9443d97..be13bfe 100644 --- a/src/description.ts +++ b/src/description.ts @@ -28,10 +28,10 @@ function convertJsonSchemaInObject (object: { [key: string]: unknown }, locale: } const valueType = getValueTypeWithKey(key, value) if (valueType === LocalizedSchemaTypes.LOCALIZED_SCHEMA) { - return { ...json, [key]: convertToJsonSchema(value as LocalizedJSONSchema, locale, descriptionLocale) } + return { ...json, [key]: renderJsonSchema(value as LocalizedJSONSchema, locale, descriptionLocale) } } if (Array.isArray(value) && valueType === LocalizedSchemaTypes.ARRAY_OF_LOCALIZED_SCHEMA) { - return { ...json, [key]: value.map(schema => convertToJsonSchema(schema, locale, descriptionLocale)) } + return { ...json, [key]: value.map(schema => renderJsonSchema(schema, locale, descriptionLocale)) } } if (valueType === LocalizedSchemaTypes.OBJECT_OF_LOCALIZED_SCHEMA) { return { ...json, [key]: convertJsonSchemaInObject({ ...value }, locale, descriptionLocale) } @@ -40,7 +40,7 @@ function convertJsonSchemaInObject (object: { [key: string]: unknown }, locale: }, {}) } -export function convertToJsonSchema (schema: LocalizedJSONSchema, locale: string, descriptionLocale?: string): JSONSchema6 { +export function renderJsonSchema (schema: LocalizedJSONSchema, locale: string, descriptionLocale?: string): JSONSchema6 { const description = getLocalizedDescription(schema, locale, descriptionLocale) const { descriptions, ...jsonSchema } = schema return { diff --git a/src/index.ts b/src/index.ts index 5df3e2d..8b50394 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,4 @@ -import { convertToJsonSchema, getDescriptions, getLocalizedDescription } from './description' +import { renderJsonSchema, getDescriptions, getLocalizedDescription } from './description' import { Descriptions, LocalizedJSONSchema } from './types' export { @@ -7,5 +7,5 @@ export { getDescriptions, getLocalizedDescription, - convertToJsonSchema + renderJsonSchema } diff --git a/src/test/description.test.ts b/src/test/description.test.ts index 1df330a..ab5fad4 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 { convertToJsonSchema, getDescriptions, getLocalizedDescription } from '../description' +import { renderJsonSchema, getDescriptions, getLocalizedDescription } from '../description' const description: string = 'test description' const englishDescription: string = 'english description' @@ -43,8 +43,8 @@ describe('Full schema', () => { expect(french).toMatch(frenchDescription) }) test('Convert schema', () => { - const englishSchema = convertToJsonSchema(fullSchema, 'en') - const frenchSchema = convertToJsonSchema(fullSchema, 'fr') + const englishSchema = renderJsonSchema(fullSchema, 'en') + const frenchSchema = renderJsonSchema(fullSchema, 'fr') expect(englishSchema).toMatchObject({ description: englishDescription }) expect(frenchSchema).toMatchObject({ description: frenchDescription }) }) @@ -62,8 +62,8 @@ describe('Schema without description', () => { expect(french).toMatch(frenchDescription) }) test('Convert schema', () => { - const englishSchema = convertToJsonSchema(schemaWithoutDescription, 'en') - const frenchSchema = convertToJsonSchema(schemaWithoutDescription, 'fr') + const englishSchema = renderJsonSchema(schemaWithoutDescription, 'en') + const frenchSchema = renderJsonSchema(schemaWithoutDescription, 'fr') expect(englishSchema).toMatchObject({ description: englishDescription }) expect(frenchSchema).toMatchObject({ description: frenchDescription }) }) @@ -81,8 +81,8 @@ describe('Schema without descriptions', () => { expect(french).toBeUndefined() }) test('Convert schema', () => { - const englishSchema = convertToJsonSchema(schemaWithoutDescriptions, 'en') - const frenchSchema = convertToJsonSchema(schemaWithoutDescriptions, 'fr') + const englishSchema = renderJsonSchema(schemaWithoutDescriptions, 'en') + const frenchSchema = renderJsonSchema(schemaWithoutDescriptions, 'fr') expect(englishSchema).toMatchObject({ description }) expect(frenchSchema).toMatchObject({ description }) }) @@ -100,8 +100,8 @@ describe('Nested schemas', () => { expect(french).toMatch(frenchDescription) }) test('Convert schema', () => { - const englishSchema = convertToJsonSchema(nestedSchemas, 'en') - const frenchSchema = convertToJsonSchema(nestedSchemas, 'fr') + const englishSchema = renderJsonSchema(nestedSchemas, 'en') + const frenchSchema = renderJsonSchema(nestedSchemas, 'fr') expect(englishSchema).toMatchObject({ description: englishDescription, items: [{ description: englishDescription }, { description: englishDescription }], From cb4a5f2491dee8dcfd01cf3982858da9db2be024 Mon Sep 17 00:00:00 2001 From: Claire Saba Date: Thu, 8 Feb 2024 18:09:52 +0100 Subject: [PATCH 05/13] refactor(description): simplify recursive render of json schema --- src/description.ts | 83 ++++++++++++++++++++++++++++++++++------------ src/types.ts | 24 -------------- 2 files changed, 62 insertions(+), 45 deletions(-) diff --git a/src/description.ts b/src/description.ts index be13bfe..d1df67c 100644 --- a/src/description.ts +++ b/src/description.ts @@ -1,6 +1,6 @@ -import { JSONSchema6 } from 'json-schema' +import { JSONSchema6, JSONSchema6Definition } from 'json-schema' import { DEFAULT_DESCRIPTION_LOCALE } from './constants' -import { Descriptions, LocalizedJSONSchema, LocalizedSchemaTypes, getValueTypeWithKey } from './types' +import { Descriptions, LocalizedJSONSchema, LocalizedJSONSchemaDefinition } from './types' import { isNotEmpty } from './utils' export function getDescriptions (schema: LocalizedJSONSchema, descriptionLocale: string = DEFAULT_DESCRIPTION_LOCALE): Descriptions { @@ -21,30 +21,71 @@ export function getLocalizedDescription (schema: LocalizedJSONSchema, locale: st return getDescriptions(schema, descriptionLocale)[locale] } -function convertJsonSchemaInObject (object: { [key: string]: unknown }, locale: string, descriptionLocale?: string): { [key: string]: unknown } { - return Object.entries(object).reduce((json, [key, value]) => { - if (value == null) { - return { ...json } - } - const valueType = getValueTypeWithKey(key, value) - if (valueType === LocalizedSchemaTypes.LOCALIZED_SCHEMA) { - return { ...json, [key]: renderJsonSchema(value as LocalizedJSONSchema, locale, descriptionLocale) } - } - if (Array.isArray(value) && valueType === LocalizedSchemaTypes.ARRAY_OF_LOCALIZED_SCHEMA) { - return { ...json, [key]: value.map(schema => renderJsonSchema(schema, locale, descriptionLocale)) } - } - if (valueType === LocalizedSchemaTypes.OBJECT_OF_LOCALIZED_SCHEMA) { - return { ...json, [key]: convertJsonSchemaInObject({ ...value }, locale, descriptionLocale) } - } - return { ...json, [key]: value } - }, {}) +function renderSimpleJsonSchema (locale: string, schema?: LocalizedJSONSchemaDefinition, descriptionLocale?: string): JSONSchema6Definition | undefined { + return schema == null + ? undefined + : typeof schema === 'boolean' + ? schema + : renderJsonSchema(schema, locale, descriptionLocale) +} + +function renderArrayOfJsonSchema (locale: string, array?: LocalizedJSONSchemaDefinition[], descriptionLocale?: string): JSONSchema6Definition[] | undefined { + return array?.map(schema => renderSimpleJsonSchema(locale, schema, descriptionLocale) as JSONSchema6Definition) +} + +function renderObjectOfJsonSchema (locale: string, object?: { [key: string]: LocalizedJSONSchemaDefinition }, descriptionLocale?: string): { [key: string]: JSONSchema6Definition } | undefined { + return object == null + ? undefined + : Object.entries(object).reduce((newSchema, [key, schema]) => ({ + ...newSchema, + [key]: renderSimpleJsonSchema(locale, schema, descriptionLocale) + }), {}) } export function renderJsonSchema (schema: LocalizedJSONSchema, locale: string, descriptionLocale?: string): JSONSchema6 { const description = getLocalizedDescription(schema, locale, descriptionLocale) - const { descriptions, ...jsonSchema } = schema + 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 : renderSimpleJsonSchema(locale, schema, descriptionLocale) + }), {}) + return { - ...convertJsonSchemaInObject(jsonSchema, locale, descriptionLocale), + ...jsonSchema, + items: Array.isArray(items) + ? renderArrayOfJsonSchema(locale, items, descriptionLocale) + : renderSimpleJsonSchema(locale, items, descriptionLocale), + additionalItems: renderSimpleJsonSchema(locale, additionalItems, descriptionLocale), + contains: renderSimpleJsonSchema(locale, contains, descriptionLocale), + properties: renderObjectOfJsonSchema(locale, properties, descriptionLocale), + patternProperties: renderObjectOfJsonSchema(locale, patternProperties, descriptionLocale), + additionalProperties: renderSimpleJsonSchema(locale, additionalProperties, descriptionLocale), + dependencies: newDependencies, + propertyNames: renderSimpleJsonSchema(locale, propertyNames, descriptionLocale), + allOf: renderArrayOfJsonSchema(locale, allOf, descriptionLocale), + anyOf: renderArrayOfJsonSchema(locale, anyOf, descriptionLocale), + oneOf: renderArrayOfJsonSchema(locale, oneOf, descriptionLocale), + not: renderSimpleJsonSchema(locale, not, descriptionLocale), + definitions: renderObjectOfJsonSchema(locale, definitions, descriptionLocale), description: description ?? jsonSchema.description } } diff --git a/src/types.ts b/src/types.ts index 25a574a..ac42500 100644 --- a/src/types.ts +++ b/src/types.ts @@ -30,27 +30,3 @@ export interface LocalizedJSONSchema extends JSONSchema6 { [k: string]: LocalizedJSONSchemaDefinition } } - -export enum LocalizedSchemaTypes { - ARRAY_OF_LOCALIZED_SCHEMA = 'ARRAY_OF_LOCALIZED_SCHEMA', - OBJECT_OF_LOCALIZED_SCHEMA = 'OBJECT_OF_LOCALIZED_SCHEMA', - LOCALIZED_SCHEMA = 'LOCALIZED_SCHEMA' -} -export function getValueTypeWithKey (key: string, value: unknown): string { - if (value == null) { - return typeof value - } - if (typeof value === 'object') { - if (Array.isArray(value) && ['items', 'allOf', 'anyOf', 'oneOf'].includes(key)) { - return LocalizedSchemaTypes.ARRAY_OF_LOCALIZED_SCHEMA - } - if (['properties', 'patternProperties', 'dependencies', 'definitions'].includes(key)) { - return LocalizedSchemaTypes.OBJECT_OF_LOCALIZED_SCHEMA - } - if (['items', 'additionalItems', 'contains', 'additionalProperties', 'propertyNames', 'not'].includes(key) || Object.keys(value).includes('descriptions')) { - return LocalizedSchemaTypes.LOCALIZED_SCHEMA - } - return 'object' - } - return typeof value -} From ea7db635cd4d97dba350a286548233654d9bd0d5 Mon Sep 17 00:00:00 2001 From: Claire Saba Date: Thu, 8 Feb 2024 18:11:45 +0100 Subject: [PATCH 06/13] doc(readme): add renderJsonSchema function to readme --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 2825bf3..f9db87e 100644 --- a/README.md +++ b/README.md @@ -29,3 +29,6 @@ The implemented functions are: - `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'`) - returns the description for the wanted locale, or `undefined` if not found +- `renderJsonSchema`: + - 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'`) + - returns the `JSONSchema6` equivalent with the selected locale From 0b2d188fe1dbfd5c2493f60afba1778836e01f32 Mon Sep 17 00:00:00 2001 From: Claire Saba Date: Wed, 14 Feb 2024 09:58:44 +0100 Subject: [PATCH 07/13] refactor(description): merge the getDescriptions and getLocalizedDescription in one --- src/description.ts | 21 ++++----------------- src/index.ts | 5 ++--- 2 files changed, 6 insertions(+), 20 deletions(-) diff --git a/src/description.ts b/src/description.ts index d1df67c..2015ced 100644 --- a/src/description.ts +++ b/src/description.ts @@ -1,24 +1,11 @@ import { JSONSchema6, JSONSchema6Definition } from 'json-schema' import { DEFAULT_DESCRIPTION_LOCALE } from './constants' -import { Descriptions, LocalizedJSONSchema, LocalizedJSONSchemaDefinition } from './types' +import { LocalizedJSONSchema, LocalizedJSONSchemaDefinition } from './types' import { isNotEmpty } from './utils' -export function getDescriptions (schema: LocalizedJSONSchema, descriptionLocale: string = DEFAULT_DESCRIPTION_LOCALE): Descriptions { +export function getDescription (schema: LocalizedJSONSchema, locale: string = DEFAULT_DESCRIPTION_LOCALE): string | undefined { const description = isNotEmpty(schema.description) ? schema.description : undefined - const descriptions = schema.descriptions - - if (descriptions == null) { - return description != null ? { [descriptionLocale]: description } : {} - } - - if (description != null && !Object.keys(descriptions).includes(descriptionLocale)) { - descriptions[descriptionLocale] = description - } - return descriptions -} - -export function getLocalizedDescription (schema: LocalizedJSONSchema, locale: string, descriptionLocale?: string): string | undefined { - return getDescriptions(schema, descriptionLocale)[locale] + return schema.descriptions?.[locale] ?? description } function renderSimpleJsonSchema (locale: string, schema?: LocalizedJSONSchemaDefinition, descriptionLocale?: string): JSONSchema6Definition | undefined { @@ -43,7 +30,7 @@ function renderObjectOfJsonSchema (locale: string, object?: { [key: string]: Loc } export function renderJsonSchema (schema: LocalizedJSONSchema, locale: string, descriptionLocale?: string): JSONSchema6 { - const description = getLocalizedDescription(schema, locale, descriptionLocale) + const description = getDescription(schema, locale) const { descriptions, items, diff --git a/src/index.ts b/src/index.ts index 8b50394..4460f41 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,11 +1,10 @@ -import { renderJsonSchema, getDescriptions, getLocalizedDescription } from './description' +import { renderJsonSchema, getDescription } from './description' import { Descriptions, LocalizedJSONSchema } from './types' export { Descriptions, LocalizedJSONSchema, - getDescriptions, - getLocalizedDescription, + getDescription, renderJsonSchema } From d0c7e4f4433ebee9dfbce2c2e3b09c15e5273e6a Mon Sep 17 00:00:00 2001 From: Claire Saba Date: Wed, 14 Feb 2024 10:00:11 +0100 Subject: [PATCH 08/13] cleanup(description): remove configurable default locale for description --- src/description.ts | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/description.ts b/src/description.ts index 2015ced..5f9d6cb 100644 --- a/src/description.ts +++ b/src/description.ts @@ -8,28 +8,28 @@ export function getDescription (schema: LocalizedJSONSchema, locale: string = DE return schema.descriptions?.[locale] ?? description } -function renderSimpleJsonSchema (locale: string, schema?: LocalizedJSONSchemaDefinition, descriptionLocale?: string): JSONSchema6Definition | undefined { +function renderSimpleJsonSchema (locale: string, schema?: LocalizedJSONSchemaDefinition): JSONSchema6Definition | undefined { return schema == null ? undefined : typeof schema === 'boolean' ? schema - : renderJsonSchema(schema, locale, descriptionLocale) + : renderJsonSchema(schema, locale) } -function renderArrayOfJsonSchema (locale: string, array?: LocalizedJSONSchemaDefinition[], descriptionLocale?: string): JSONSchema6Definition[] | undefined { - return array?.map(schema => renderSimpleJsonSchema(locale, schema, descriptionLocale) as JSONSchema6Definition) +function renderArrayOfJsonSchema (locale: string, array?: LocalizedJSONSchemaDefinition[]): JSONSchema6Definition[] | undefined { + return array?.map(schema => renderSimpleJsonSchema(locale, schema) as JSONSchema6Definition) } -function renderObjectOfJsonSchema (locale: string, object?: { [key: string]: LocalizedJSONSchemaDefinition }, descriptionLocale?: string): { [key: string]: JSONSchema6Definition } | undefined { +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]: renderSimpleJsonSchema(locale, schema, descriptionLocale) + [key]: renderSimpleJsonSchema(locale, schema) }), {}) } -export function renderJsonSchema (schema: LocalizedJSONSchema, locale: string, descriptionLocale?: string): JSONSchema6 { +export function renderJsonSchema (schema: LocalizedJSONSchema, locale: string): JSONSchema6 { const description = getDescription(schema, locale) const { descriptions, @@ -53,26 +53,26 @@ export function renderJsonSchema (schema: LocalizedJSONSchema, locale: string, d ? undefined : Object.entries(dependencies).reduce((newSchema, [key, schema]) => ({ ...newSchema, - [key]: Array.isArray(schema) ? schema : renderSimpleJsonSchema(locale, schema, descriptionLocale) + [key]: Array.isArray(schema) ? schema : renderSimpleJsonSchema(locale, schema) }), {}) return { ...jsonSchema, items: Array.isArray(items) - ? renderArrayOfJsonSchema(locale, items, descriptionLocale) - : renderSimpleJsonSchema(locale, items, descriptionLocale), - additionalItems: renderSimpleJsonSchema(locale, additionalItems, descriptionLocale), - contains: renderSimpleJsonSchema(locale, contains, descriptionLocale), - properties: renderObjectOfJsonSchema(locale, properties, descriptionLocale), - patternProperties: renderObjectOfJsonSchema(locale, patternProperties, descriptionLocale), - additionalProperties: renderSimpleJsonSchema(locale, additionalProperties, descriptionLocale), + ? renderArrayOfJsonSchema(locale, items) + : renderSimpleJsonSchema(locale, items), + additionalItems: renderSimpleJsonSchema(locale, additionalItems), + contains: renderSimpleJsonSchema(locale, contains), + properties: renderObjectOfJsonSchema(locale, properties), + patternProperties: renderObjectOfJsonSchema(locale, patternProperties), + additionalProperties: renderSimpleJsonSchema(locale, additionalProperties), dependencies: newDependencies, - propertyNames: renderSimpleJsonSchema(locale, propertyNames, descriptionLocale), - allOf: renderArrayOfJsonSchema(locale, allOf, descriptionLocale), - anyOf: renderArrayOfJsonSchema(locale, anyOf, descriptionLocale), - oneOf: renderArrayOfJsonSchema(locale, oneOf, descriptionLocale), - not: renderSimpleJsonSchema(locale, not, descriptionLocale), - definitions: renderObjectOfJsonSchema(locale, definitions, descriptionLocale), + propertyNames: renderSimpleJsonSchema(locale, propertyNames), + allOf: renderArrayOfJsonSchema(locale, allOf), + anyOf: renderArrayOfJsonSchema(locale, anyOf), + oneOf: renderArrayOfJsonSchema(locale, oneOf), + not: renderSimpleJsonSchema(locale, not), + definitions: renderObjectOfJsonSchema(locale, definitions), description: description ?? jsonSchema.description } } From bfa793c2fcc6504d41b75d590442e210fe858f23 Mon Sep 17 00:00:00 2001 From: Claire Saba Date: Wed, 14 Feb 2024 10:00:46 +0100 Subject: [PATCH 09/13] test(description): update tests on descriptions --- src/test/description.test.ts | 44 ++++++++++++------------------------ 1 file changed, 14 insertions(+), 30 deletions(-) diff --git a/src/test/description.test.ts b/src/test/description.test.ts index ab5fad4..f332c68 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 { renderJsonSchema, getDescriptions, getLocalizedDescription } from '../description' +import { renderJsonSchema, getDescription } from '../description' const description: string = 'test description' const englishDescription: string = 'english description' @@ -32,17 +32,13 @@ const nestedSchemas: LocalizedJSONSchema = { } 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('Convert schema', () => { + test('Render schema', () => { const englishSchema = renderJsonSchema(fullSchema, 'en') const frenchSchema = renderJsonSchema(fullSchema, 'fr') expect(englishSchema).toMatchObject({ description: englishDescription }) @@ -51,17 +47,13 @@ describe('Full schema', () => { }) 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('Convert schema', () => { + test('Render schema', () => { const englishSchema = renderJsonSchema(schemaWithoutDescription, 'en') const frenchSchema = renderJsonSchema(schemaWithoutDescription, 'fr') expect(englishSchema).toMatchObject({ description: englishDescription }) @@ -70,17 +62,13 @@ describe('Schema without description', () => { }) 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('Convert schema', () => { + test('Render schema', () => { const englishSchema = renderJsonSchema(schemaWithoutDescriptions, 'en') const frenchSchema = renderJsonSchema(schemaWithoutDescriptions, 'fr') expect(englishSchema).toMatchObject({ description }) @@ -89,17 +77,13 @@ describe('Schema without descriptions', () => { }) describe('Nested schemas', () => { - test('Descriptions', () => { - const localizedDescriptions: Descriptions = getDescriptions(nestedSchemas) - expect(localizedDescriptions).toMatchObject(descriptions) - }) test('Localized description', () => { - const english = getLocalizedDescription(nestedSchemas, 'en') - const french = getLocalizedDescription(nestedSchemas, 'fr') + const english = getDescription(nestedSchemas, 'en') + const french = getDescription(nestedSchemas, 'fr') expect(english).toMatch(englishDescription) expect(french).toMatch(frenchDescription) }) - test('Convert schema', () => { + test('Render schema', () => { const englishSchema = renderJsonSchema(nestedSchemas, 'en') const frenchSchema = renderJsonSchema(nestedSchemas, 'fr') expect(englishSchema).toMatchObject({ From 94ad7d56fc63f62e354895fa3ffebfc271070078 Mon Sep 17 00:00:00 2001 From: Claire Saba Date: Wed, 14 Feb 2024 11:44:00 +0100 Subject: [PATCH 10/13] refactor(description): merge renderJsonSchema and renderSimpleJsonSchema --- src/description.ts | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/src/description.ts b/src/description.ts index 5f9d6cb..64e470f 100644 --- a/src/description.ts +++ b/src/description.ts @@ -3,21 +3,13 @@ import { DEFAULT_DESCRIPTION_LOCALE } from './constants' import { LocalizedJSONSchema, LocalizedJSONSchemaDefinition } from './types' import { isNotEmpty } from './utils' -export function getDescription (schema: LocalizedJSONSchema, locale: string = DEFAULT_DESCRIPTION_LOCALE): string | undefined { +function getDescription (schema: LocalizedJSONSchema, locale: string = DEFAULT_DESCRIPTION_LOCALE): string | undefined { const description = isNotEmpty(schema.description) ? schema.description : undefined return schema.descriptions?.[locale] ?? description } -function renderSimpleJsonSchema (locale: string, schema?: LocalizedJSONSchemaDefinition): JSONSchema6Definition | undefined { - return schema == null - ? undefined - : typeof schema === 'boolean' - ? schema - : renderJsonSchema(schema, locale) -} - function renderArrayOfJsonSchema (locale: string, array?: LocalizedJSONSchemaDefinition[]): JSONSchema6Definition[] | undefined { - return array?.map(schema => renderSimpleJsonSchema(locale, schema) as JSONSchema6Definition) + 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 { @@ -25,11 +17,21 @@ function renderObjectOfJsonSchema (locale: string, object?: { [key: string]: Loc ? undefined : Object.entries(object).reduce((newSchema, [key, schema]) => ({ ...newSchema, - [key]: renderSimpleJsonSchema(locale, schema) + [key]: renderJsonSchema(locale, schema) }), {}) } -export function renderJsonSchema (schema: LocalizedJSONSchema, locale: string): JSONSchema6 { +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 + } + const description = getDescription(schema, locale) const { descriptions, @@ -53,26 +55,28 @@ export function renderJsonSchema (schema: LocalizedJSONSchema, locale: string): ? undefined : Object.entries(dependencies).reduce((newSchema, [key, schema]) => ({ ...newSchema, - [key]: Array.isArray(schema) ? schema : renderSimpleJsonSchema(locale, schema) + [key]: Array.isArray(schema) ? schema : renderJsonSchema(locale, schema) }), {}) return { ...jsonSchema, items: Array.isArray(items) ? renderArrayOfJsonSchema(locale, items) - : renderSimpleJsonSchema(locale, items), - additionalItems: renderSimpleJsonSchema(locale, additionalItems), - contains: renderSimpleJsonSchema(locale, contains), + : renderJsonSchema(locale, items), + additionalItems: renderJsonSchema(locale, additionalItems), + contains: renderJsonSchema(locale, contains), properties: renderObjectOfJsonSchema(locale, properties), patternProperties: renderObjectOfJsonSchema(locale, patternProperties), - additionalProperties: renderSimpleJsonSchema(locale, additionalProperties), + additionalProperties: renderJsonSchema(locale, additionalProperties), dependencies: newDependencies, - propertyNames: renderSimpleJsonSchema(locale, propertyNames), + propertyNames: renderJsonSchema(locale, propertyNames), allOf: renderArrayOfJsonSchema(locale, allOf), anyOf: renderArrayOfJsonSchema(locale, anyOf), oneOf: renderArrayOfJsonSchema(locale, oneOf), - not: renderSimpleJsonSchema(locale, not), + not: renderJsonSchema(locale, not), definitions: renderObjectOfJsonSchema(locale, definitions), description: description ?? jsonSchema.description } } + +export { getDescription, renderJsonSchema } From 7e4cbc2a21aa9956ed8a6e92db79c49b73595bc7 Mon Sep 17 00:00:00 2001 From: Claire Saba Date: Wed, 14 Feb 2024 11:44:22 +0100 Subject: [PATCH 11/13] test(description): update tests on descriptions --- src/test/description.test.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/test/description.test.ts b/src/test/description.test.ts index f332c68..1316e77 100644 --- a/src/test/description.test.ts +++ b/src/test/description.test.ts @@ -39,8 +39,8 @@ describe('Full schema', () => { expect(french).toMatch(frenchDescription) }) test('Render schema', () => { - const englishSchema = renderJsonSchema(fullSchema, 'en') - const frenchSchema = renderJsonSchema(fullSchema, 'fr') + const englishSchema = renderJsonSchema('en', fullSchema) + const frenchSchema = renderJsonSchema('fr', fullSchema) expect(englishSchema).toMatchObject({ description: englishDescription }) expect(frenchSchema).toMatchObject({ description: frenchDescription }) }) @@ -54,8 +54,8 @@ describe('Schema without description', () => { expect(french).toMatch(frenchDescription) }) test('Render schema', () => { - const englishSchema = renderJsonSchema(schemaWithoutDescription, 'en') - const frenchSchema = renderJsonSchema(schemaWithoutDescription, 'fr') + const englishSchema = renderJsonSchema('en', schemaWithoutDescription) + const frenchSchema = renderJsonSchema('fr', schemaWithoutDescription) expect(englishSchema).toMatchObject({ description: englishDescription }) expect(frenchSchema).toMatchObject({ description: frenchDescription }) }) @@ -69,8 +69,8 @@ describe('Schema without descriptions', () => { expect(french).toMatch(description) }) test('Render schema', () => { - const englishSchema = renderJsonSchema(schemaWithoutDescriptions, 'en') - const frenchSchema = renderJsonSchema(schemaWithoutDescriptions, 'fr') + const englishSchema = renderJsonSchema('en', schemaWithoutDescriptions) + const frenchSchema = renderJsonSchema('fr', schemaWithoutDescriptions) expect(englishSchema).toMatchObject({ description }) expect(frenchSchema).toMatchObject({ description }) }) @@ -84,8 +84,8 @@ describe('Nested schemas', () => { expect(french).toMatch(frenchDescription) }) test('Render schema', () => { - const englishSchema = renderJsonSchema(nestedSchemas, 'en') - const frenchSchema = renderJsonSchema(nestedSchemas, 'fr') + const englishSchema = renderJsonSchema('en', nestedSchemas) + const frenchSchema = renderJsonSchema('fr', nestedSchemas) expect(englishSchema).toMatchObject({ description: englishDescription, items: [{ description: englishDescription }, { description: englishDescription }], From 32668b88c181732dac3161c3f9d7df8f4025014a Mon Sep 17 00:00:00 2001 From: Claire Saba Date: Wed, 14 Feb 2024 14:08:31 +0100 Subject: [PATCH 12/13] doc(readme): update readme --- README.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index f9db87e..82fc0e3 100644 --- a/README.md +++ b/README.md @@ -23,12 +23,11 @@ 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 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'`) - - returns the `JSONSchema6` equivalent with the selected locale + - it can take in parameters the locale for which we want the description and a schema with localized descriptions and returns the `JSONSchema6` equivalent with the selected locale + - it can take in parameters the locale for which we want the description and a boolean and returns the boolean + - it can take in parameters the locale for which we want the description and an undefined schema and returns `undefined` + - it can take in parameters the locale for which we want the description and an optional schema with localized descriptions or boolean and returns the `JSONSchema6Definition` equivalent with the selected locale From a57110281587fd1dffd696d818a7218056bee979 Mon Sep 17 00:00:00 2001 From: Claire Saba Date: Wed, 14 Feb 2024 14:33:35 +0100 Subject: [PATCH 13/13] doc(readme): simplify renderJsonSchema description in readme --- README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 82fc0e3..afff0b3 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,5 @@ The implemented functions are: - 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`: - - it can take in parameters the locale for which we want the description and a schema with localized descriptions and returns the `JSONSchema6` equivalent with the selected locale - - it can take in parameters the locale for which we want the description and a boolean and returns the boolean - - it can take in parameters the locale for which we want the description and an undefined schema and returns `undefined` - - it can take in parameters the locale for which we want the description and an optional schema with localized descriptions or boolean and returns the `JSONSchema6Definition` equivalent with the selected locale + - 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