diff --git a/src/openApi/v2/parser/getModel.ts b/src/openApi/v2/parser/getModel.ts index c95bbe0e..ba9dbba0 100644 --- a/src/openApi/v2/parser/getModel.ts +++ b/src/openApi/v2/parser/getModel.ts @@ -7,6 +7,7 @@ import { getComment } from './getComment'; import { getEnum } from './getEnum'; import { getEnumFromDescription } from './getEnumFromDescription'; import { getModelProperties } from './getModelProperties'; +import { getPattern } from './getPattern'; import { getType } from './getType'; export function getModel(openApi: OpenApi, definition: OpenApiSchema, isDefinition: boolean = false, name: string = ''): Model { @@ -30,12 +31,12 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, isDefiniti multipleOf: definition.multipleOf, maxLength: definition.maxLength, minLength: definition.minLength, - pattern: definition.pattern, maxItems: definition.maxItems, minItems: definition.minItems, uniqueItems: definition.uniqueItems, maxProperties: definition.maxProperties, minProperties: definition.minProperties, + pattern: getPattern(definition.pattern), imports: [], extends: [], enum: [], diff --git a/src/openApi/v2/parser/getModelProperties.ts b/src/openApi/v2/parser/getModelProperties.ts index f867a966..8ba58438 100644 --- a/src/openApi/v2/parser/getModelProperties.ts +++ b/src/openApi/v2/parser/getModelProperties.ts @@ -3,6 +3,7 @@ import type { OpenApi } from '../interfaces/OpenApi'; import type { OpenApiSchema } from '../interfaces/OpenApiSchema'; import { escapeName } from './escapeName'; import { getComment } from './getComment'; +import { getPattern } from './getPattern'; import { getType } from './getType'; // Fix for circular dependency between getModel and getModelProperties @@ -36,12 +37,12 @@ export function getModelProperties(openApi: OpenApi, definition: OpenApiSchema, multipleOf: property.multipleOf, maxLength: property.maxLength, minLength: property.minLength, - pattern: property.pattern, maxItems: property.maxItems, minItems: property.minItems, uniqueItems: property.uniqueItems, maxProperties: property.maxProperties, minProperties: property.minProperties, + pattern: getPattern(property.pattern), imports: model.imports, extends: [], enum: [], @@ -70,12 +71,12 @@ export function getModelProperties(openApi: OpenApi, definition: OpenApiSchema, multipleOf: property.multipleOf, maxLength: property.maxLength, minLength: property.minLength, - pattern: property.pattern, maxItems: property.maxItems, minItems: property.minItems, uniqueItems: property.uniqueItems, maxProperties: property.maxProperties, minProperties: property.minProperties, + pattern: getPattern(property.pattern), imports: model.imports, extends: model.extends, enum: model.enum, diff --git a/src/openApi/v2/parser/getOperationParameter.ts b/src/openApi/v2/parser/getOperationParameter.ts index c929b3b1..1a107801 100644 --- a/src/openApi/v2/parser/getOperationParameter.ts +++ b/src/openApi/v2/parser/getOperationParameter.ts @@ -9,6 +9,7 @@ import { getEnumFromDescription } from './getEnumFromDescription'; import { getModel } from './getModel'; import { getOperationParameterDefault } from './getOperationParameterDefault'; import { getOperationParameterName } from './getOperationParameterName'; +import { getPattern } from './getPattern'; import { getType } from './getType'; export function getOperationParameter(openApi: OpenApi, parameter: OpenApiParameter): OperationParameter { @@ -34,10 +35,10 @@ export function getOperationParameter(openApi: OpenApi, parameter: OpenApiParame multipleOf: parameter.multipleOf, maxLength: parameter.maxLength, minLength: parameter.minLength, - pattern: parameter.pattern, maxItems: parameter.maxItems, minItems: parameter.minItems, uniqueItems: parameter.uniqueItems, + pattern: getPattern(parameter.pattern), imports: [], extends: [], enum: [], diff --git a/src/openApi/v2/parser/getOperationResponse.ts b/src/openApi/v2/parser/getOperationResponse.ts index b7349750..025db6e7 100644 --- a/src/openApi/v2/parser/getOperationResponse.ts +++ b/src/openApi/v2/parser/getOperationResponse.ts @@ -4,6 +4,7 @@ import type { OpenApiResponse } from '../interfaces/OpenApiResponse'; import { PrimaryType } from './constants'; import { getComment } from './getComment'; import { getModel } from './getModel'; +import { getPattern } from './getPattern'; import { getType } from './getType'; export function getOperationResponse(openApi: OpenApi, response: OpenApiResponse, responseCode: number): OperationResponse { @@ -73,12 +74,12 @@ export function getOperationResponse(openApi: OpenApi, response: OpenApiResponse operationResponse.multipleOf = model.multipleOf; operationResponse.maxLength = model.maxLength; operationResponse.minLength = model.minLength; - operationResponse.pattern = model.pattern; operationResponse.maxItems = model.maxItems; operationResponse.minItems = model.minItems; operationResponse.uniqueItems = model.uniqueItems; operationResponse.maxProperties = model.maxProperties; operationResponse.minProperties = model.minProperties; + operationResponse.pattern = getPattern(model.pattern); operationResponse.imports.push(...model.imports); operationResponse.extends.push(...model.extends); operationResponse.enum.push(...model.enum); diff --git a/src/openApi/v2/parser/getPattern.spec.ts b/src/openApi/v2/parser/getPattern.spec.ts new file mode 100644 index 00000000..09094664 --- /dev/null +++ b/src/openApi/v2/parser/getPattern.spec.ts @@ -0,0 +1,14 @@ +import { getPattern } from './getPattern'; + +describe('getPattern', () => { + it('should produce correct result', () => { + expect(getPattern()).toEqual(undefined); + expect(getPattern('')).toEqual(''); + expect(getPattern('^[a-zA-Z]')).toEqual('^[a-zA-Z]'); + expect(getPattern('^\\w+$')).toEqual('^\\\\w+$'); + expect(getPattern('^\\d{3}-\\d{2}-\\d{4}$')).toEqual('^\\\\d{3}-\\\\d{2}-\\\\d{4}$'); + expect(getPattern('\\')).toEqual('\\\\'); + expect(getPattern('\\/')).toEqual('\\\\/'); + expect(getPattern('\\/\\/')).toEqual('\\\\/\\\\/'); + }); +}); diff --git a/src/openApi/v2/parser/getPattern.ts b/src/openApi/v2/parser/getPattern.ts new file mode 100644 index 00000000..a4f54bfa --- /dev/null +++ b/src/openApi/v2/parser/getPattern.ts @@ -0,0 +1,10 @@ +/** + * The spec generates a pattern like this '^\d{3}-\d{2}-\d{4}$' + * However, to use it in HTML or inside new RegExp() we need to + * escape the pattern to become: '^\\d{3}-\\d{2}-\\d{4}$' in order + * to make it a valid regexp string. + * @param pattern + */ +export function getPattern(pattern?: string): string | undefined { + return pattern?.replace(/\\/g, '\\\\'); +} diff --git a/src/openApi/v3/parser/getModel.ts b/src/openApi/v3/parser/getModel.ts index d7ef1678..e57553fa 100644 --- a/src/openApi/v3/parser/getModel.ts +++ b/src/openApi/v3/parser/getModel.ts @@ -8,6 +8,7 @@ import { getEnum } from './getEnum'; import { getEnumFromDescription } from './getEnumFromDescription'; import { getModelDefault } from './getModelDefault'; import { getModelProperties } from './getModelProperties'; +import { getPattern } from './getPattern'; import { getType } from './getType'; export function getModel(openApi: OpenApi, definition: OpenApiSchema, isDefinition: boolean = false, name: string = ''): Model { @@ -31,12 +32,12 @@ export function getModel(openApi: OpenApi, definition: OpenApiSchema, isDefiniti multipleOf: definition.multipleOf, maxLength: definition.maxLength, minLength: definition.minLength, - pattern: definition.pattern, maxItems: definition.maxItems, minItems: definition.minItems, uniqueItems: definition.uniqueItems, maxProperties: definition.maxProperties, minProperties: definition.minProperties, + pattern: getPattern(definition.pattern), imports: [], extends: [], enum: [], diff --git a/src/openApi/v3/parser/getModelProperties.ts b/src/openApi/v3/parser/getModelProperties.ts index dc804fd2..5030faf7 100644 --- a/src/openApi/v3/parser/getModelProperties.ts +++ b/src/openApi/v3/parser/getModelProperties.ts @@ -3,6 +3,7 @@ import type { OpenApi } from '../interfaces/OpenApi'; import type { OpenApiSchema } from '../interfaces/OpenApiSchema'; import { escapeName } from './escapeName'; import { getComment } from './getComment'; +import { getPattern } from './getPattern'; import { getType } from './getType'; // Fix for circular dependency between getModel and getModelProperties @@ -36,12 +37,12 @@ export function getModelProperties(openApi: OpenApi, definition: OpenApiSchema, multipleOf: property.multipleOf, maxLength: property.maxLength, minLength: property.minLength, - pattern: property.pattern, maxItems: property.maxItems, minItems: property.minItems, uniqueItems: property.uniqueItems, maxProperties: property.maxProperties, minProperties: property.minProperties, + pattern: getPattern(property.pattern), imports: model.imports, extends: [], enum: [], @@ -70,12 +71,12 @@ export function getModelProperties(openApi: OpenApi, definition: OpenApiSchema, multipleOf: property.multipleOf, maxLength: property.maxLength, minLength: property.minLength, - pattern: property.pattern, maxItems: property.maxItems, minItems: property.minItems, uniqueItems: property.uniqueItems, maxProperties: property.maxProperties, minProperties: property.minProperties, + pattern: getPattern(property.pattern), imports: model.imports, extends: model.extends, enum: model.enum, diff --git a/src/openApi/v3/parser/getOperationParameter.ts b/src/openApi/v3/parser/getOperationParameter.ts index 409aca72..15e703b0 100644 --- a/src/openApi/v3/parser/getOperationParameter.ts +++ b/src/openApi/v3/parser/getOperationParameter.ts @@ -6,6 +6,7 @@ import { getComment } from './getComment'; import { getModel } from './getModel'; import { getModelDefault } from './getModelDefault'; import { getOperationParameterName } from './getOperationParameterName'; +import { getPattern } from './getPattern'; import { getType } from './getType'; export function getOperationParameter(openApi: OpenApi, parameter: OpenApiParameter): OperationParameter { @@ -68,12 +69,12 @@ export function getOperationParameter(openApi: OpenApi, parameter: OpenApiParame operationParameter.multipleOf = model.multipleOf; operationParameter.maxLength = model.maxLength; operationParameter.minLength = model.minLength; - operationParameter.pattern = model.pattern; operationParameter.maxItems = model.maxItems; operationParameter.minItems = model.minItems; operationParameter.uniqueItems = model.uniqueItems; operationParameter.maxProperties = model.maxProperties; operationParameter.minProperties = model.minProperties; + operationParameter.pattern = getPattern(model.pattern); operationParameter.default = model.default; operationParameter.imports.push(...model.imports); operationParameter.extends.push(...model.extends); diff --git a/src/openApi/v3/parser/getOperationRequestBody.ts b/src/openApi/v3/parser/getOperationRequestBody.ts index 62a0cb01..dd517e99 100644 --- a/src/openApi/v3/parser/getOperationRequestBody.ts +++ b/src/openApi/v3/parser/getOperationRequestBody.ts @@ -5,6 +5,7 @@ import { PrimaryType } from './constants'; import { getComment } from './getComment'; import { getContent } from './getContent'; import { getModel } from './getModel'; +import { getPattern } from './getPattern'; import { getType } from './getType'; export function getOperationRequestBody(openApi: OpenApi, parameter: OpenApiRequestBody): OperationParameter { @@ -59,12 +60,12 @@ export function getOperationRequestBody(openApi: OpenApi, parameter: OpenApiRequ requestBody.multipleOf = model.multipleOf; requestBody.maxLength = model.maxLength; requestBody.minLength = model.minLength; - requestBody.pattern = model.pattern; requestBody.maxItems = model.maxItems; requestBody.minItems = model.minItems; requestBody.uniqueItems = model.uniqueItems; requestBody.maxProperties = model.maxProperties; requestBody.minProperties = model.minProperties; + requestBody.pattern = getPattern(model.pattern); requestBody.imports.push(...model.imports); requestBody.extends.push(...model.extends); requestBody.enum.push(...model.enum); diff --git a/src/openApi/v3/parser/getOperationResponse.ts b/src/openApi/v3/parser/getOperationResponse.ts index e3118512..6c86c96d 100644 --- a/src/openApi/v3/parser/getOperationResponse.ts +++ b/src/openApi/v3/parser/getOperationResponse.ts @@ -5,6 +5,7 @@ import { PrimaryType } from './constants'; import { getComment } from './getComment'; import { getContent } from './getContent'; import { getModel } from './getModel'; +import { getPattern } from './getPattern'; import { getType } from './getType'; export function getOperationResponse(openApi: OpenApi, response: OpenApiResponse, responseCode: number): OperationResponse { @@ -72,12 +73,12 @@ export function getOperationResponse(openApi: OpenApi, response: OpenApiResponse operationResponse.multipleOf = model.multipleOf; operationResponse.maxLength = model.maxLength; operationResponse.minLength = model.minLength; - operationResponse.pattern = model.pattern; operationResponse.maxItems = model.maxItems; operationResponse.minItems = model.minItems; operationResponse.uniqueItems = model.uniqueItems; operationResponse.maxProperties = model.maxProperties; operationResponse.minProperties = model.minProperties; + operationResponse.pattern = getPattern(model.pattern); operationResponse.imports.push(...model.imports); operationResponse.extends.push(...model.extends); operationResponse.enum.push(...model.enum); diff --git a/src/openApi/v3/parser/getPattern.spec.ts b/src/openApi/v3/parser/getPattern.spec.ts new file mode 100644 index 00000000..09094664 --- /dev/null +++ b/src/openApi/v3/parser/getPattern.spec.ts @@ -0,0 +1,14 @@ +import { getPattern } from './getPattern'; + +describe('getPattern', () => { + it('should produce correct result', () => { + expect(getPattern()).toEqual(undefined); + expect(getPattern('')).toEqual(''); + expect(getPattern('^[a-zA-Z]')).toEqual('^[a-zA-Z]'); + expect(getPattern('^\\w+$')).toEqual('^\\\\w+$'); + expect(getPattern('^\\d{3}-\\d{2}-\\d{4}$')).toEqual('^\\\\d{3}-\\\\d{2}-\\\\d{4}$'); + expect(getPattern('\\')).toEqual('\\\\'); + expect(getPattern('\\/')).toEqual('\\\\/'); + expect(getPattern('\\/\\/')).toEqual('\\\\/\\\\/'); + }); +}); diff --git a/src/openApi/v3/parser/getPattern.ts b/src/openApi/v3/parser/getPattern.ts new file mode 100644 index 00000000..a4f54bfa --- /dev/null +++ b/src/openApi/v3/parser/getPattern.ts @@ -0,0 +1,10 @@ +/** + * The spec generates a pattern like this '^\d{3}-\d{2}-\d{4}$' + * However, to use it in HTML or inside new RegExp() we need to + * escape the pattern to become: '^\\d{3}-\\d{2}-\\d{4}$' in order + * to make it a valid regexp string. + * @param pattern + */ +export function getPattern(pattern?: string): string | undefined { + return pattern?.replace(/\\/g, '\\\\'); +} diff --git a/src/templates/partials/schemaGeneric.hbs b/src/templates/partials/schemaGeneric.hbs index dc81e351..7b0d96c9 100644 --- a/src/templates/partials/schemaGeneric.hbs +++ b/src/templates/partials/schemaGeneric.hbs @@ -36,7 +36,7 @@ minLength: {{{minLength}}}, {{/if}} {{#if pattern}} - pattern: /{{{pattern}}}/, + pattern: '{{{pattern}}}', {{/if}} {{#if maxItems}} maxItems: {{{maxItems}}}, diff --git a/test/__snapshots__/index.spec.js.snap b/test/__snapshots__/index.spec.js.snap index 0781ef30..46904de4 100644 --- a/test/__snapshots__/index.spec.js.snap +++ b/test/__snapshots__/index.spec.js.snap @@ -883,6 +883,8 @@ export interface ModelWithPattern { name: string; readonly enabled?: boolean; readonly modified?: string; + id?: string; + text?: string; } " `; @@ -1525,7 +1527,7 @@ export const $ModelWithPattern = { type: 'string', isRequired: true, maxLength: 64, - pattern: /^[a-zA-Z0-9_]*$/, + pattern: '^[a-zA-Z0-9_]*$', }, name: { type: 'string', @@ -1541,6 +1543,14 @@ export const $ModelWithPattern = { isReadOnly: true, format: 'date-time', }, + id: { + type: 'string', + pattern: '^\\\\\\\\d{2}-\\\\\\\\d{3}-\\\\\\\\d{4}$', + }, + text: { + type: 'string', + pattern: '^\\\\\\\\w+$', + }, }, };" `; @@ -1671,7 +1681,7 @@ exports[`v2 should generate: ./test/generated/v2/schemas/$SimpleStringWithPatter export const $SimpleStringWithPattern = { type: 'string', maxLength: 64, - pattern: /^[a-zA-Z0-9_]*$/, + pattern: '^[a-zA-Z0-9_]*$', };" `; @@ -3105,6 +3115,8 @@ export interface ModelWithPattern { name: string; readonly enabled?: boolean; readonly modified?: string; + id?: string; + text?: string; } " `; @@ -3758,7 +3770,7 @@ export const $ModelWithPattern = { type: 'string', isRequired: true, maxLength: 64, - pattern: /^[a-zA-Z0-9_]*$/, + pattern: '^[a-zA-Z0-9_]*$', }, name: { type: 'string', @@ -3774,6 +3786,14 @@ export const $ModelWithPattern = { isReadOnly: true, format: 'date-time', }, + id: { + type: 'string', + pattern: '^\\\\\\\\d{2}-\\\\\\\\d{3}-\\\\\\\\d{4}$', + }, + text: { + type: 'string', + pattern: '^\\\\\\\\w+$', + }, }, };" `; @@ -3910,7 +3930,7 @@ export const $SimpleStringWithPattern = { type: 'string', isNullable: true, maxLength: 64, - pattern: /^[a-zA-Z0-9_]*$/, + pattern: '^[a-zA-Z0-9_]*$', };" `; diff --git a/test/spec/v2.json b/test/spec/v2.json index 6159a8a8..5649e438 100644 --- a/test/spec/v2.json +++ b/test/spec/v2.json @@ -1234,6 +1234,14 @@ "type": "string", "format": "date-time", "readOnly": true + }, + "id": { + "type": "string", + "pattern": "^\\d{2}-\\d{3}-\\d{4}$" + }, + "text": { + "type": "string", + "pattern": "^\\w+$" } } } diff --git a/test/spec/v3.json b/test/spec/v3.json index f0843826..daa47fd0 100644 --- a/test/spec/v3.json +++ b/test/spec/v3.json @@ -1751,6 +1751,14 @@ "type": "string", "format": "date-time", "readOnly": true + }, + "id": { + "type": "string", + "pattern": "^\\d{2}-\\d{3}-\\d{4}$" + }, + "text": { + "type": "string", + "pattern": "^\\w+$" } } }