Skip to content

Commit 90b7199

Browse files
committed
Add support scaffolding for open api spec 3.2.
1 parent f4aab72 commit 90b7199

File tree

8 files changed

+33
-8
lines changed

8 files changed

+33
-8
lines changed

.vscode/settings.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
"randombytes",
1313
"rapidoc",
1414
"redoc",
15-
"sublicensees"
15+
"sublicensees",
16+
"toposort"
1617
],
1718
"files.exclude": {
1819
}

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
# Changelog #
22
This package follows standard semver, `<major>.<minor>.<build>`. No breaking changes will be introduced to existing `<minor>` versions.
33

4+
## 2.4
5+
* Add support for [OpenAPI Spec 3.2](https://www.openapis.org/blog/2025/09/23/announcing-openapi-v3-2).
6+
47
## 2.3
58
* Schema types will now utilize the title property for displaying, rather than the type ID, when defined.
69
* Increase font sizes by 1px to set a more accessible default display.

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ This is an open source project managed by the [Authress Engineering team](https:
4545
```
4646

4747
## Features
48-
- OpenAPI 3.X
48+
- OpenAPI 3.2+
4949
- Built in automatic Internationalization (I18n)
5050
- Works with any framework
5151
- View resources, models, and directly make API calls

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@
118118
"sinon-chai": "^3.3.0",
119119
"style-loader": "^2.0.0",
120120
"terser-webpack-plugin": "^5.1.1",
121+
"toposort": "^2.0.2",
121122
"webpack": "^5.30.0",
122123
"webpack-bundle-analyzer": "^4.4.0",
123124
"webpack-cli": "^4.6.0",

src/styles/font-styles.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ export default css`
6060
h1,h2,h3,h4,h5,h5{
6161
margin-block-end: 0.2em;
6262
margin-block-start: 0.5em;
63+
padding-top: 0;
6364
}
6465
h3 {
6566
margin-top: 0;

src/templates/expanded-endpoint-template.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,14 @@ export function expandedEndpointBodyTemplate(path, tag) {
1414
const nonEmptyApiKeys = this.resolvedSpec.securitySchemes.filter((v) => (v.finalKeyValue && path.security && path.security.some((ps) => ps[v.apiKeyId]))) || [];
1515

1616
const codeSampleTabPanel = path.xCodeSamples ? codeSamplesTemplate.call(this, path.xCodeSamples) : '';
17+
18+
const tagSummary = tag?.summary ? html`<small style="font-weight: 400">- ${tag?.summary}</small>` : '';
1719
return html`
1820
${this.renderStyle === 'read' ? html`<div class='divider' part="operation-divider"></div>` : ''}
1921
<div class='expanded-endpoint-body observe-me ${path.method}' part="section-operation ${path.elementId}" id='${path.elementId}'>
2022
${(this.renderStyle === 'focused' && tag && tag.name !== 'General ⦂')
21-
? html`<div class="title tag-link" role="heading" aria-level="1" data-content-id="${tag.elementId}" @click="${(e) => this.scrollToEventTarget(e, false)}"> ${tag?.name} </div>`
23+
? html`<h1 style="display: inline; align-self: center" class="title tag-link" role="heading" aria-level="1" data-content-id="${tag.elementId}"
24+
@click="${(e) => this.scrollToEventTarget(e, false)}"> ${tag?.name} ${tagSummary}</h1>`
2225
: ''}
2326
<slot name="${tag.elementId}"></slot>
2427
@@ -91,9 +94,11 @@ export function expandedEndpointBodyTemplate(path, tag) {
9194
export function expandedTagTemplate(tagId, subsectionFullId) {
9295
const tag = (this.resolvedSpec.tags || []).find(t => t.elementId === tagId);
9396
const subsectionId = subsectionFullId.replace(`${tagId}--`, '');
97+
const tagSummary = tag.summary ? html`<h2 style="font-weight: 400">${tag.summary}</h2>` : '';
9498
return html`
9599
<section id="${tag.elementId}" part="section-tag" class="regular-font section-gap--read-mode observe-me" style="">
96-
<div class="title tag" part="label-tag-title" role="heading" aria-level="1">${tag.name}</div>
100+
<h1 class="title tag" part="label-tag-title" role="heading" aria-level="1">${tag.name}</h1>
101+
${tagSummary}
97102
<slot name="${tag.elementId}--subsection--${subsectionId}">
98103
<div class="regular-font-size">
99104
${

src/utils/spec-parser.js

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import OpenApiResolver from 'openapi-resolver/dist/openapi-resolver.browser.js';
33
import { marked } from 'marked';
44
import { invalidCharsRegEx } from './common-utils.js';
55
import cloneDeep from 'lodash.clonedeep';
6+
import toposort from 'toposort';
67

78
export default async function ProcessSpec(specUrlOrObject, serverUrl = '') {
89
const inputSpecIsAUrl = typeof specUrlOrObject === 'string' && specUrlOrObject.match(/^http/) || typeof specUrlOrObject === 'object' && typeof specUrlOrObject.href === 'string';
@@ -146,19 +147,27 @@ function getComponents(openApiSpec) {
146147

147148
function groupByTags(openApiSpec) {
148149
const supportedMethods = ['get', 'query', 'put', 'post', 'patch', 'delete', 'head', 'options']; // this is also used for ordering endpoints by methods
149-
const tags = openApiSpec.tags && Array.isArray(openApiSpec.tags)
150-
? openApiSpec.tags.map((t) => {
150+
const rawTags = openApiSpec.tags && Array.isArray(openApiSpec.tags) ? openApiSpec.tags : [];
151+
const unsortedTags = rawTags
152+
// Only support nav tags in grouping, because these tags will be used for navigation.
153+
.filter(t => !t.kind || t.kind === 'nav')
154+
.map((t) => {
151155
const name = typeof t === 'string' ? t : t.name;
152156
return {
153157
elementId: `tag--${name.replace(invalidCharsRegEx, '-')}`,
154158
name: name,
159+
summary: t.summary,
155160
description: t.description || '',
156161
headers: t.description ? getHeadersFromMarkdown(t.description) : [],
157162
paths: [],
158163
expanded: true
159164
};
160-
})
161-
: [];
165+
});
166+
167+
const tagMap = unsortedTags.reduce((acc, t) => ({ ...acc, [t.name]: t }), {});
168+
169+
const tagDependencies = rawTags.map(t => t.parent && [t.parent, t.name] || [t.name, 'null']);
170+
const tags = toposort(tagDependencies).map(tagName => tagMap[tagName]).filter(t => t);
162171

163172
const pathsAndWebhooks = openApiSpec.paths || {};
164173
if (openApiSpec.webhooks) {

yarn.lock

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7760,6 +7760,11 @@ [email protected]:
77607760
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35"
77617761
integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
77627762

7763+
toposort@^2.0.2:
7764+
version "2.0.2"
7765+
resolved "https://registry.yarnpkg.com/toposort/-/toposort-2.0.2.tgz#ae21768175d1559d48bef35420b2f4962f09c330"
7766+
integrity sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==
7767+
77637768
totalist@^3.0.0:
77647769
version "3.0.1"
77657770
resolved "https://registry.yarnpkg.com/totalist/-/totalist-3.0.1.tgz#ba3a3d600c915b1a97872348f79c127475f6acf8"

0 commit comments

Comments
 (0)