Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: exclusiveMin/Max shows incorect range #1799

Merged
merged 12 commits into from
Nov 24, 2021
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.md
47 changes: 24 additions & 23 deletions config/docker/index.tpl.html
Original file line number Diff line number Diff line change
@@ -1,27 +1,28 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>%PAGE_TITLE%</title>
<link rel="icon" href="%PAGE_FAVICON%" />
<style>
body {
margin: 0;
padding: 0;
}

<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>%PAGE_TITLE%</title>
<link rel="icon" href="%PAGE_FAVICON%">
<style>
body {
margin: 0;
padding: 0;
}
redoc {
display: block;
}
</style>
<link
href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700"
rel="stylesheet"
/>
</head>

redoc {
display: block;
}
</style>
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet">
</head>

<body>
<redoc spec-url="%SPEC_URL%" %REDOC_OPTIONS%></redoc>
<script src="redoc.standalone.js"></script>
</body>

</html>
<body>
<redoc spec-url="%SPEC_URL%" %REDOC_OPTIONS%></redoc>
<script src="redoc.standalone.js"></script>
</body>
</html>
10 changes: 5 additions & 5 deletions docs/deployment/intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,13 @@ The following options are supported:
### OpenAPI definition

You will need an OpenAPI definition. For testing purposes, you can use one of the following sample OpenAPI definitions:

- OpenAPI 3.0
- [Rebilly Users OpenAPI Definition](https://raw.githubusercontent.com/Rebilly/api-definitions/main/openapi/users.yaml)
- [Swagger Petstore Sample OpenAPI Definition](https://petstore3.swagger.io/api/v3/openapi.json)
- [Rebilly Users OpenAPI Definition](https://raw.githubusercontent.com/Rebilly/api-definitions/main/openapi/users.yaml)
- [Swagger Petstore Sample OpenAPI Definition](https://petstore3.swagger.io/api/v3/openapi.json)
- OpenAPI 2.0
- [Thingful OpenAPI Definition](https://raw.githubusercontent.com/thingful/openapi-spec/master/spec/swagger.yaml)
- [Fitbit Plus OpenAPI Definition](https://raw.githubusercontent.com/TwineHealth/TwineDeveloperDocs/master/spec/swagger.yaml)

- [Thingful OpenAPI Definition](https://raw.githubusercontent.com/thingful/openapi-spec/master/spec/swagger.yaml)
- [Fitbit Plus OpenAPI Definition](https://raw.githubusercontent.com/TwineHealth/TwineDeveloperDocs/master/spec/swagger.yaml)

:::info OpenAPI specification
For more information on the OpenAPI specification, refer to the [Learning OpenAPI 3](https://redoc.ly/docs/resources/learning-openapi/)
Expand Down
16 changes: 9 additions & 7 deletions docs/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,12 @@ replace the `spec-url` attribute with the URL or local file address to your defi
<head>
<title>Redoc</title>
<!-- needed for adaptive design -->
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet">
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link
href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700"
rel="stylesheet"
/>

<!--
Redoc doesn't change outer page styles
Expand All @@ -28,17 +31,16 @@ replace the `spec-url` attribute with the URL or local file address to your defi
</style>
</head>
<body>
<!--
<!--
Redoc element with link to your OpenAPI definition
-->
<redoc spec-url='http://petstore.swagger.io/v2/swagger.json'></redoc>
<redoc spec-url="http://petstore.swagger.io/v2/swagger.json"></redoc>
<!--
Link to Redoc JavaScript on CDN for rendering standalone element
-->
<script src="https://cdn.jsdelivr.net/npm/redoc@latest/bundles/redoc.standalone.js"> </script>
<script src="https://cdn.jsdelivr.net/npm/redoc@latest/bundles/redoc.standalone.js"></script>
</body>
</html>

```

:::attention Running Redoc locally requires an HTTP server
Expand Down
16 changes: 8 additions & 8 deletions src/common-elements/dropdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,16 @@ export const StyledDropdown = styled(Dropdown)`
width: auto;
background: white;
color: #263238;
font-family: ${(props) => props.theme.typography.headings.fontFamily};
font-family: ${props => props.theme.typography.headings.fontFamily};
font-size: 0.929em;
line-height: 1.5em;
cursor: pointer;
transition: border 0.25s ease, color 0.25s ease, box-shadow 0.25s ease;
&:hover,
&:focus-within {
border: 1px solid ${(props) => props.theme.colors.primary.main};
color: ${(props) => props.theme.colors.primary.main};
box-shadow: 0px 0px 0px 1px ${(props) => props.theme.colors.primary.main};
border: 1px solid ${props => props.theme.colors.primary.main};
color: ${props => props.theme.colors.primary.main};
box-shadow: 0px 0px 0px 1px ${props => props.theme.colors.primary.main};
}
.dropdown-selector {
display: inline-flex;
Expand All @@ -48,7 +48,7 @@ export const StyledDropdown = styled(Dropdown)`
margin-bottom: 5px;
}
.dropdown-selector-value {
font-family: ${(props) => props.theme.typography.headings.fontFamily};
font-family: ${props => props.theme.typography.headings.fontFamily};
position: relative;
font-size: 0.929em;
width: 100%;
Expand All @@ -63,7 +63,7 @@ export const StyledDropdown = styled(Dropdown)`
right: 3px;
top: 50%;
transform: translateY(-50%);
border-color: ${(props) => props.theme.colors.primary.main} transparent transparent;
border-color: ${props => props.theme.colors.primary.main} transparent transparent;
border-style: solid;
border-width: 0.35em 0.35em 0;
width: 0;
Expand Down Expand Up @@ -128,8 +128,8 @@ export const SimpleDropdown = styled(StyledDropdown)`
border: none;
box-shadow: none;
.dropdown-selector-value {
color: ${(props) => props.theme.colors.primary.main};
text-shadow: 0px 0px 0px ${(props) => props.theme.colors.primary.main};
color: ${props => props.theme.colors.primary.main};
text-shadow: 0px 0px 0px ${props => props.theme.colors.primary.main};
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/components/Callbacks/CallbackTitle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,10 @@ const CallbackTitleWrapper = styled.button`
`;

const CallbackName = styled.span<{ deprecated?: boolean }>`
text-decoration: ${(props) => (props.deprecated ? 'line-through' : 'none')};
text-decoration: ${props => (props.deprecated ? 'line-through' : 'none')};
margin-right: 8px;
`;

const OperationBadgeStyled = styled(OperationBadge)`
margin: 0px 5px 0px 0px;
margin: 0 5px 0 0;
`;
4 changes: 2 additions & 2 deletions src/components/JsonViewer/JsonViewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@ class Json extends React.PureComponent<JsonProps> {
<button onClick={this.collapseAll}> Collapse all </button>
</SampleControls>
<OptionsContext.Consumer>
{(options) => (
{options => (
<PrismDiv
className={this.props.className}
// tslint:disable-next-line
ref={(node) => (this.node = node!)}
ref={node => (this.node = node!)}
dangerouslySetInnerHTML={{
__html: jsonToHTML(this.props.data, options.jsonSampleExpandLevel),
}}
Expand Down
8 changes: 4 additions & 4 deletions src/components/JsonViewer/style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ export const jsonStyles = css`
pointer-events: none;
}

font-family: ${(props) => props.theme.typography.code.fontFamily};
font-size: ${(props) => props.theme.typography.code.fontSize};
font-family: ${props => props.theme.typography.code.fontFamily};
font-size: ${props => props.theme.typography.code.fontSize};

white-space: ${({ theme }) => (theme.typography.code.wrap ? 'pre-wrap' : 'pre')};
contain: content;
Expand Down Expand Up @@ -51,8 +51,8 @@ export const jsonStyles = css`
background-color: transparent;
border: 0;
color: #fff;
font-family: ${(props) => props.theme.typography.code.fontFamily};
font-size: ${(props) => props.theme.typography.code.fontSize};
font-family: ${props => props.theme.typography.code.fontFamily};
font-size: ${props => props.theme.typography.code.fontSize};
padding-right: 6px;
padding-left: 6px;
padding-top: 0;
Expand Down
2 changes: 1 addition & 1 deletion src/components/Operation/Operation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export class Operation extends React.Component<OperationProps> {

return (
<OptionsContext.Consumer>
{(options) => (
{options => (
<OperationRow>
<MiddlePanel>
<H2>
Expand Down
8 changes: 4 additions & 4 deletions src/components/Responses/styled.elements.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ export const StyledResponseTitle = styled(ResponseTitle)`
background-color: #f2f2f2;
cursor: pointer;

color: ${(props) => props.theme.colors.responses[props.type].color};
background-color: ${(props) => props.theme.colors.responses[props.type].backgroundColor};
color: ${props => props.theme.colors.responses[props.type].color};
background-color: ${props => props.theme.colors.responses[props.type].backgroundColor};
&:focus {
outline: auto;
outline-color: ${(props) => props.theme.colors.responses[props.type].color};
outline-color: ${props => props.theme.colors.responses[props.type].color};
}
${(props) =>
${props =>
(props.empty &&
`
cursor: default;
Expand Down
10 changes: 5 additions & 5 deletions src/components/SecurityRequirement/SecurityRequirement.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import { SecurityRequirementModel } from '../../services/models/SecurityRequirem
import { linksCss } from '../Markdown/styled.elements';

const ScopeName = styled.code`
font-size: ${(props) => props.theme.typography.code.fontSize};
font-family: ${(props) => props.theme.typography.code.fontFamily};
font-size: ${props => props.theme.typography.code.fontSize};
font-family: ${props => props.theme.typography.code.fontFamily};
border: 1px solid ${({ theme }) => theme.colors.border.dark};
margin: 0 3px;
padding: 0.2em;
Expand Down Expand Up @@ -67,12 +67,12 @@ export class SecurityRequirement extends React.PureComponent<SecurityRequirement
return (
<SecurityRequirementOrWrap>
{security.schemes.length ? (
security.schemes.map((scheme) => {
security.schemes.map(scheme => {
return (
<SecurityRequirementAndWrap key={scheme.id}>
<Link to={scheme.sectionId}>{scheme.id}</Link>
{scheme.scopes.length > 0 && ' ('}
{scheme.scopes.map((scope) => (
{scheme.scopes.map(scope => (
<ScopeName key={scope}>{scope}</ScopeName>
))}
{scheme.scopes.length > 0 && ') '}
Expand All @@ -92,7 +92,7 @@ const AuthHeaderColumn = styled.div`
`;

const SecuritiesColumn = styled.div`
width: ${(props) => props.theme.schema.defaultDetailsWidth};
width: ${props => props.theme.schema.defaultDetailsWidth};
${media.lessThan('small')`
margin-top: 10px;
`}
Expand Down
6 changes: 3 additions & 3 deletions src/services/RedocNormalizedOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export class RedocNormalizedOptions {
}
if (typeof value === 'string') {
const res = {};
value.split(',').forEach((code) => {
value.split(',').forEach(code => {
res[code.trim()] = true;
});
return res;
Expand Down Expand Up @@ -138,7 +138,7 @@ export class RedocNormalizedOptions {
case 'false':
return false;
default:
return value.split(',').map((ext) => ext.trim());
return value.split(',').map(ext => ext.trim());
}
}

Expand Down Expand Up @@ -266,7 +266,7 @@ export class RedocNormalizedOptions {
this.maxDisplayedEnumValues = argValueToNumber(raw.maxDisplayedEnumValues);
const ignoreNamedSchemas = Array.isArray(raw.ignoreNamedSchemas)
? raw.ignoreNamedSchemas
: raw.ignoreNamedSchemas?.split(',').map((s) => s.trim());
: raw.ignoreNamedSchemas?.split(',').map(s => s.trim());
this.ignoreNamedSchemas = new Set(ignoreNamedSchemas);
this.hideSchemaPattern = argValueToBoolean(raw.hideSchemaPattern);
this.generatedPayloadSamplesMaxDepth =
Expand Down
71 changes: 71 additions & 0 deletions src/utils/__tests__/openapi.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
pluralizeType,
serializeParameterValue,
sortByRequired,
humanizeNumberRange,
} from '../';

import { FieldModel, OpenAPIParser, RedocNormalizedOptions } from '../../services';
Expand Down Expand Up @@ -410,6 +411,76 @@ describe('Utils', () => {
});
});

describe('openapi humanizeNumberRange', () => {
it('should return `>=` when only minimum value present or exclusiveMinimum = false', () => {
const expected = '>= 0';
expect(humanizeNumberRange({ minimum: 0 })).toEqual(expected);
expect(humanizeNumberRange({ minimum: 0, exclusiveMinimum: false })).toEqual(expected);
});

it('should return `>` when minimum value present and exclusiveMinimum set to true', () => {
expect(humanizeNumberRange({ minimum: 0, exclusiveMinimum: true })).toEqual('> 0');
});

it('should return `<=` when only maximum value present or exclusiveMinimum = false', () => {
const expected = '<= 10';
expect(humanizeNumberRange({ maximum: 10 })).toEqual(expected);
expect(humanizeNumberRange({ maximum: 10, exclusiveMaximum: false })).toEqual(expected);
});

it('should return `<` when maximum value present and exclusiveMaximum set to true', () => {
expect(humanizeNumberRange({ maximum: 10, exclusiveMaximum: true })).toEqual('< 10');
});

it('should return correct range for minimum and maximum values and with different exclusive set', () => {
expect(humanizeNumberRange({ minimum: 0, maximum: 10 })).toEqual('[ 0 .. 10 ]');
expect(
humanizeNumberRange({
minimum: 0,
exclusiveMinimum: true,
maximum: 10,
exclusiveMaximum: true,
}),
).toEqual('( 0 .. 10 )');
expect(
humanizeNumberRange({
minimum: 0,
maximum: 10,
exclusiveMaximum: true,
}),
).toEqual('[ 0 .. 10 )');
expect(
humanizeNumberRange({
minimum: 0,
exclusiveMinimum: true,
maximum: 10,
}),
).toEqual('( 0 .. 10 ]');
});

it('should return correct range exclusive values only', () => {
expect(humanizeNumberRange({ exclusiveMinimum: 0 })).toEqual('> 0');
expect(humanizeNumberRange({ exclusiveMaximum: 10 })).toEqual('< 10');
expect(humanizeNumberRange({ exclusiveMinimum: 0, exclusiveMaximum: 10 })).toEqual(
'( 0 .. 10 )',
);
});

it('should return correct min value', () => {
expect(humanizeNumberRange({ minimum: 5, exclusiveMinimum: 10 })).toEqual('> 5');
expect(humanizeNumberRange({ minimum: -5, exclusiveMinimum: -10 })).toEqual('> -10');
});

it('should return correct max value', () => {
expect(humanizeNumberRange({ maximum: 10, exclusiveMaximum: 15 })).toEqual('< 15');
expect(humanizeNumberRange({ maximum: -10, exclusiveMaximum: -15 })).toEqual('< -10');
});

it('should return undefined', () => {
expect(humanizeNumberRange({})).toEqual(undefined);
});
});

describe('openapi humanizeConstraints', () => {
const itemConstraintSchema = (
min?: number,
Expand Down
Loading