DOP-3505: Redoc CLI ingests version data from json file (#15)

This commit is contained in:
mmeigs 2023-02-16 14:17:47 -05:00 committed by GitHub
parent 2d61688fcc
commit da330e9178
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 136 additions and 20 deletions

View File

@ -40,6 +40,35 @@ With `node` installed, run by doing the following:
node <path/to/redoc/cli/index.js> build <path/to/spec/file/or/url> --options=<path/to/options.json> --output=<path/to/custom/output/file/name.html> node <path/to/redoc/cli/index.js> build <path/to/spec/file/or/url> --options=<path/to/options.json> --output=<path/to/custom/output/file/name.html>
``` ```
#### Versioned Options in the CLI
If wanting to add versioning support in your build, you must create a JSON file with the following data structure (replace example values with any mock values):
```
{
"active": {
"apiVersion": "2.0",
"resourceVersion": "2023-02-14"
},
"rootUrl": "https://mongodb.com/docs/atlas/reference/api-resources-spec/v2",
"resourceVersions": ["2022-09-09", "2022-10-18", "2023-02-14"]
}
```
After doing so, run the build much the same as above but with the following option added:
Note: the path to the version data option JSON file should be referenced in relation to the `redoc/cli` directory
```
--options.versionData=<path/to/mock/data/file.json/from/cli/directory>
```
Such as:
Note: this is referencing a JSON file in the root directory
```
node <path/to/redoc/cli/index.js> build <path/to/spec/file/or/url> --options.versionData=../version-data.json
```
### Releasing ### Releasing
The Redoc React component and the Redoc CLI have 2 separate release processes. Because the Redoc CLI pulls its version of Redoc from GitHub, build artifacts are included in the version tag being installed. The Redoc React component and the Redoc CLI have 2 separate release processes. Because the Redoc CLI pulls its version of Redoc from GitHub, build artifacts are included in the version tag being installed.

View File

@ -27,4 +27,29 @@ describe('build', () => {
expect(result).toContain('Found .redocly.yaml and using features.openapi options'); expect(result).toContain('Found .redocly.yaml and using features.openapi options');
expect(result).toContain('bundled successfully'); expect(result).toContain('bundled successfully');
}); });
it('should ingest version data from json file', () => {
const pathToTestData = '__test__/data/version-data.json';
const r = spawnSync(
'ts-node',
[
'../../../index.ts',
'build',
' ../../../../demo/openapi.yaml',
'--output=redoc-test.html',
`--options.versionData=${pathToTestData}`,
],
{
cwd: __dirname,
shell: true,
},
);
const out = r.stdout.toString('utf-8');
const err = r.stderr.toString('utf-8');
const result = `${out}\n${err}`;
expect(result).toContain(`Found ${pathToTestData} and using version data.`);
expect(result).toContain('bundled successfully');
});
}); });

View File

@ -0,0 +1,8 @@
{
"active": {
"apiVersion": "2.0",
"resourceVersion": "2023-02-14"
},
"rootUrl": "https://mongodb.com/docs/atlas/reference/api-resources-spec/v2",
"resourceVersions": ["2022-09-09", "2022-10-18", "2028-02-14"]
}

View File

@ -439,6 +439,22 @@ function handleError(error: Error) {
function getObjectOrJSON(options) { function getObjectOrJSON(options) {
switch (typeof options) { switch (typeof options) {
case 'object': case 'object':
if (options?.versionData) {
const { versionData: versionPath } = options;
const versionFilePath = resolve(__dirname, versionPath);
try {
if (existsSync(versionFilePath) && lstatSync(versionFilePath).isFile()) {
const versionData = JSON.parse(readFileSync(versionFilePath, 'utf-8'));
options.versionData = versionData;
console.log(`Found ${versionPath} and using version data.`);
}
} catch (e) {
console.log(
`Encountered error:\n\n${versionPath}\n\nis not a file with a valid JSON object.`,
);
handleError(e);
}
}
return options; return options;
case 'string': case 'string':
try { try {

View File

@ -4,7 +4,7 @@ describe('Menu', () => {
}); });
it('should have valid items count', () => { it('should have valid items count', () => {
cy.get('.menu-content').find('li').should('have.length', 35); cy.get('.menu-content').find('li').not('[role="option"]').should('have.length', 35);
}); });
it('should have a back button', () => { it('should have a back button', () => {

View File

@ -21,6 +21,7 @@ import {
import { SearchBox } from '../SearchBox/SearchBox'; import { SearchBox } from '../SearchBox/SearchBox';
import { StoreProvider } from '../StoreBuilder'; import { StoreProvider } from '../StoreBuilder';
import { VersionSelector } from '../VersionSelector';
export interface RedocProps { export interface RedocProps {
store: AppStore; store: AppStore;
@ -69,6 +70,9 @@ export class Redoc extends React.Component<RedocProps> {
/> />
)) || )) ||
null} null}
{options.versionData && typeof options.versionData == 'object' && (
<VersionSelector {...options.versionData} />
)}
<SideMenu menu={menu} /> <SideMenu menu={menu} />
</StickyResponsiveSidebar> </StickyResponsiveSidebar>
<ApiContentWrap className="api-content"> <ApiContentWrap className="api-content">

View File

@ -9,6 +9,7 @@ import {
StyledMenuList, StyledMenuList,
StyledDisplay, StyledDisplay,
StyledDropdown, StyledDropdown,
StyledSelected,
} from './styled.elements'; } from './styled.elements';
import { Option } from './Option'; import { Option } from './Option';
import { VersionSelectorProps } from './types'; import { VersionSelectorProps } from './types';
@ -42,9 +43,7 @@ const VersionSelectorComponent = ({
{description && <StyledDescription>{description}</StyledDescription>} {description && <StyledDescription>{description}</StyledDescription>}
<StyledButton onClick={() => setOpen(!open)}> <StyledButton onClick={() => setOpen(!open)}>
<StyledDisplay> <StyledDisplay>
<div> <StyledSelected>{resourceVersions[selectedIdx]}</StyledSelected>
<div>{resourceVersions[selectedIdx]}</div>
</div>
<ArrowIcon open={open} /> <ArrowIcon open={open} />
</StyledDisplay> </StyledDisplay>
</StyledButton> </StyledButton>

View File

@ -10,7 +10,7 @@ const transitionDuration = {
slower: 300, slower: 300,
} as const; } as const;
export const ArrowIcon = styled(ArrowSvg)` export const ArrowIcon = styled(ArrowSvg)<{ open: boolean }>`
position: absolute; position: absolute;
pointer-events: none; pointer-events: none;
z-index: 1; z-index: 1;
@ -101,12 +101,17 @@ export const StyledMenuList = styled.ul`
`; `;
export const StyledDisplay = styled.div` export const StyledDisplay = styled.div`
width: 100%;
display: grid; display: grid;
grid-template-columns: 1fr 16px; grid-template-columns: 1fr 16px;
gap: 6px; gap: 6px;
padding: 0 4px 0 12px; padding: 0 4px 0 12px;
`; `;
export const StyledSelected = styled.div`
display: flex;
`;
export const disabledOptionStyle = css` export const disabledOptionStyle = css`
cursor: not-allowed; cursor: not-allowed;
color: ${palette.gray.base}; color: ${palette.gray.base};

View File

@ -354,6 +354,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
}, },
"unstable_ignoreMimeParameters": false, "unstable_ignoreMimeParameters": false,
"untrustedSpec": false, "untrustedSpec": false,
"versionData": undefined,
}, },
"pattern": undefined, "pattern": undefined,
"pointer": "#/components/schemas/Dog/properties/packSize", "pointer": "#/components/schemas/Dog/properties/packSize",
@ -687,6 +688,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
}, },
"unstable_ignoreMimeParameters": false, "unstable_ignoreMimeParameters": false,
"untrustedSpec": false, "untrustedSpec": false,
"versionData": undefined,
}, },
"pattern": undefined, "pattern": undefined,
"pointer": "#/components/schemas/Dog/properties/type", "pointer": "#/components/schemas/Dog/properties/type",
@ -1007,6 +1009,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
}, },
"unstable_ignoreMimeParameters": false, "unstable_ignoreMimeParameters": false,
"untrustedSpec": false, "untrustedSpec": false,
"versionData": undefined,
}, },
"pattern": undefined, "pattern": undefined,
"pointer": "#/components/schemas/Dog", "pointer": "#/components/schemas/Dog",
@ -1389,6 +1392,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
}, },
"unstable_ignoreMimeParameters": false, "unstable_ignoreMimeParameters": false,
"untrustedSpec": false, "untrustedSpec": false,
"versionData": undefined,
}, },
"pattern": undefined, "pattern": undefined,
"pointer": "#/components/schemas/Cat/properties/type", "pointer": "#/components/schemas/Cat/properties/type",
@ -1734,6 +1738,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
}, },
"unstable_ignoreMimeParameters": false, "unstable_ignoreMimeParameters": false,
"untrustedSpec": false, "untrustedSpec": false,
"versionData": undefined,
}, },
"pattern": undefined, "pattern": undefined,
"pointer": "#/components/schemas/Cat/properties/packSize", "pointer": "#/components/schemas/Cat/properties/packSize",
@ -2050,6 +2055,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
}, },
"unstable_ignoreMimeParameters": false, "unstable_ignoreMimeParameters": false,
"untrustedSpec": false, "untrustedSpec": false,
"versionData": undefined,
}, },
"pattern": undefined, "pattern": undefined,
"pointer": "#/components/schemas/Cat", "pointer": "#/components/schemas/Cat",
@ -2391,6 +2397,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
}, },
"unstable_ignoreMimeParameters": false, "unstable_ignoreMimeParameters": false,
"untrustedSpec": false, "untrustedSpec": false,
"versionData": undefined,
}, },
"pattern": undefined, "pattern": undefined,
"pointer": "#/components/schemas/Pet", "pointer": "#/components/schemas/Pet",
@ -2762,6 +2769,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
}, },
"unstable_ignoreMimeParameters": false, "unstable_ignoreMimeParameters": false,
"untrustedSpec": false, "untrustedSpec": false,
"versionData": undefined,
}, },
"pattern": undefined, "pattern": undefined,
"pointer": "#/components/schemas/Dog/properties/packSize", "pointer": "#/components/schemas/Dog/properties/packSize",
@ -3095,6 +3103,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
}, },
"unstable_ignoreMimeParameters": false, "unstable_ignoreMimeParameters": false,
"untrustedSpec": false, "untrustedSpec": false,
"versionData": undefined,
}, },
"pattern": undefined, "pattern": undefined,
"pointer": "#/components/schemas/Dog/properties/type", "pointer": "#/components/schemas/Dog/properties/type",
@ -3415,6 +3424,7 @@ exports[`Components SchemaView discriminator should correctly render SchemaView
}, },
"unstable_ignoreMimeParameters": false, "unstable_ignoreMimeParameters": false,
"untrustedSpec": false, "untrustedSpec": false,
"versionData": undefined,
}, },
"pattern": undefined, "pattern": undefined,
"pointer": "#/components/schemas/Dog", "pointer": "#/components/schemas/Dog",

View File

@ -17,12 +17,12 @@ exports[`VersionSelector should correctly render VersionSelector 1`] = `
class="sc-hKFxyN hYrDYQ" class="sc-hKFxyN hYrDYQ"
> >
<div <div
class="sc-iCoGMd fgtoGu" class="sc-iCoGMd gojxeT"
> >
<div> <div
<div> class="sc-fujyAs hQJiDC"
2023-01-01 >
</div> 2023-01-01
</div> </div>
<svg <svg
fill="none" fill="none"
@ -44,7 +44,7 @@ exports[`VersionSelector should correctly render VersionSelector 1`] = `
</div> </div>
<div <div
aria-labelledby="View a different version of documentation." aria-labelledby="View a different version of documentation."
class="sc-jrsJWt ofjNY" class="sc-kEqXSa litKaz"
role="listbox" role="listbox"
tabindex="-1" tabindex="-1"
> >
@ -54,44 +54,44 @@ exports[`VersionSelector should correctly render VersionSelector 1`] = `
> >
<li <li
aria-selected="false" aria-selected="false"
class="sc-fujyAs iIVhNL" class="sc-pNWdM glxGCd"
role="option" role="option"
tabindex="0" tabindex="0"
> >
<span <span
class="sc-kEqXSa cBTyJc" class="sc-iqAclL dXUzZL"
/> />
<span <span
class="sc-pNWdM irvinq" class="sc-jrsJWt hDLwjI"
> >
2021-09-09 2021-09-09
</span> </span>
</li> </li>
<li <li
aria-selected="false" aria-selected="false"
class="sc-fujyAs iIVhNL" class="sc-pNWdM glxGCd"
role="option" role="option"
tabindex="0" tabindex="0"
> >
<span <span
class="sc-kEqXSa cBTyJc" class="sc-iqAclL dXUzZL"
/> />
<span <span
class="sc-pNWdM irvinq" class="sc-jrsJWt hDLwjI"
> >
2022-10-18 2022-10-18
</span> </span>
</li> </li>
<li <li
aria-selected="true" aria-selected="true"
class="sc-fujyAs Ywdfd" class="sc-pNWdM jlRKTH"
role="option" role="option"
selected="" selected=""
tabindex="0" tabindex="0"
> >
<svg <svg
aria-label="Checkmark Icon" aria-label="Checkmark Icon"
class="sc-iqAclL ejyrfD" class="sc-crzoAE gdYtkZ"
height="16" height="16"
role="img" role="img"
viewBox="0 0 16 16" viewBox="0 0 16 16"
@ -105,7 +105,7 @@ exports[`VersionSelector should correctly render VersionSelector 1`] = `
/> />
</svg> </svg>
<span <span
class="sc-pNWdM irvinq" class="sc-jrsJWt hDLwjI"
> >
2023-01-01 2023-01-01
</span> </span>

View File

@ -61,6 +61,16 @@ export interface RedocRawOptions {
backNavigationPath?: string; backNavigationPath?: string;
ignoreIncompatibleTypes?: boolean | string; ignoreIncompatibleTypes?: boolean | string;
siteTitle?: string; siteTitle?: string;
versionData?: string;
}
export interface VersionData {
active: {
apiVersion: string;
resourceVersion: string;
};
rootUrl: string;
resourceVersions: string[];
} }
export function argValueToBoolean(val?: string | boolean, defaultValue?: boolean): boolean { export function argValueToBoolean(val?: string | boolean, defaultValue?: boolean): boolean {
@ -269,6 +279,7 @@ export class RedocNormalizedOptions {
backNavigationPath?: string; backNavigationPath?: string;
ignoreIncompatibleTypes: boolean; ignoreIncompatibleTypes: boolean;
siteTitle?: string; siteTitle?: string;
versionData?: string | VersionData;
constructor(raw: RedocRawOptions, defaults: RedocRawOptions = {}) { constructor(raw: RedocRawOptions, defaults: RedocRawOptions = {}) {
raw = { ...defaults, ...raw }; raw = { ...defaults, ...raw };
@ -351,5 +362,6 @@ export class RedocNormalizedOptions {
this.backNavigationPath = raw.backNavigationPath; this.backNavigationPath = raw.backNavigationPath;
this.ignoreIncompatibleTypes = argValueToBoolean(raw.ignoreIncompatibleTypes); this.ignoreIncompatibleTypes = argValueToBoolean(raw.ignoreIncompatibleTypes);
this.siteTitle = raw.siteTitle; this.siteTitle = raw.siteTitle;
this.versionData = raw.versionData;
} }
} }

8
version-data.json Normal file
View File

@ -0,0 +1,8 @@
{
"active": {
"apiVersion": "2.0",
"resourceVersion": "2023-02-14"
},
"rootUrl": "https://mongodb.com/docs/atlas/reference/api-resources-spec/v2",
"resourceVersions": ["2022-09-09", "2022-10-18", "2023-02-14"]
}