From 9f388bf182fe741e4dccb2dc3b1d6a50389ee842 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jurgen=20Belie=CC=88n?= Date: Thu, 9 Dec 2021 18:27:55 +0100 Subject: [PATCH 1/6] feat: add descriptions to schema output --- rollup.config.js | 1 + src/templates/partials/schemaComposition.hbs | 3 +++ src/templates/partials/schemaGeneric.hbs | 3 +++ src/templates/partials/schemaInterface.hbs | 3 +++ src/utils/registerHandlebarHelpers.ts | 4 ++++ 5 files changed, 14 insertions(+) diff --git a/rollup.config.js b/rollup.config.js index 6333316d..60545d7c 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -32,6 +32,7 @@ const handlebarsPlugin = () => ({ preventIndent: true, knownHelpersOnly: true, knownHelpers: { + escapeQuotes: true, equals: true, notEquals: true, containsSpaces: true, diff --git a/src/templates/partials/schemaComposition.hbs b/src/templates/partials/schemaComposition.hbs index 32c5a647..005ea046 100644 --- a/src/templates/partials/schemaComposition.hbs +++ b/src/templates/partials/schemaComposition.hbs @@ -1,5 +1,8 @@ { type: '{{export}}', +{{#if description}} + description: '{{{escapeQuotes description}}}', +{{/if}} contains: [{{#each properties}}{{>schema}}{{#unless @last}}, {{/unless}}{{/each}}], {{#if isReadOnly}} isReadOnly: {{{isReadOnly}}}, diff --git a/src/templates/partials/schemaGeneric.hbs b/src/templates/partials/schemaGeneric.hbs index 7b0d96c9..d41956a8 100644 --- a/src/templates/partials/schemaGeneric.hbs +++ b/src/templates/partials/schemaGeneric.hbs @@ -2,6 +2,9 @@ {{#if type}} type: '{{{base}}}', {{/if}} +{{#if description}} + description: '{{{escapeQuotes description}}}', +{{/if}} {{#if isReadOnly}} isReadOnly: {{{isReadOnly}}}, {{/if}} diff --git a/src/templates/partials/schemaInterface.hbs b/src/templates/partials/schemaInterface.hbs index 88460880..0488adae 100644 --- a/src/templates/partials/schemaInterface.hbs +++ b/src/templates/partials/schemaInterface.hbs @@ -1,4 +1,7 @@ { +{{#if description}} + description: '{{{escapeQuotes description}}}', +{{/if}} properties: { {{#if properties}} {{#each properties}} diff --git a/src/utils/registerHandlebarHelpers.ts b/src/utils/registerHandlebarHelpers.ts index a937d1cf..99c5dca2 100644 --- a/src/utils/registerHandlebarHelpers.ts +++ b/src/utils/registerHandlebarHelpers.ts @@ -10,6 +10,10 @@ export function registerHandlebarHelpers(root: { useOptions: boolean; useUnionTypes: boolean; }): void { + Handlebars.registerHelper('escapeQuotes', function (value: string): string { + return value.replace(/(['"])/g, '\\$1'); + }); + Handlebars.registerHelper( 'equals', function (this: any, a: string, b: string, options: Handlebars.HelperOptions): string { From 6e75fb01599074906d78ff06d9ac3966b527d3bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jurgen=20Belie=CC=88n?= Date: Thu, 9 Dec 2021 18:28:07 +0100 Subject: [PATCH 2/6] test: update snapshots --- test/__snapshots__/index.spec.js.snap | 90 +++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/test/__snapshots__/index.spec.js.snap b/test/__snapshots__/index.spec.js.snap index 3f0f1f84..82a997db 100644 --- a/test/__snapshots__/index.spec.js.snap +++ b/test/__snapshots__/index.spec.js.snap @@ -1367,6 +1367,7 @@ exports[`v2 should generate: ./test/generated/v2/schemas/$Date.ts 1`] = ` /* eslint-disable */ export const $Date = { type: 'string', + description: 'This is a type-only model that defines Date as a string', } as const;" `; @@ -1449,6 +1450,7 @@ exports[`v2 should generate: ./test/generated/v2/schemas/$EnumFromDescription.ts /* eslint-disable */ export const $EnumFromDescription = { type: 'number', + description: 'Success=1,Warning=2,Error=3', } as const;" `; @@ -1485,6 +1487,7 @@ exports[`v2 should generate: ./test/generated/v2/schemas/$ModelThatExtends.ts 1` /* eslint-disable */ export const $ModelThatExtends = { type: 'all-of', + description: 'This is a model that extends another model', contains: [{ type: 'ModelWithString', }, { @@ -1506,6 +1509,7 @@ exports[`v2 should generate: ./test/generated/v2/schemas/$ModelThatExtendsExtend /* eslint-disable */ export const $ModelThatExtendsExtends = { type: 'all-of', + description: 'This is a model that extends another model', contains: [{ type: 'ModelWithString', }, { @@ -1528,6 +1532,7 @@ exports[`v2 should generate: ./test/generated/v2/schemas/$ModelWithArray.ts 1`] /* tslint:disable */ /* eslint-disable */ export const $ModelWithArray = { + description: 'This is a model with one property containing an array', properties: { prop: { type: 'array', @@ -1556,9 +1561,11 @@ exports[`v2 should generate: ./test/generated/v2/schemas/$ModelWithBoolean.ts 1` /* tslint:disable */ /* eslint-disable */ export const $ModelWithBoolean = { + description: 'This is a model with one boolean property', properties: { prop: { type: 'boolean', + description: 'This is a simple boolean property', }, }, } as const;" @@ -1569,6 +1576,7 @@ exports[`v2 should generate: ./test/generated/v2/schemas/$ModelWithCircularRefer /* tslint:disable */ /* eslint-disable */ export const $ModelWithCircularReference = { + description: 'This is a model with one property containing a circular reference', properties: { prop: { type: 'ModelWithCircularReference', @@ -1582,6 +1590,7 @@ exports[`v2 should generate: ./test/generated/v2/schemas/$ModelWithDictionary.ts /* tslint:disable */ /* eslint-disable */ export const $ModelWithDictionary = { + description: 'This is a model with one property containing a dictionary', properties: { prop: { type: 'dictionary', @@ -1598,6 +1607,7 @@ exports[`v2 should generate: ./test/generated/v2/schemas/$ModelWithDuplicateImpo /* tslint:disable */ /* eslint-disable */ export const $ModelWithDuplicateImports = { + description: 'This is a model with duplicated imports', properties: { propA: { type: 'ModelWithString', @@ -1617,6 +1627,7 @@ exports[`v2 should generate: ./test/generated/v2/schemas/$ModelWithDuplicateProp /* tslint:disable */ /* eslint-disable */ export const $ModelWithDuplicateProperties = { + description: 'This is a model with duplicated properties', properties: { prop: { type: 'ModelWithString', @@ -1630,6 +1641,7 @@ exports[`v2 should generate: ./test/generated/v2/schemas/$ModelWithEnum.ts 1`] = /* tslint:disable */ /* eslint-disable */ export const $ModelWithEnum = { + description: 'This is a model with one enum', properties: { test: { type: 'Enum', @@ -1639,6 +1651,7 @@ export const $ModelWithEnum = { }, bool: { type: 'boolean', + description: 'Simple boolean enum', }, }, } as const;" @@ -1649,6 +1662,7 @@ exports[`v2 should generate: ./test/generated/v2/schemas/$ModelWithEnumFromDescr /* tslint:disable */ /* eslint-disable */ export const $ModelWithEnumFromDescription = { + description: 'This is a model with one enum', properties: { test: { type: 'Enum', @@ -1662,9 +1676,11 @@ exports[`v2 should generate: ./test/generated/v2/schemas/$ModelWithInteger.ts 1` /* tslint:disable */ /* eslint-disable */ export const $ModelWithInteger = { + description: 'This is a model with one number property', properties: { prop: { type: 'number', + description: 'This is a simple number property', }, }, } as const;" @@ -1675,6 +1691,7 @@ exports[`v2 should generate: ./test/generated/v2/schemas/$ModelWithNestedEnums.t /* tslint:disable */ /* eslint-disable */ export const $ModelWithNestedEnums = { + description: 'This is a model with nested enums', properties: { dictionaryWithEnum: { type: 'dictionary', @@ -1709,6 +1726,7 @@ exports[`v2 should generate: ./test/generated/v2/schemas/$ModelWithNestedPropert /* tslint:disable */ /* eslint-disable */ export const $ModelWithNestedProperties = { + description: 'This is a model with one nested property', properties: { first: { properties: { @@ -1736,13 +1754,16 @@ exports[`v2 should generate: ./test/generated/v2/schemas/$ModelWithNullableStrin /* tslint:disable */ /* eslint-disable */ export const $ModelWithNullableString = { + description: 'This is a model with one string property', properties: { nullableProp: { type: 'string', + description: 'This is a simple string property', isNullable: true, }, nullableRequiredProp: { type: 'string', + description: 'This is a simple string property', isRequired: true, isNullable: true, }, @@ -1755,6 +1776,7 @@ exports[`v2 should generate: ./test/generated/v2/schemas/$ModelWithOrderedProper /* tslint:disable */ /* eslint-disable */ export const $ModelWithOrderedProperties = { + description: 'This is a model with ordered properties', properties: { zebra: { type: 'string', @@ -1774,6 +1796,7 @@ exports[`v2 should generate: ./test/generated/v2/schemas/$ModelWithPattern.ts 1` /* tslint:disable */ /* eslint-disable */ export const $ModelWithPattern = { + description: 'This is a model that contains a some patterns', properties: { key: { type: 'string', @@ -1812,6 +1835,7 @@ exports[`v2 should generate: ./test/generated/v2/schemas/$ModelWithProperties.ts /* tslint:disable */ /* eslint-disable */ export const $ModelWithProperties = { + description: 'This is a model with one nested property', properties: { required: { type: 'string', @@ -1860,6 +1884,7 @@ exports[`v2 should generate: ./test/generated/v2/schemas/$ModelWithReference.ts /* tslint:disable */ /* eslint-disable */ export const $ModelWithReference = { + description: 'This is a model with one property containing a reference', properties: { prop: { type: 'ModelWithProperties', @@ -1873,9 +1898,11 @@ exports[`v2 should generate: ./test/generated/v2/schemas/$ModelWithString.ts 1`] /* tslint:disable */ /* eslint-disable */ export const $ModelWithString = { + description: 'This is a model with one string property', properties: { prop: { type: 'string', + description: 'This is a simple string property', }, }, } as const;" @@ -1887,6 +1914,10 @@ exports[`v2 should generate: ./test/generated/v2/schemas/$MultilineComment.ts 1` /* eslint-disable */ export const $MultilineComment = { type: 'number', + description: 'Testing multiline comments. + * This must go to the next line. + * + * This will contain a break.', } as const;" `; @@ -1896,6 +1927,7 @@ exports[`v2 should generate: ./test/generated/v2/schemas/$SimpleBoolean.ts 1`] = /* eslint-disable */ export const $SimpleBoolean = { type: 'boolean', + description: 'This is a simple boolean', } as const;" `; @@ -1905,6 +1937,7 @@ exports[`v2 should generate: ./test/generated/v2/schemas/$SimpleFile.ts 1`] = ` /* eslint-disable */ export const $SimpleFile = { type: 'binary', + description: 'This is a simple file', } as const;" `; @@ -1914,6 +1947,7 @@ exports[`v2 should generate: ./test/generated/v2/schemas/$SimpleInteger.ts 1`] = /* eslint-disable */ export const $SimpleInteger = { type: 'number', + description: 'This is a simple number', } as const;" `; @@ -1923,6 +1957,7 @@ exports[`v2 should generate: ./test/generated/v2/schemas/$SimpleReference.ts 1`] /* eslint-disable */ export const $SimpleReference = { type: 'ModelWithString', + description: 'This is a simple reference', } as const;" `; @@ -1932,6 +1967,7 @@ exports[`v2 should generate: ./test/generated/v2/schemas/$SimpleString.ts 1`] = /* eslint-disable */ export const $SimpleString = { type: 'string', + description: 'This is a simple string', } as const;" `; @@ -1941,6 +1977,7 @@ exports[`v2 should generate: ./test/generated/v2/schemas/$SimpleStringWithPatter /* eslint-disable */ export const $SimpleStringWithPattern = { type: 'string', + description: 'This is a simple string', maxLength: 64, pattern: '^[a-zA-Z0-9_]*$', } as const;" @@ -4209,6 +4246,7 @@ exports[`v3 should generate: ./test/generated/v3/schemas/$CompositionBaseModel.t /* tslint:disable */ /* eslint-disable */ export const $CompositionBaseModel = { + description: 'This is a base model with two simple optional properties', properties: { firstName: { type: 'string', @@ -4226,6 +4264,7 @@ exports[`v3 should generate: ./test/generated/v3/schemas/$CompositionExtendedMod /* eslint-disable */ export const $CompositionExtendedModel = { type: 'all-of', + description: 'This is a model that extends the base model', contains: [{ type: 'CompositionBaseModel', }, { @@ -4252,6 +4291,7 @@ exports[`v3 should generate: ./test/generated/v3/schemas/$CompositionWithAllOfAn /* tslint:disable */ /* eslint-disable */ export const $CompositionWithAllOfAndNullable = { + description: 'This is a model with one property with a \\\\'all of\\\\' relationship', properties: { propA: { type: 'all-of', @@ -4279,6 +4319,7 @@ exports[`v3 should generate: ./test/generated/v3/schemas/$CompositionWithAnyOf.t /* tslint:disable */ /* eslint-disable */ export const $CompositionWithAnyOf = { + description: 'This is a model with one property with a \\\\'any of\\\\' relationship', properties: { propA: { type: 'any-of', @@ -4301,6 +4342,7 @@ exports[`v3 should generate: ./test/generated/v3/schemas/$CompositionWithAnyOfAn /* tslint:disable */ /* eslint-disable */ export const $CompositionWithAnyOfAndNullable = { + description: 'This is a model with one property with a \\\\'any of\\\\' relationship', properties: { propA: { type: 'any-of', @@ -4328,10 +4370,12 @@ exports[`v3 should generate: ./test/generated/v3/schemas/$CompositionWithAnyOfAn /* tslint:disable */ /* eslint-disable */ export const $CompositionWithAnyOfAnonymous = { + description: 'This is a model with one property with a \\\\'any of\\\\' relationship where the options are not $ref', properties: { propA: { type: 'any-of', contains: [{ + description: 'Anonymous object type', properties: { propA: { type: 'string', @@ -4339,8 +4383,10 @@ export const $CompositionWithAnyOfAnonymous = { }, }, { type: 'string', + description: 'Anonymous string type', }, { type: 'number', + description: 'Anonymous integer type', }], }, }, @@ -4352,6 +4398,7 @@ exports[`v3 should generate: ./test/generated/v3/schemas/$CompositionWithOneOf.t /* tslint:disable */ /* eslint-disable */ export const $CompositionWithOneOf = { + description: 'This is a model with one property with a \\\\'one of\\\\' relationship', properties: { propA: { type: 'one-of', @@ -4374,6 +4421,7 @@ exports[`v3 should generate: ./test/generated/v3/schemas/$CompositionWithOneOfAn /* tslint:disable */ /* eslint-disable */ export const $CompositionWithOneOfAndNullable = { + description: 'This is a model with one property with a \\\\'one of\\\\' relationship', properties: { propA: { type: 'one-of', @@ -4401,10 +4449,12 @@ exports[`v3 should generate: ./test/generated/v3/schemas/$CompositionWithOneOfAn /* tslint:disable */ /* eslint-disable */ export const $CompositionWithOneOfAnonymous = { + description: 'This is a model with one property with a \\\\'one of\\\\' relationship where the options are not $ref', properties: { propA: { type: 'one-of', contains: [{ + description: 'Anonymous object type', properties: { propA: { type: 'string', @@ -4412,8 +4462,10 @@ export const $CompositionWithOneOfAnonymous = { }, }, { type: 'string', + description: 'Anonymous string type', }, { type: 'number', + description: 'Anonymous integer type', }], }, }, @@ -4499,6 +4551,7 @@ exports[`v3 should generate: ./test/generated/v3/schemas/$EnumFromDescription.ts /* eslint-disable */ export const $EnumFromDescription = { type: 'number', + description: 'Success=1,Warning=2,Error=3', } as const;" `; @@ -4535,6 +4588,7 @@ exports[`v3 should generate: ./test/generated/v3/schemas/$ModelThatExtends.ts 1` /* eslint-disable */ export const $ModelThatExtends = { type: 'all-of', + description: 'This is a model that extends another model', contains: [{ type: 'ModelWithString', }, { @@ -4556,6 +4610,7 @@ exports[`v3 should generate: ./test/generated/v3/schemas/$ModelThatExtendsExtend /* eslint-disable */ export const $ModelThatExtendsExtends = { type: 'all-of', + description: 'This is a model that extends another model', contains: [{ type: 'ModelWithString', }, { @@ -4578,6 +4633,7 @@ exports[`v3 should generate: ./test/generated/v3/schemas/$ModelWithArray.ts 1`] /* tslint:disable */ /* eslint-disable */ export const $ModelWithArray = { + description: 'This is a model with one property containing an array', properties: { prop: { type: 'array', @@ -4606,9 +4662,11 @@ exports[`v3 should generate: ./test/generated/v3/schemas/$ModelWithBoolean.ts 1` /* tslint:disable */ /* eslint-disable */ export const $ModelWithBoolean = { + description: 'This is a model with one boolean property', properties: { prop: { type: 'boolean', + description: 'This is a simple boolean property', }, }, } as const;" @@ -4619,6 +4677,7 @@ exports[`v3 should generate: ./test/generated/v3/schemas/$ModelWithCircularRefer /* tslint:disable */ /* eslint-disable */ export const $ModelWithCircularReference = { + description: 'This is a model with one property containing a circular reference', properties: { prop: { type: 'ModelWithCircularReference', @@ -4632,6 +4691,7 @@ exports[`v3 should generate: ./test/generated/v3/schemas/$ModelWithDictionary.ts /* tslint:disable */ /* eslint-disable */ export const $ModelWithDictionary = { + description: 'This is a model with one property containing a dictionary', properties: { prop: { type: 'dictionary', @@ -4648,6 +4708,7 @@ exports[`v3 should generate: ./test/generated/v3/schemas/$ModelWithDuplicateImpo /* tslint:disable */ /* eslint-disable */ export const $ModelWithDuplicateImports = { + description: 'This is a model with duplicated imports', properties: { propA: { type: 'ModelWithString', @@ -4667,6 +4728,7 @@ exports[`v3 should generate: ./test/generated/v3/schemas/$ModelWithDuplicateProp /* tslint:disable */ /* eslint-disable */ export const $ModelWithDuplicateProperties = { + description: 'This is a model with duplicated properties', properties: { prop: { type: 'ModelWithString', @@ -4680,6 +4742,7 @@ exports[`v3 should generate: ./test/generated/v3/schemas/$ModelWithEnum.ts 1`] = /* tslint:disable */ /* eslint-disable */ export const $ModelWithEnum = { + description: 'This is a model with one enum', properties: { test: { type: 'Enum', @@ -4689,6 +4752,7 @@ export const $ModelWithEnum = { }, bool: { type: 'boolean', + description: 'Simple boolean enum', }, }, } as const;" @@ -4699,6 +4763,7 @@ exports[`v3 should generate: ./test/generated/v3/schemas/$ModelWithEnumFromDescr /* tslint:disable */ /* eslint-disable */ export const $ModelWithEnumFromDescription = { + description: 'This is a model with one enum', properties: { test: { type: 'Enum', @@ -4712,9 +4777,11 @@ exports[`v3 should generate: ./test/generated/v3/schemas/$ModelWithInteger.ts 1` /* tslint:disable */ /* eslint-disable */ export const $ModelWithInteger = { + description: 'This is a model with one number property', properties: { prop: { type: 'number', + description: 'This is a simple number property', }, }, } as const;" @@ -4725,6 +4792,7 @@ exports[`v3 should generate: ./test/generated/v3/schemas/$ModelWithNestedEnums.t /* tslint:disable */ /* eslint-disable */ export const $ModelWithNestedEnums = { + description: 'This is a model with nested enums', properties: { dictionaryWithEnum: { type: 'dictionary', @@ -4759,6 +4827,7 @@ exports[`v3 should generate: ./test/generated/v3/schemas/$ModelWithNestedPropert /* tslint:disable */ /* eslint-disable */ export const $ModelWithNestedProperties = { + description: 'This is a model with one nested property', properties: { first: { properties: { @@ -4789,22 +4858,27 @@ exports[`v3 should generate: ./test/generated/v3/schemas/$ModelWithNullableStrin /* tslint:disable */ /* eslint-disable */ export const $ModelWithNullableString = { + description: 'This is a model with one string property', properties: { nullableProp1: { type: 'string', + description: 'This is a simple string property', isNullable: true, }, nullableRequiredProp1: { type: 'string', + description: 'This is a simple string property', isRequired: true, isNullable: true, }, nullableProp2: { type: 'string', + description: 'This is a simple string property', isNullable: true, }, nullableRequiredProp2: { type: 'string', + description: 'This is a simple string property', isRequired: true, isNullable: true, }, @@ -4817,6 +4891,7 @@ exports[`v3 should generate: ./test/generated/v3/schemas/$ModelWithOrderedProper /* tslint:disable */ /* eslint-disable */ export const $ModelWithOrderedProperties = { + description: 'This is a model with ordered properties', properties: { zebra: { type: 'string', @@ -4836,6 +4911,7 @@ exports[`v3 should generate: ./test/generated/v3/schemas/$ModelWithPattern.ts 1` /* tslint:disable */ /* eslint-disable */ export const $ModelWithPattern = { + description: 'This is a model that contains a some patterns', properties: { key: { type: 'string', @@ -4874,6 +4950,7 @@ exports[`v3 should generate: ./test/generated/v3/schemas/$ModelWithProperties.ts /* tslint:disable */ /* eslint-disable */ export const $ModelWithProperties = { + description: 'This is a model with one nested property', properties: { required: { type: 'string', @@ -4927,6 +5004,7 @@ exports[`v3 should generate: ./test/generated/v3/schemas/$ModelWithReference.ts /* tslint:disable */ /* eslint-disable */ export const $ModelWithReference = { + description: 'This is a model with one property containing a reference', properties: { prop: { type: 'ModelWithProperties', @@ -4940,9 +5018,11 @@ exports[`v3 should generate: ./test/generated/v3/schemas/$ModelWithString.ts 1`] /* tslint:disable */ /* eslint-disable */ export const $ModelWithString = { + description: 'This is a model with one string property', properties: { prop: { type: 'string', + description: 'This is a simple string property', }, }, } as const;" @@ -4954,6 +5034,10 @@ exports[`v3 should generate: ./test/generated/v3/schemas/$MultilineComment.ts 1` /* eslint-disable */ export const $MultilineComment = { type: 'number', + description: 'Testing multiline comments. + * This must go to the next line. + * + * This will contain a break.', } as const;" `; @@ -4963,6 +5047,7 @@ exports[`v3 should generate: ./test/generated/v3/schemas/$SimpleBoolean.ts 1`] = /* eslint-disable */ export const $SimpleBoolean = { type: 'boolean', + description: 'This is a simple boolean', } as const;" `; @@ -4972,6 +5057,7 @@ exports[`v3 should generate: ./test/generated/v3/schemas/$SimpleFile.ts 1`] = ` /* eslint-disable */ export const $SimpleFile = { type: 'binary', + description: 'This is a simple file', } as const;" `; @@ -4981,6 +5067,7 @@ exports[`v3 should generate: ./test/generated/v3/schemas/$SimpleInteger.ts 1`] = /* eslint-disable */ export const $SimpleInteger = { type: 'number', + description: 'This is a simple number', } as const;" `; @@ -4990,6 +5077,7 @@ exports[`v3 should generate: ./test/generated/v3/schemas/$SimpleReference.ts 1`] /* eslint-disable */ export const $SimpleReference = { type: 'ModelWithString', + description: 'This is a simple reference', } as const;" `; @@ -4999,6 +5087,7 @@ exports[`v3 should generate: ./test/generated/v3/schemas/$SimpleString.ts 1`] = /* eslint-disable */ export const $SimpleString = { type: 'string', + description: 'This is a simple string', } as const;" `; @@ -5008,6 +5097,7 @@ exports[`v3 should generate: ./test/generated/v3/schemas/$SimpleStringWithPatter /* eslint-disable */ export const $SimpleStringWithPattern = { type: 'string', + description: 'This is a simple string', isNullable: true, maxLength: 64, pattern: '^[a-zA-Z0-9_]*$', From ac0d8f9bb02e3dc59f457cfc364f89c6b771616f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jurgen=20Belie=CC=88n?= Date: Fri, 10 Dec 2021 09:28:13 +0100 Subject: [PATCH 3/6] fix(templates): only escape single quotes --- rollup.config.js | 2 +- src/templates/partials/schemaComposition.hbs | 2 +- src/templates/partials/schemaGeneric.hbs | 2 +- src/templates/partials/schemaInterface.hbs | 2 +- src/utils/registerHandlebarHelpers.ts | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/rollup.config.js b/rollup.config.js index 60545d7c..4e97a3de 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -32,7 +32,7 @@ const handlebarsPlugin = () => ({ preventIndent: true, knownHelpersOnly: true, knownHelpers: { - escapeQuotes: true, + escapeSinglequotes: true, equals: true, notEquals: true, containsSpaces: true, diff --git a/src/templates/partials/schemaComposition.hbs b/src/templates/partials/schemaComposition.hbs index 005ea046..1cceecf0 100644 --- a/src/templates/partials/schemaComposition.hbs +++ b/src/templates/partials/schemaComposition.hbs @@ -1,7 +1,7 @@ { type: '{{export}}', {{#if description}} - description: '{{{escapeQuotes description}}}', + description: '{{{escapeSinglequotes description}}}', {{/if}} contains: [{{#each properties}}{{>schema}}{{#unless @last}}, {{/unless}}{{/each}}], {{#if isReadOnly}} diff --git a/src/templates/partials/schemaGeneric.hbs b/src/templates/partials/schemaGeneric.hbs index d41956a8..ec964dd4 100644 --- a/src/templates/partials/schemaGeneric.hbs +++ b/src/templates/partials/schemaGeneric.hbs @@ -3,7 +3,7 @@ type: '{{{base}}}', {{/if}} {{#if description}} - description: '{{{escapeQuotes description}}}', + description: '{{{escapeSinglequotes description}}}', {{/if}} {{#if isReadOnly}} isReadOnly: {{{isReadOnly}}}, diff --git a/src/templates/partials/schemaInterface.hbs b/src/templates/partials/schemaInterface.hbs index 0488adae..65fd3316 100644 --- a/src/templates/partials/schemaInterface.hbs +++ b/src/templates/partials/schemaInterface.hbs @@ -1,6 +1,6 @@ { {{#if description}} - description: '{{{escapeQuotes description}}}', + description: '{{{escapeSinglequotes description}}}', {{/if}} properties: { {{#if properties}} diff --git a/src/utils/registerHandlebarHelpers.ts b/src/utils/registerHandlebarHelpers.ts index 99c5dca2..bea65337 100644 --- a/src/utils/registerHandlebarHelpers.ts +++ b/src/utils/registerHandlebarHelpers.ts @@ -11,7 +11,7 @@ export function registerHandlebarHelpers(root: { useUnionTypes: boolean; }): void { Handlebars.registerHelper('escapeQuotes', function (value: string): string { - return value.replace(/(['"])/g, '\\$1'); + return value.replace(/(')/g, '\\$1'); }); Handlebars.registerHelper( From a543b9d490014e2ea36cc34df8913da2c87332c3 Mon Sep 17 00:00:00 2001 From: Sjoerd Mulder Date: Tue, 21 Dec 2021 14:05:19 +0100 Subject: [PATCH 4/6] Adding discriminator support for oneOf --- .../v2/parser/getOperationParameterName.ts | 3 +- src/openApi/v3/parser/getModel.ts | 2 +- src/openApi/v3/parser/getModelProperties.ts | 87 ++++++++-------- .../v3/parser/getOperationParameterName.ts | 3 +- src/templates/partials/schemaGeneric.hbs | 2 +- src/utils/discriminator.ts | 46 +++++++++ test/__snapshots__/index.spec.js.snap | 99 +++++++++++++++++++ test/spec/v3.json | 45 +++++++++ 8 files changed, 241 insertions(+), 46 deletions(-) create mode 100644 src/utils/discriminator.ts diff --git a/src/openApi/v2/parser/getOperationParameterName.ts b/src/openApi/v2/parser/getOperationParameterName.ts index 0954d736..e21e83c8 100644 --- a/src/openApi/v2/parser/getOperationParameterName.ts +++ b/src/openApi/v2/parser/getOperationParameterName.ts @@ -1,7 +1,6 @@ import camelCase from 'camelcase'; -const reservedWords = - /^(arguments|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|eval|export|extends|false|finally|for|function|if|implements|import|in|instanceof|interface|let|new|null|package|private|protected|public|return|static|super|switch|this|throw|true|try|typeof|var|void|while|with|yield)$/g; +const reservedWords = /^(arguments|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|eval|export|extends|false|finally|for|function|if|implements|import|in|instanceof|interface|let|new|null|package|private|protected|public|return|static|super|switch|this|throw|true|try|typeof|var|void|while|with|yield)$/g; /** * Replaces any invalid characters from a parameter name. diff --git a/src/openApi/v3/parser/getModel.ts b/src/openApi/v3/parser/getModel.ts index 30efcfac..99507ad8 100644 --- a/src/openApi/v3/parser/getModel.ts +++ b/src/openApi/v3/parser/getModel.ts @@ -165,7 +165,7 @@ export function getModel( model.default = getModelDefault(definition, model); if (definition.properties) { - const modelProperties = getModelProperties(openApi, definition, getModel); + const modelProperties = getModelProperties(openApi, definition, getModel, model); modelProperties.forEach(modelProperty => { model.imports.push(...modelProperty.imports); model.enums.push(...modelProperty.enums); diff --git a/src/openApi/v3/parser/getModelProperties.ts b/src/openApi/v3/parser/getModelProperties.ts index 5d59b3e4..653378ca 100644 --- a/src/openApi/v3/parser/getModelProperties.ts +++ b/src/openApi/v3/parser/getModelProperties.ts @@ -1,4 +1,5 @@ import type { Model } from '../../../client/interfaces/Model'; +import { findOneOfParentDiscriminator, mapPropertyValue } from '../../../utils/discriminator'; import { getPattern } from '../../../utils/getPattern'; import type { OpenApi } from '../interfaces/OpenApi'; import type { OpenApiSchema } from '../interfaces/OpenApiSchema'; @@ -10,77 +11,83 @@ import { getType } from './getType'; // Fix for circular dependency export type GetModelFn = typeof getModel; -export function getModelProperties(openApi: OpenApi, definition: OpenApiSchema, getModel: GetModelFn): Model[] { +export function getModelProperties( + openApi: OpenApi, + definition: OpenApiSchema, + getModel: GetModelFn, + parent?: Model +): Model[] { const models: Model[] = []; + const discriminator = findOneOfParentDiscriminator(openApi, parent); for (const propertyName in definition.properties) { if (definition.properties.hasOwnProperty(propertyName)) { const property = definition.properties[propertyName]; const propertyRequired = !!definition.required?.includes(propertyName); - if (property.$ref) { + const propertyValues = { + name: escapeName(propertyName), + description: getComment(property.description), + isDefinition: false, + isReadOnly: property.readOnly === true, + isRequired: propertyRequired, + format: property.format, + maximum: property.maximum, + exclusiveMaximum: property.exclusiveMaximum, + minimum: property.minimum, + exclusiveMinimum: property.exclusiveMinimum, + multipleOf: property.multipleOf, + maxLength: property.maxLength, + minLength: property.minLength, + maxItems: property.maxItems, + minItems: property.minItems, + uniqueItems: property.uniqueItems, + maxProperties: property.maxProperties, + minProperties: property.minProperties, + pattern: getPattern(property.pattern), + }; + if (parent && discriminator?.propertyName == propertyName) { + models.push({ + export: 'reference', + type: 'string', + base: `'${mapPropertyValue(discriminator, parent)}'`, + template: null, + isNullable: property.nullable === true, + link: null, + imports: [], + enum: [], + enums: [], + properties: [], + ...propertyValues, + }); + } else if (property.$ref) { const model = getType(property.$ref); models.push({ - name: escapeName(propertyName), export: 'reference', type: model.type, base: model.base, template: model.template, link: null, - description: getComment(property.description), - isDefinition: false, - isReadOnly: property.readOnly === true, - isRequired: propertyRequired, isNullable: model.isNullable || property.nullable === true, - format: property.format, - maximum: property.maximum, - exclusiveMaximum: property.exclusiveMaximum, - minimum: property.minimum, - exclusiveMinimum: property.exclusiveMinimum, - multipleOf: property.multipleOf, - maxLength: property.maxLength, - minLength: property.minLength, - maxItems: property.maxItems, - minItems: property.minItems, - uniqueItems: property.uniqueItems, - maxProperties: property.maxProperties, - minProperties: property.minProperties, - pattern: getPattern(property.pattern), imports: model.imports, enum: [], enums: [], properties: [], + ...propertyValues, }); } else { const model = getModel(openApi, property); models.push({ - name: escapeName(propertyName), export: model.export, type: model.type, base: model.base, template: model.template, link: model.link, - description: getComment(property.description), - isDefinition: false, - isReadOnly: property.readOnly === true, - isRequired: propertyRequired, isNullable: model.isNullable || property.nullable === true, - format: property.format, - maximum: property.maximum, - exclusiveMaximum: property.exclusiveMaximum, - minimum: property.minimum, - exclusiveMinimum: property.exclusiveMinimum, - multipleOf: property.multipleOf, - maxLength: property.maxLength, - minLength: property.minLength, - maxItems: property.maxItems, - minItems: property.minItems, - uniqueItems: property.uniqueItems, - maxProperties: property.maxProperties, - minProperties: property.minProperties, - pattern: getPattern(property.pattern), + imports: model.imports, enum: model.enum, enums: model.enums, properties: model.properties, + ...propertyValues, }); } } diff --git a/src/openApi/v3/parser/getOperationParameterName.ts b/src/openApi/v3/parser/getOperationParameterName.ts index 0954d736..e21e83c8 100644 --- a/src/openApi/v3/parser/getOperationParameterName.ts +++ b/src/openApi/v3/parser/getOperationParameterName.ts @@ -1,7 +1,6 @@ import camelCase from 'camelcase'; -const reservedWords = - /^(arguments|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|eval|export|extends|false|finally|for|function|if|implements|import|in|instanceof|interface|let|new|null|package|private|protected|public|return|static|super|switch|this|throw|true|try|typeof|var|void|while|with|yield)$/g; +const reservedWords = /^(arguments|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|eval|export|extends|false|finally|for|function|if|implements|import|in|instanceof|interface|let|new|null|package|private|protected|public|return|static|super|switch|this|throw|true|try|typeof|var|void|while|with|yield)$/g; /** * Replaces any invalid characters from a parameter name. diff --git a/src/templates/partials/schemaGeneric.hbs b/src/templates/partials/schemaGeneric.hbs index 7b0d96c9..d8a9e5bc 100644 --- a/src/templates/partials/schemaGeneric.hbs +++ b/src/templates/partials/schemaGeneric.hbs @@ -1,6 +1,6 @@ { {{#if type}} - type: '{{{base}}}', + type: '{{{type}}}', {{/if}} {{#if isReadOnly}} isReadOnly: {{{isReadOnly}}}, diff --git a/src/utils/discriminator.ts b/src/utils/discriminator.ts new file mode 100644 index 00000000..cf78d470 --- /dev/null +++ b/src/utils/discriminator.ts @@ -0,0 +1,46 @@ +import { Model } from '../client/interfaces/Model'; +import { OpenApi } from '../openApi/v3/interfaces/OpenApi'; +import { OpenApiDiscriminator } from '../openApi/v3/interfaces/OpenApiDiscriminator'; +import { stripNamespace } from '../openApi/v3/parser/stripNamespace'; +import { Dictionary } from './types'; + +const inverseDictionary = (mapObj: Dictionary) => { + const m2: Dictionary = {}; + for (const key in mapObj) { + m2[mapObj[key]] = key; + } + return m2; +}; + +export function findOneOfParentDiscriminator(openApi: OpenApi, parent?: Model): OpenApiDiscriminator | undefined { + if (openApi.components) { + for (const definitionName in openApi.components.schemas) { + if (openApi.components.schemas.hasOwnProperty(definitionName)) { + const schema = openApi.components.schemas[definitionName]; + if (parent && schema.oneOf?.length && schema.discriminator) { + const isPartOf = + schema.oneOf + .map(definition => { + return definition.$ref && stripNamespace(definition.$ref) == parent.name; + }) + .filter(Boolean).length > 0; + if (isPartOf) { + return schema.discriminator; + } + } + } + } + } + return undefined; +} + +export function mapPropertyValue(discriminator: OpenApiDiscriminator, parent: Model): string { + if (discriminator.mapping) { + const mapping = inverseDictionary(discriminator.mapping); + const key = Object.keys(mapping).find(item => stripNamespace(item) == parent.name); + if (key && mapping[key]) { + return mapping[key]; + } + } + return parent.name; +} diff --git a/test/__snapshots__/index.spec.js.snap b/test/__snapshots__/index.spec.js.snap index 8d3251f8..13e5ac1c 100644 --- a/test/__snapshots__/index.spec.js.snap +++ b/test/__snapshots__/index.spec.js.snap @@ -3169,6 +3169,7 @@ export type { CompositionWithAnyOfAnonymous } from './models/CompositionWithAnyO export type { CompositionWithOneOf } from './models/CompositionWithOneOf'; export type { CompositionWithOneOfAndNullable } from './models/CompositionWithOneOfAndNullable'; export type { CompositionWithOneOfAnonymous } from './models/CompositionWithOneOfAnonymous'; +export type { CompositionWithOneOfDiscriminator } from './models/CompositionWithOneOfDiscriminator'; export type { DictionaryWithArray } from './models/DictionaryWithArray'; export type { DictionaryWithDictionary } from './models/DictionaryWithDictionary'; export type { DictionaryWithProperties } from './models/DictionaryWithProperties'; @@ -3178,6 +3179,8 @@ export type { EnumFromDescription } from './models/EnumFromDescription'; export { EnumWithExtensions } from './models/EnumWithExtensions'; export { EnumWithNumbers } from './models/EnumWithNumbers'; export { EnumWithStrings } from './models/EnumWithStrings'; +export type { ModelCircle } from './models/ModelCircle'; +export type { ModelSquare } from './models/ModelSquare'; export type { ModelThatExtends } from './models/ModelThatExtends'; export type { ModelThatExtendsExtends } from './models/ModelThatExtendsExtends'; export type { ModelWithArray } from './models/ModelWithArray'; @@ -3220,6 +3223,7 @@ export { $CompositionWithAnyOfAnonymous } from './schemas/$CompositionWithAnyOfA export { $CompositionWithOneOf } from './schemas/$CompositionWithOneOf'; export { $CompositionWithOneOfAndNullable } from './schemas/$CompositionWithOneOfAndNullable'; export { $CompositionWithOneOfAnonymous } from './schemas/$CompositionWithOneOfAnonymous'; +export { $CompositionWithOneOfDiscriminator } from './schemas/$CompositionWithOneOfDiscriminator'; export { $DictionaryWithArray } from './schemas/$DictionaryWithArray'; export { $DictionaryWithDictionary } from './schemas/$DictionaryWithDictionary'; export { $DictionaryWithProperties } from './schemas/$DictionaryWithProperties'; @@ -3229,6 +3233,8 @@ export { $EnumFromDescription } from './schemas/$EnumFromDescription'; export { $EnumWithExtensions } from './schemas/$EnumWithExtensions'; export { $EnumWithNumbers } from './schemas/$EnumWithNumbers'; export { $EnumWithStrings } from './schemas/$EnumWithStrings'; +export { $ModelCircle } from './schemas/$ModelCircle'; +export { $ModelSquare } from './schemas/$ModelSquare'; export { $ModelThatExtends } from './schemas/$ModelThatExtends'; export { $ModelThatExtendsExtends } from './schemas/$ModelThatExtendsExtends'; export { $ModelWithArray } from './schemas/$ModelWithArray'; @@ -3513,6 +3519,21 @@ export type CompositionWithOneOfAnonymous = { " `; +exports[`v3 should generate: ./test/generated/v3/models/CompositionWithOneOfDiscriminator.ts 1`] = ` +"/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +import type { ModelCircle } from './ModelCircle'; +import type { ModelSquare } from './ModelSquare'; + +/** + * This is a model with one property with a 'one of' relationship where the options are not $ref + */ +export type CompositionWithOneOfDiscriminator = (ModelCircle | ModelSquare); +" +`; + exports[`v3 should generate: ./test/generated/v3/models/DictionaryWithArray.ts 1`] = ` "/* istanbul ignore file */ /* tslint:disable */ @@ -3652,6 +3673,36 @@ export enum EnumWithStrings { }" `; +exports[`v3 should generate: ./test/generated/v3/models/ModelCircle.ts 1`] = ` +"/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +/** + * Circle + */ +export type ModelCircle = { + kind: 'circle'; + radius?: number; +} +" +`; + +exports[`v3 should generate: ./test/generated/v3/models/ModelSquare.ts 1`] = ` +"/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ + +/** + * Square + */ +export type ModelSquare = { + kind: 'square'; + sideLength?: number; +} +" +`; + exports[`v3 should generate: ./test/generated/v3/models/ModelThatExtends.ts 1`] = ` "/* istanbul ignore file */ /* tslint:disable */ @@ -4422,6 +4473,20 @@ export const $CompositionWithOneOfAnonymous = { } as const;" `; +exports[`v3 should generate: ./test/generated/v3/schemas/$CompositionWithOneOfDiscriminator.ts 1`] = ` +"/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export const $CompositionWithOneOfDiscriminator = { + type: 'one-of', + contains: [{ + type: 'ModelCircle', + }, { + type: 'ModelSquare', + }], +} as const;" +`; + exports[`v3 should generate: ./test/generated/v3/schemas/$DictionaryWithArray.ts 1`] = ` "/* istanbul ignore file */ /* tslint:disable */ @@ -4531,6 +4596,40 @@ export const $EnumWithStrings = { } as const;" `; +exports[`v3 should generate: ./test/generated/v3/schemas/$ModelCircle.ts 1`] = ` +"/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export const $ModelCircle = { + properties: { + kind: { + type: 'string', + isRequired: true, + }, + radius: { + type: 'number', + }, + }, +} as const;" +`; + +exports[`v3 should generate: ./test/generated/v3/schemas/$ModelSquare.ts 1`] = ` +"/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export const $ModelSquare = { + properties: { + kind: { + type: 'string', + isRequired: true, + }, + sideLength: { + type: 'number', + }, + }, +} as const;" +`; + exports[`v3 should generate: ./test/generated/v3/schemas/$ModelThatExtends.ts 1`] = ` "/* istanbul ignore file */ /* tslint:disable */ diff --git a/test/spec/v3.json b/test/spec/v3.json index 892687f8..8e7b9b02 100644 --- a/test/spec/v3.json +++ b/test/spec/v3.json @@ -1863,6 +1863,51 @@ } } }, + "ModelCircle": { + "description": "Circle", + "type": "object", + "required": ["kind"], + "properties": { + "kind": { + "type": "string" + }, + "radius": { + "type": "number" + } + } + }, + "ModelSquare": { + "description": "Square", + "type": "object", + "required": ["kind"], + "properties": { + "kind": { + "type": "string" + }, + "sideLength": { + "type": "number" + } + } + }, + "CompositionWithOneOfDiscriminator": { + "description": "This is a model with one property with a 'one of' relationship where the options are not $ref", + "type": "object", + "oneOf": [ + { + "$ref": "#/components/schemas/ModelCircle" + }, + { + "$ref": "#/components/schemas/ModelSquare" + } + ], + "discriminator": { + "propertyName": "kind", + "mapping": { + "circle": "#/components/schemas/ModelCircle", + "square": "#/components/schemas/ModelSquare" + } + } + }, "CompositionWithAnyOf": { "description": "This is a model with one property with a 'any of' relationship", "type": "object", From d82f3eb706d8d0739c6df2eef6d02a0f5334e018 Mon Sep 17 00:00:00 2001 From: Sjoerd Mulder Date: Tue, 21 Dec 2021 14:08:04 +0100 Subject: [PATCH 5/6] Removed whitespace --- src/openApi/v3/parser/getModelProperties.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/openApi/v3/parser/getModelProperties.ts b/src/openApi/v3/parser/getModelProperties.ts index 653378ca..cad55ae9 100644 --- a/src/openApi/v3/parser/getModelProperties.ts +++ b/src/openApi/v3/parser/getModelProperties.ts @@ -82,7 +82,6 @@ export function getModelProperties( template: model.template, link: model.link, isNullable: model.isNullable || property.nullable === true, - imports: model.imports, enum: model.enum, enums: model.enums, From 9680e9c7444c29ce70fd139b85761490365c0035 Mon Sep 17 00:00:00 2001 From: Sjoerd Mulder Date: Tue, 21 Dec 2021 14:24:00 +0100 Subject: [PATCH 6/6] Allow FormData as body argument --- src/templates/core/fetch/getHeaders.hbs | 2 +- src/templates/core/fetch/getRequestBody.hbs | 2 +- src/templates/core/fetch/request.hbs | 3 +++ src/templates/core/functions/isFormData.hbs | 3 +++ src/templates/core/node/getHeaders.hbs | 2 +- src/templates/core/node/getRequestBody.hbs | 2 +- src/templates/core/xhr/getHeaders.hbs | 2 +- src/templates/core/xhr/getRequestBody.hbs | 2 +- src/utils/registerHandlebarTemplates.ts | 2 ++ test/__snapshots__/index.spec.js.snap | 16 ++++++++++++---- 10 files changed, 26 insertions(+), 10 deletions(-) create mode 100644 src/templates/core/functions/isFormData.hbs diff --git a/src/templates/core/fetch/getHeaders.hbs b/src/templates/core/fetch/getHeaders.hbs index 71efdd96..261cc9b8 100644 --- a/src/templates/core/fetch/getHeaders.hbs +++ b/src/templates/core/fetch/getHeaders.hbs @@ -33,7 +33,7 @@ async function getHeaders(options: ApiRequestOptions): Promise { headers.append('Content-Type', options.body.type || 'application/octet-stream'); } else if (isString(options.body)) { headers.append('Content-Type', 'text/plain'); - } else { + } else if (!isFormData(options.body)) { headers.append('Content-Type', 'application/json'); } } diff --git a/src/templates/core/fetch/getRequestBody.hbs b/src/templates/core/fetch/getRequestBody.hbs index 7ce4045c..5167ec72 100644 --- a/src/templates/core/fetch/getRequestBody.hbs +++ b/src/templates/core/fetch/getRequestBody.hbs @@ -2,7 +2,7 @@ function getRequestBody(options: ApiRequestOptions): BodyInit | undefined { if (options.body) { if (options.mediaType?.includes('/json')) { return JSON.stringify(options.body) - } else if (isString(options.body) || isBlob(options.body)) { + } else if (isString(options.body) || isBlob(options.body) || isFormData(options.body)) { return options.body; } else { return JSON.stringify(options.body); diff --git a/src/templates/core/fetch/request.hbs b/src/templates/core/fetch/request.hbs index b37002be..ecb988de 100644 --- a/src/templates/core/fetch/request.hbs +++ b/src/templates/core/fetch/request.hbs @@ -19,6 +19,9 @@ import { OpenAPI } from './OpenAPI'; {{>functions/isBlob}} +{{>functions/isFormData}} + + {{>functions/base64}} diff --git a/src/templates/core/functions/isFormData.hbs b/src/templates/core/functions/isFormData.hbs new file mode 100644 index 00000000..6e26ecfc --- /dev/null +++ b/src/templates/core/functions/isFormData.hbs @@ -0,0 +1,3 @@ +function isFormData(value: any): value is FormData { + return value instanceof FormData; +} \ No newline at end of file diff --git a/src/templates/core/node/getHeaders.hbs b/src/templates/core/node/getHeaders.hbs index 53ecfc74..c8dcc9ff 100644 --- a/src/templates/core/node/getHeaders.hbs +++ b/src/templates/core/node/getHeaders.hbs @@ -33,7 +33,7 @@ async function getHeaders(options: ApiRequestOptions): Promise { headers.append('Content-Type', 'application/octet-stream'); } else if (isString(options.body)) { headers.append('Content-Type', 'text/plain'); - } else { + } else if (!isFormData(options.body)) { headers.append('Content-Type', 'application/json'); } } diff --git a/src/templates/core/node/getRequestBody.hbs b/src/templates/core/node/getRequestBody.hbs index 79ba7a8e..3cf835ba 100644 --- a/src/templates/core/node/getRequestBody.hbs +++ b/src/templates/core/node/getRequestBody.hbs @@ -2,7 +2,7 @@ function getRequestBody(options: ApiRequestOptions): BodyInit | undefined { if (options.body) { if (options.mediaType?.includes('/json')) { return JSON.stringify(options.body) - } else if (isString(options.body) || isBlob(options.body)) { + } else if (isString(options.body) || isBlob(options.body) || isFormData(options.body)) { return options.body as any; } else { return JSON.stringify(options.body); diff --git a/src/templates/core/xhr/getHeaders.hbs b/src/templates/core/xhr/getHeaders.hbs index bc85b084..bdb7db74 100644 --- a/src/templates/core/xhr/getHeaders.hbs +++ b/src/templates/core/xhr/getHeaders.hbs @@ -33,7 +33,7 @@ async function getHeaders(options: ApiRequestOptions): Promise { headers.append('Content-Type', options.body.type || 'application/octet-stream'); } else if (isString(options.body)) { headers.append('Content-Type', 'text/plain'); - } else { + } else if (!isFormData(options.body)) { headers.append('Content-Type', 'application/json'); } } diff --git a/src/templates/core/xhr/getRequestBody.hbs b/src/templates/core/xhr/getRequestBody.hbs index bd9d689e..c94aca18 100644 --- a/src/templates/core/xhr/getRequestBody.hbs +++ b/src/templates/core/xhr/getRequestBody.hbs @@ -2,7 +2,7 @@ function getRequestBody(options: ApiRequestOptions): any { if (options.body) { if (options.mediaType?.includes('/json')) { return JSON.stringify(options.body) - } else if (isString(options.body) || isBlob(options.body)) { + } else if (isString(options.body) || isBlob(options.body) || isFormData(options.body)) { return options.body; } else { return JSON.stringify(options.body); diff --git a/src/utils/registerHandlebarTemplates.ts b/src/utils/registerHandlebarTemplates.ts index fe5a6b1a..94601601 100644 --- a/src/utils/registerHandlebarTemplates.ts +++ b/src/utils/registerHandlebarTemplates.ts @@ -24,6 +24,7 @@ import functionGetQueryString from '../templates/core/functions/getQueryString.h import functionGetUrl from '../templates/core/functions/getUrl.hbs'; import functionIsBlob from '../templates/core/functions/isBlob.hbs'; import functionIsDefined from '../templates/core/functions/isDefined.hbs'; +import functionIsFormData from '../templates/core/functions/isFormData.hbs'; import functionIsString from '../templates/core/functions/isString.hbs'; import functionIsStringWithValue from '../templates/core/functions/isStringWithValue.hbs'; import functionIsSuccess from '../templates/core/functions/isSuccess.hbs'; @@ -157,6 +158,7 @@ export function registerHandlebarTemplates(root: { Handlebars.registerPartial('functions/getUrl', Handlebars.template(functionGetUrl)); Handlebars.registerPartial('functions/isBlob', Handlebars.template(functionIsBlob)); Handlebars.registerPartial('functions/isDefined', Handlebars.template(functionIsDefined)); + Handlebars.registerPartial('functions/isFormData', Handlebars.template(functionIsFormData)); Handlebars.registerPartial('functions/isString', Handlebars.template(functionIsString)); Handlebars.registerPartial('functions/isStringWithValue', Handlebars.template(functionIsStringWithValue)); Handlebars.registerPartial('functions/isSuccess', Handlebars.template(functionIsSuccess)); diff --git a/test/__snapshots__/index.spec.js.snap b/test/__snapshots__/index.spec.js.snap index 8d3251f8..092a3147 100644 --- a/test/__snapshots__/index.spec.js.snap +++ b/test/__snapshots__/index.spec.js.snap @@ -233,6 +233,10 @@ function isBlob(value: any): value is Blob { return value instanceof Blob; } +function isFormData(value: any): value is FormData { + return value instanceof FormData; +} + function base64(str: string): string { try { return btoa(str); @@ -347,7 +351,7 @@ async function getHeaders(options: ApiRequestOptions): Promise { headers.append('Content-Type', options.body.type || 'application/octet-stream'); } else if (isString(options.body)) { headers.append('Content-Type', 'text/plain'); - } else { + } else if (!isFormData(options.body)) { headers.append('Content-Type', 'application/json'); } } @@ -359,7 +363,7 @@ function getRequestBody(options: ApiRequestOptions): BodyInit | undefined { if (options.body) { if (options.mediaType?.includes('/json')) { return JSON.stringify(options.body) - } else if (isString(options.body) || isBlob(options.body)) { + } else if (isString(options.body) || isBlob(options.body) || isFormData(options.body)) { return options.body; } else { return JSON.stringify(options.body); @@ -2896,6 +2900,10 @@ function isBlob(value: any): value is Blob { return value instanceof Blob; } +function isFormData(value: any): value is FormData { + return value instanceof FormData; +} + function base64(str: string): string { try { return btoa(str); @@ -3010,7 +3018,7 @@ async function getHeaders(options: ApiRequestOptions): Promise { headers.append('Content-Type', options.body.type || 'application/octet-stream'); } else if (isString(options.body)) { headers.append('Content-Type', 'text/plain'); - } else { + } else if (!isFormData(options.body)) { headers.append('Content-Type', 'application/json'); } } @@ -3022,7 +3030,7 @@ function getRequestBody(options: ApiRequestOptions): BodyInit | undefined { if (options.body) { if (options.mediaType?.includes('/json')) { return JSON.stringify(options.body) - } else if (isString(options.body) || isBlob(options.body)) { + } else if (isString(options.body) || isBlob(options.body) || isFormData(options.body)) { return options.body; } else { return JSON.stringify(options.body);