From b87cf0d8d5344681ff83b97f72c5ce07c5a39906 Mon Sep 17 00:00:00 2001 From: Roman Hotsiy Date: Thu, 4 Oct 2018 11:09:59 +0300 Subject: [PATCH] feat: new option sortPropsAlphabetically --- README.md | 1 + src/services/RedocNormalizedOptions.ts | 3 +++ src/services/models/Operation.ts | 4 ++++ src/services/models/Schema.ts | 7 ++++++- src/utils/openapi.ts | 8 +++++++- 5 files changed, 21 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3708a335..3eb80383 100644 --- a/README.md +++ b/README.md @@ -215,6 +215,7 @@ You can use all of the following options with standalone version on tag * `hideHostname` - if set, the protocol and hostname is not shown in the operation definition. * `expandResponses` - specify which responses to expand by default by response codes. Values should be passed as comma-separated list without spaces e.g. `expandResponses="200,201"`. Special value `"all"` expands all responses by default. Be careful: this option can slow-down documentation rendering time. * `requiredPropsFirst` - show required properties first ordered in the same order as in `required` array. +* `sortPropsAlphabetically` - sort properties alphabetically * `showExtensions` - show vendor extensions ("x-" fields). Extensions used by ReDoc are ignored. Can be boolean or an array of `string` with names of extensions to display * `noAutoAuth` - do not inject Authentication section automatically * `pathInMiddlePanel` - show path link and HTTP verb in the middle panel instead of the right one diff --git a/src/services/RedocNormalizedOptions.ts b/src/services/RedocNormalizedOptions.ts index c0368a3b..d472ae5d 100644 --- a/src/services/RedocNormalizedOptions.ts +++ b/src/services/RedocNormalizedOptions.ts @@ -10,6 +10,7 @@ export interface RedocRawOptions { hideHostname?: boolean | string; expandResponses?: string | 'all'; requiredPropsFirst?: boolean | string; + sortPropsAlphabetically?: boolean | string; noAutoAuth?: boolean | string; nativeScrollbars?: boolean | string; pathInMiddlePanel?: boolean | string; @@ -109,6 +110,7 @@ export class RedocNormalizedOptions { hideHostname: boolean; expandResponses: { [code: string]: boolean } | 'all'; requiredPropsFirst: boolean; + sortPropsAlphabetically: boolean; noAutoAuth: boolean; nativeScrollbars: boolean; pathInMiddlePanel: boolean; @@ -135,6 +137,7 @@ export class RedocNormalizedOptions { this.hideHostname = RedocNormalizedOptions.normalizeHideHostname(raw.hideHostname); this.expandResponses = RedocNormalizedOptions.normalizeExpandResponses(raw.expandResponses); this.requiredPropsFirst = argValueToBoolean(raw.requiredPropsFirst); + this.sortPropsAlphabetically = argValueToBoolean(raw.sortPropsAlphabetically); this.noAutoAuth = argValueToBoolean(raw.noAutoAuth); this.nativeScrollbars = argValueToBoolean(raw.nativeScrollbars); this.pathInMiddlePanel = argValueToBoolean(raw.pathInMiddlePanel); diff --git a/src/services/models/Operation.ts b/src/services/models/Operation.ts index de558086..3e31a367 100644 --- a/src/services/models/Operation.ts +++ b/src/services/models/Operation.ts @@ -20,6 +20,7 @@ import { memoize, mergeParams, normalizeServers, + sortByField, sortByRequired, } from '../../utils'; import { ContentItemModel, ExtendedOpenAPIOperation } from '../MenuBuilder'; @@ -152,6 +153,9 @@ export class OperationModel implements IMenuItem { // TODO: fix pointer ).map(paramOrRef => new FieldModel(this.parser, paramOrRef, this.pointer, this.options)); + if (this.options.sortPropsAlphabetically) { + sortByField(_parameters, 'name'); + } if (this.options.requiredPropsFirst) { sortByRequired(_parameters); } diff --git a/src/services/models/Schema.ts b/src/services/models/Schema.ts index ad13aa12..e5b69fcb 100644 --- a/src/services/models/Schema.ts +++ b/src/services/models/Schema.ts @@ -14,6 +14,7 @@ import { isNamedDefinition, isPrimitiveType, JsonPointer, + sortByField, sortByRequired, } from '../../utils/'; @@ -261,8 +262,12 @@ function buildFields( ); }); + if (options.sortPropsAlphabetically) { + sortByField(fields, 'name'); + } if (options.requiredPropsFirst) { - sortByRequired(fields, schema.required); + // if not sort alphabetically sort in the order from required keyword + sortByRequired(fields, !options.sortPropsAlphabetically ? schema.required : undefined); } if (typeof additionalProps === 'object' || additionalProps === true) { diff --git a/src/utils/openapi.ts b/src/utils/openapi.ts index 16c74a76..7e172132 100644 --- a/src/utils/openapi.ts +++ b/src/utils/openapi.ts @@ -196,13 +196,19 @@ export function sortByRequired( } else if (a.required && !b.required) { return -1; } else if (a.required && b.required) { - return order.indexOf(a.name) > order.indexOf(b.name) ? 1 : -1; + return order.indexOf(a.name) - order.indexOf(b.name); } else { return 0; } }); } +export function sortByField(fields: Array<{ [P in T]: string }>, param: T) { + fields.sort((a, b) => { + return a[param].localeCompare(b[param]); + }); +} + export function mergeParams( parser: OpenAPIParser, pathParams: Array> = [],