docusaurus-plugin-openapi-docs 4.7.1 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -8
- package/lib/index.js +4 -4
- package/lib/markdown/createLicense.js +5 -1
- package/lib/markdown/createSchema.js +3 -34
- package/lib/markdown/schema.d.ts +0 -1
- package/lib/markdown/schema.js +0 -105
- package/lib/markdown/utils.js +3 -1
- package/lib/openapi/createSchemaExample.test.js +26 -0
- package/lib/openapi/openapi.js +17 -13
- package/lib/openapi/openapi.test.js +152 -0
- package/lib/openapi/types.d.ts +1 -0
- package/lib/openapi/utils/loadAndResolveSpec.js +5 -4
- package/lib/openapi/utils/utils/openapi.d.ts +0 -2
- package/lib/openapi/utils/utils/openapi.js +0 -82
- package/lib/sidebars/index.js +24 -8
- package/lib/sidebars/index.test.js +68 -0
- package/package.json +13 -13
- package/src/index.ts +4 -4
- package/src/markdown/__snapshots__/createSchema.test.ts.snap +0 -100
- package/src/markdown/createLicense.ts +7 -1
- package/src/markdown/createSchema.ts +4 -43
- package/src/markdown/schema.ts +0 -126
- package/src/markdown/utils.ts +3 -1
- package/src/openapi/createSchemaExample.test.ts +32 -0
- package/src/openapi/openapi.test.ts +176 -0
- package/src/openapi/openapi.ts +31 -15
- package/src/openapi/types.ts +1 -0
- package/src/openapi/utils/loadAndResolveSpec.ts +8 -6
- package/src/openapi/utils/utils/openapi.ts +0 -110
- package/src/sidebars/index.test.ts +94 -0
- package/src/sidebars/index.ts +28 -9
- package/lib/markdown/schema.test.js +0 -181
- package/src/markdown/schema.test.ts +0 -208
- /package/lib/{markdown/schema.test.d.ts → sidebars/index.test.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -41,9 +41,10 @@ Key Features:
|
|
|
41
41
|
|
|
42
42
|
| Docusaurus OpenAPI Docs | Docusaurus |
|
|
43
43
|
| ----------------------- | --------------- |
|
|
44
|
-
|
|
|
44
|
+
| 5.x.x (current) | `3.10.0+` |
|
|
45
|
+
| 4.x.x (legacy) | `3.5.0 - 3.9.2` |
|
|
45
46
|
| 3.0.x (end-of-support) | `3.0.1 - 3.4.0` |
|
|
46
|
-
| 2.2.3 (
|
|
47
|
+
| 2.2.3 (end-of-support) | `2.4.1 - 2.4.3` |
|
|
47
48
|
| 1.7.3 (end-of-support) | `2.0.1 - 2.2.0` |
|
|
48
49
|
|
|
49
50
|
## Bootstrapping from Template (new Docusaurus site)
|
|
@@ -51,7 +52,7 @@ Key Features:
|
|
|
51
52
|
Run the following to bootstrap a Docusaurus v3 site (classic theme) with `docusaurus-openapi-docs`:
|
|
52
53
|
|
|
53
54
|
```bash
|
|
54
|
-
npx create-docusaurus@3.
|
|
55
|
+
npx create-docusaurus@3.10.0 my-website --package-manager yarn
|
|
55
56
|
```
|
|
56
57
|
|
|
57
58
|
> When prompted to select a template choose `Git repository`.
|
|
@@ -253,11 +254,12 @@ petstore: {
|
|
|
253
254
|
|
|
254
255
|
The `docusaurus-theme-openapi-docs` theme can be configured with the following options in `themeConfig.api`:
|
|
255
256
|
|
|
256
|
-
| Name
|
|
257
|
-
|
|
|
258
|
-
| `proxy`
|
|
259
|
-
| `authPersistance`
|
|
260
|
-
| `requestTimeout`
|
|
257
|
+
| Name | Type | Default | Description |
|
|
258
|
+
| -------------------- | -------- | --------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
|
|
259
|
+
| `proxy` | `string` | `null` | _Optional:_ Site-wide proxy URL to prepend to base URL when performing API requests. Can be overridden per-spec via plugin config. |
|
|
260
|
+
| `authPersistance` | `string` | `null` | _Optional:_ Determines how auth credentials are persisted. Options: `"localStorage"`, `"sessionStorage"`, or `false` to disable. |
|
|
261
|
+
| `requestTimeout` | `number` | `30000` | _Optional:_ Request timeout in milliseconds for API requests made from the browser. Defaults to 30 seconds. |
|
|
262
|
+
| `requestCredentials` | `string` | `"same-origin"` | _Optional:_ Controls cookie behavior for API requests. Options: `"omit"`, `"same-origin"`, or `"include"`. |
|
|
261
263
|
|
|
262
264
|
Example:
|
|
263
265
|
|
|
@@ -269,6 +271,7 @@ Example:
|
|
|
269
271
|
proxy: "https://cors.pan.dev", // Site-wide proxy (can be overridden per-spec in plugin config)
|
|
270
272
|
authPersistance: "localStorage",
|
|
271
273
|
requestTimeout: 60000, // 60 seconds
|
|
274
|
+
requestCredentials: "omit", // Prevent cookies from being sent with requests
|
|
272
275
|
},
|
|
273
276
|
},
|
|
274
277
|
}
|
package/lib/index.js
CHANGED
|
@@ -538,7 +538,7 @@ custom_edit_url: null
|
|
|
538
538
|
let targetDocsPluginId;
|
|
539
539
|
if (pluginId) {
|
|
540
540
|
try {
|
|
541
|
-
const pluginConfig = getPluginConfig(
|
|
541
|
+
const pluginConfig = getPluginConfig(pluginInstances, pluginId);
|
|
542
542
|
targetConfig = (_a = pluginConfig.config) !== null && _a !== void 0 ? _a : {};
|
|
543
543
|
targetDocsPluginId = pluginConfig.docsPluginId;
|
|
544
544
|
}
|
|
@@ -597,7 +597,7 @@ custom_edit_url: null
|
|
|
597
597
|
let targetDocsPluginId;
|
|
598
598
|
if (pluginId) {
|
|
599
599
|
try {
|
|
600
|
-
const pluginConfig = getPluginConfig(
|
|
600
|
+
const pluginConfig = getPluginConfig(pluginInstances, pluginId);
|
|
601
601
|
targetConfig = (_a = pluginConfig.config) !== null && _a !== void 0 ? _a : {};
|
|
602
602
|
targetDocsPluginId = pluginConfig.docsPluginId;
|
|
603
603
|
}
|
|
@@ -677,7 +677,7 @@ custom_edit_url: null
|
|
|
677
677
|
let targetConfig;
|
|
678
678
|
if (pluginId) {
|
|
679
679
|
try {
|
|
680
|
-
const pluginConfig = getPluginConfig(
|
|
680
|
+
const pluginConfig = getPluginConfig(pluginInstances, pluginId);
|
|
681
681
|
targetConfig = (_a = pluginConfig.config) !== null && _a !== void 0 ? _a : {};
|
|
682
682
|
}
|
|
683
683
|
catch {
|
|
@@ -728,7 +728,7 @@ custom_edit_url: null
|
|
|
728
728
|
let targetConfig;
|
|
729
729
|
if (pluginId) {
|
|
730
730
|
try {
|
|
731
|
-
const pluginConfig = getPluginConfig(
|
|
731
|
+
const pluginConfig = getPluginConfig(pluginInstances, pluginId);
|
|
732
732
|
targetConfig = (_a = pluginConfig.config) !== null && _a !== void 0 ? _a : {};
|
|
733
733
|
}
|
|
734
734
|
catch {
|
|
@@ -11,7 +11,7 @@ const utils_1 = require("./utils");
|
|
|
11
11
|
function createLicense(license) {
|
|
12
12
|
if (!license || !Object.keys(license).length)
|
|
13
13
|
return "";
|
|
14
|
-
const { name, url } = license;
|
|
14
|
+
const { name, url, identifier } = license;
|
|
15
15
|
return (0, utils_1.create)("div", {
|
|
16
16
|
style: {
|
|
17
17
|
marginBottom: "var(--ifm-paragraph-margin-bottom)",
|
|
@@ -27,6 +27,10 @@ function createLicense(license) {
|
|
|
27
27
|
href: url,
|
|
28
28
|
children: name !== null && name !== void 0 ? name : url,
|
|
29
29
|
})),
|
|
30
|
+
(0, utils_1.guard)(identifier, () => (0, utils_1.create)("a", {
|
|
31
|
+
href: `https://spdx.org/licenses/${identifier}.html`,
|
|
32
|
+
children: name !== null && name !== void 0 ? name : identifier,
|
|
33
|
+
})),
|
|
30
34
|
],
|
|
31
35
|
});
|
|
32
36
|
}
|
|
@@ -30,7 +30,7 @@ function mergeAllOf(allOf) {
|
|
|
30
30
|
console.warn(msg);
|
|
31
31
|
};
|
|
32
32
|
const mergedSchemas = (0, allof_merge_1.merge)(allOf, { onMergeError });
|
|
33
|
-
return mergedSchemas;
|
|
33
|
+
return mergedSchemas !== null && mergedSchemas !== void 0 ? mergedSchemas : {};
|
|
34
34
|
}
|
|
35
35
|
/**
|
|
36
36
|
* For handling nested anyOf/oneOf.
|
|
@@ -122,7 +122,6 @@ function createProperties(schema) {
|
|
|
122
122
|
name: "",
|
|
123
123
|
required: false,
|
|
124
124
|
schemaName: "object",
|
|
125
|
-
qualifierMessage: undefined,
|
|
126
125
|
schema: {},
|
|
127
126
|
});
|
|
128
127
|
}
|
|
@@ -151,7 +150,6 @@ function createAdditionalProperties(schema) {
|
|
|
151
150
|
name: "property name*",
|
|
152
151
|
required: false,
|
|
153
152
|
schemaName: "any",
|
|
154
|
-
qualifierMessage: (0, schema_1.getQualifierMessage)(schema),
|
|
155
153
|
schema: schema,
|
|
156
154
|
collapsible: false,
|
|
157
155
|
discriminator: false,
|
|
@@ -179,7 +177,6 @@ function createAdditionalProperties(schema) {
|
|
|
179
177
|
name: "property name*",
|
|
180
178
|
required: false,
|
|
181
179
|
schemaName: schemaName,
|
|
182
|
-
qualifierMessage: (0, schema_1.getQualifierMessage)(schema),
|
|
183
180
|
schema: additionalProperties,
|
|
184
181
|
collapsible: false,
|
|
185
182
|
discriminator: false,
|
|
@@ -336,10 +333,6 @@ function createDetailsNode(name, schemaName, schema, required, nullable) {
|
|
|
336
333
|
style: { marginTop: ".5rem", marginBottom: ".5rem" },
|
|
337
334
|
children: (0, createDescription_1.createDescription)(description),
|
|
338
335
|
})),
|
|
339
|
-
(0, utils_1.guard)((0, schema_1.getQualifierMessage)(schema), (message) => (0, utils_1.create)("div", {
|
|
340
|
-
style: { marginTop: ".5rem", marginBottom: ".5rem" },
|
|
341
|
-
children: (0, createDescription_1.createDescription)(message),
|
|
342
|
-
})),
|
|
343
336
|
createNodes(schema, SCHEMA_TYPE),
|
|
344
337
|
],
|
|
345
338
|
}),
|
|
@@ -465,12 +458,6 @@ function createPropertyDiscriminator(name, schemaName, schema, discriminator, re
|
|
|
465
458
|
},
|
|
466
459
|
children: (0, createDescription_1.createDescription)(description),
|
|
467
460
|
})),
|
|
468
|
-
(0, utils_1.guard)((0, schema_1.getQualifierMessage)(discriminator), (message) => (0, utils_1.create)("div", {
|
|
469
|
-
style: {
|
|
470
|
-
paddingLeft: "1rem",
|
|
471
|
-
},
|
|
472
|
-
children: (0, createDescription_1.createDescription)(message),
|
|
473
|
-
})),
|
|
474
461
|
(0, utils_1.create)("DiscriminatorTabs", {
|
|
475
462
|
className: "openapi-tabs__discriminator",
|
|
476
463
|
children: Object.keys(discriminator === null || discriminator === void 0 ? void 0 : discriminator.mapping).map((key, index) => {
|
|
@@ -554,7 +541,6 @@ function createEdges({ name, schema, required, discriminator, }) {
|
|
|
554
541
|
name,
|
|
555
542
|
required: Array.isArray(required) ? required.includes(name) : required,
|
|
556
543
|
schemaName: mergedSchemaName,
|
|
557
|
-
qualifierMessage: (0, schema_1.getQualifierMessage)(mergedSchemas),
|
|
558
544
|
schema: mergedSchemas,
|
|
559
545
|
});
|
|
560
546
|
}
|
|
@@ -564,7 +550,6 @@ function createEdges({ name, schema, required, discriminator, }) {
|
|
|
564
550
|
name,
|
|
565
551
|
required: Array.isArray(required) ? required.includes(name) : required,
|
|
566
552
|
schemaName: schemaName,
|
|
567
|
-
qualifierMessage: (0, schema_1.getQualifierMessage)(schema),
|
|
568
553
|
schema: schema,
|
|
569
554
|
});
|
|
570
555
|
}
|
|
@@ -633,15 +618,7 @@ function createNodes(schema, schemaType) {
|
|
|
633
618
|
marginTop: ".5rem",
|
|
634
619
|
marginBottom: ".5rem",
|
|
635
620
|
},
|
|
636
|
-
children: [
|
|
637
|
-
(0, createDescription_1.createDescription)(schema.type),
|
|
638
|
-
(0, utils_1.guard)((0, schema_1.getQualifierMessage)(schema), (message) => (0, utils_1.create)("div", {
|
|
639
|
-
style: {
|
|
640
|
-
paddingTop: "1rem",
|
|
641
|
-
},
|
|
642
|
-
children: (0, createDescription_1.createDescription)(message),
|
|
643
|
-
})),
|
|
644
|
-
],
|
|
621
|
+
children: [(0, createDescription_1.createDescription)(schema.type)],
|
|
645
622
|
});
|
|
646
623
|
}
|
|
647
624
|
// handle circular references
|
|
@@ -651,15 +628,7 @@ function createNodes(schema, schemaType) {
|
|
|
651
628
|
marginTop: ".5rem",
|
|
652
629
|
marginBottom: ".5rem",
|
|
653
630
|
},
|
|
654
|
-
children: [
|
|
655
|
-
(0, createDescription_1.createDescription)(schema),
|
|
656
|
-
(0, utils_1.guard)((0, schema_1.getQualifierMessage)(schema), (message) => (0, utils_1.create)("div", {
|
|
657
|
-
style: {
|
|
658
|
-
paddingTop: "1rem",
|
|
659
|
-
},
|
|
660
|
-
children: (0, createDescription_1.createDescription)(message),
|
|
661
|
-
})),
|
|
662
|
-
],
|
|
631
|
+
children: [(0, createDescription_1.createDescription)(schema)],
|
|
663
632
|
});
|
|
664
633
|
}
|
|
665
634
|
// Unknown node/schema type should return undefined
|
package/lib/markdown/schema.d.ts
CHANGED
package/lib/markdown/schema.js
CHANGED
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
* ========================================================================== */
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
9
|
exports.getSchemaName = getSchemaName;
|
|
10
|
-
exports.getQualifierMessage = getQualifierMessage;
|
|
11
10
|
function prettyName(schema, circular) {
|
|
12
11
|
var _a, _b, _c, _d, _e;
|
|
13
12
|
// Handle enum-only schemas (valid in JSON Schema)
|
|
@@ -56,107 +55,3 @@ function getSchemaName(schema, circular) {
|
|
|
56
55
|
}
|
|
57
56
|
return (_a = prettyName(schema, circular)) !== null && _a !== void 0 ? _a : "";
|
|
58
57
|
}
|
|
59
|
-
function getQualifierMessage(schema) {
|
|
60
|
-
// TODO:
|
|
61
|
-
// - uniqueItems
|
|
62
|
-
// - maxProperties
|
|
63
|
-
// - minProperties
|
|
64
|
-
// - multipleOf
|
|
65
|
-
if (!schema) {
|
|
66
|
-
return undefined;
|
|
67
|
-
}
|
|
68
|
-
if (schema.items &&
|
|
69
|
-
schema.minItems === undefined &&
|
|
70
|
-
schema.maxItems === undefined) {
|
|
71
|
-
return getQualifierMessage(schema.items);
|
|
72
|
-
}
|
|
73
|
-
let message = "**Possible values:** ";
|
|
74
|
-
let qualifierGroups = [];
|
|
75
|
-
if (schema.items && schema.items.enum) {
|
|
76
|
-
if (schema.items.enum) {
|
|
77
|
-
qualifierGroups.push(`[${schema.items.enum.map((e) => `\`${e}\``).join(", ")}]`);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
if (schema.minLength || schema.maxLength) {
|
|
81
|
-
let lengthQualifier = "";
|
|
82
|
-
let minLength;
|
|
83
|
-
let maxLength;
|
|
84
|
-
if (schema.minLength && schema.minLength > 1) {
|
|
85
|
-
minLength = `\`>= ${schema.minLength} characters\``;
|
|
86
|
-
}
|
|
87
|
-
if (schema.minLength && schema.minLength === 1) {
|
|
88
|
-
minLength = `\`non-empty\``;
|
|
89
|
-
}
|
|
90
|
-
if (schema.maxLength) {
|
|
91
|
-
maxLength = `\`<= ${schema.maxLength} characters\``;
|
|
92
|
-
}
|
|
93
|
-
if (minLength && !maxLength) {
|
|
94
|
-
lengthQualifier += minLength;
|
|
95
|
-
}
|
|
96
|
-
if (maxLength && !minLength) {
|
|
97
|
-
lengthQualifier += maxLength;
|
|
98
|
-
}
|
|
99
|
-
if (minLength && maxLength) {
|
|
100
|
-
lengthQualifier += `${minLength} and ${maxLength}`;
|
|
101
|
-
}
|
|
102
|
-
qualifierGroups.push(lengthQualifier);
|
|
103
|
-
}
|
|
104
|
-
if (schema.minimum != null ||
|
|
105
|
-
schema.maximum != null ||
|
|
106
|
-
typeof schema.exclusiveMinimum === "number" ||
|
|
107
|
-
typeof schema.exclusiveMaximum === "number") {
|
|
108
|
-
let minmaxQualifier = "";
|
|
109
|
-
let minimum;
|
|
110
|
-
let maximum;
|
|
111
|
-
if (typeof schema.exclusiveMinimum === "number") {
|
|
112
|
-
minimum = `\`> ${schema.exclusiveMinimum}\``;
|
|
113
|
-
}
|
|
114
|
-
else if (schema.minimum != null && !schema.exclusiveMinimum) {
|
|
115
|
-
minimum = `\`>= ${schema.minimum}\``;
|
|
116
|
-
}
|
|
117
|
-
else if (schema.minimum != null && schema.exclusiveMinimum === true) {
|
|
118
|
-
minimum = `\`> ${schema.minimum}\``;
|
|
119
|
-
}
|
|
120
|
-
if (typeof schema.exclusiveMaximum === "number") {
|
|
121
|
-
maximum = `\`< ${schema.exclusiveMaximum}\``;
|
|
122
|
-
}
|
|
123
|
-
else if (schema.maximum != null && !schema.exclusiveMaximum) {
|
|
124
|
-
maximum = `\`<= ${schema.maximum}\``;
|
|
125
|
-
}
|
|
126
|
-
else if (schema.maximum != null && schema.exclusiveMaximum === true) {
|
|
127
|
-
maximum = `\`< ${schema.maximum}\``;
|
|
128
|
-
}
|
|
129
|
-
if (minimum && !maximum) {
|
|
130
|
-
minmaxQualifier += minimum;
|
|
131
|
-
}
|
|
132
|
-
if (maximum && !minimum) {
|
|
133
|
-
minmaxQualifier += maximum;
|
|
134
|
-
}
|
|
135
|
-
if (minimum && maximum) {
|
|
136
|
-
minmaxQualifier += `${minimum} and ${maximum}`;
|
|
137
|
-
}
|
|
138
|
-
qualifierGroups.push(minmaxQualifier);
|
|
139
|
-
}
|
|
140
|
-
if (schema.pattern) {
|
|
141
|
-
qualifierGroups.push(`Value must match regular expression \`${schema.pattern}\``);
|
|
142
|
-
}
|
|
143
|
-
// Check if discriminator mapping
|
|
144
|
-
const discriminator = schema;
|
|
145
|
-
if (discriminator.mapping) {
|
|
146
|
-
const values = Object.keys(discriminator.mapping);
|
|
147
|
-
qualifierGroups.push(`[${values.map((e) => `\`${e}\``).join(", ")}]`);
|
|
148
|
-
}
|
|
149
|
-
if (schema.enum) {
|
|
150
|
-
qualifierGroups.push(`[${schema.enum.map((e) => `\`${e}\``).join(", ")}]`);
|
|
151
|
-
}
|
|
152
|
-
if (schema.minItems) {
|
|
153
|
-
qualifierGroups.push(`\`>= ${schema.minItems}\``);
|
|
154
|
-
}
|
|
155
|
-
if (schema.maxItems) {
|
|
156
|
-
qualifierGroups.push(`\`<= ${schema.maxItems}\``);
|
|
157
|
-
}
|
|
158
|
-
if (qualifierGroups.length === 0) {
|
|
159
|
-
return undefined;
|
|
160
|
-
}
|
|
161
|
-
return message + qualifierGroups.join(", ");
|
|
162
|
-
}
|
package/lib/markdown/utils.js
CHANGED
|
@@ -81,7 +81,9 @@ function create(tag, props, options = {}) {
|
|
|
81
81
|
else {
|
|
82
82
|
// Inline props as usual
|
|
83
83
|
for (const [key, value] of Object.entries(rest)) {
|
|
84
|
-
|
|
84
|
+
if (value !== undefined) {
|
|
85
|
+
propString += `\n ${key}={${JSON.stringify(value)}}`;
|
|
86
|
+
}
|
|
85
87
|
}
|
|
86
88
|
}
|
|
87
89
|
let indentedChildren = render(children).replace(/^/gm, " ");
|
|
@@ -45,4 +45,30 @@ describe("sampleFromSchema", () => {
|
|
|
45
45
|
expect(result).toBe("dog");
|
|
46
46
|
});
|
|
47
47
|
});
|
|
48
|
+
describe("allOf with incompatible types", () => {
|
|
49
|
+
it("should return undefined when allOf contains incompatible types", () => {
|
|
50
|
+
const schema = {
|
|
51
|
+
allOf: [{ type: "string" }, { type: "integer" }],
|
|
52
|
+
};
|
|
53
|
+
const context = { type: "request" };
|
|
54
|
+
const result = (0, createSchemaExample_1.sampleFromSchema)(schema, context);
|
|
55
|
+
expect(result).toBeUndefined();
|
|
56
|
+
});
|
|
57
|
+
it("should handle incompatible allOf types in a property", () => {
|
|
58
|
+
const schema = {
|
|
59
|
+
type: "object",
|
|
60
|
+
properties: {
|
|
61
|
+
numero: {
|
|
62
|
+
allOf: [{ type: "string" }, { type: "integer" }],
|
|
63
|
+
},
|
|
64
|
+
name: {
|
|
65
|
+
type: "string",
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
const context = { type: "request" };
|
|
70
|
+
const result = (0, createSchemaExample_1.sampleFromSchema)(schema, context);
|
|
71
|
+
expect(result.name).toBe("string");
|
|
72
|
+
});
|
|
73
|
+
});
|
|
48
74
|
});
|
package/lib/openapi/openapi.js
CHANGED
|
@@ -481,22 +481,26 @@ function createItems(openapiData, options, sidebarOptions) {
|
|
|
481
481
|
/**
|
|
482
482
|
* Attach Postman Request objects to the corresponding ApiItems.
|
|
483
483
|
*/
|
|
484
|
+
function pathTemplateToRegex(pathTemplate) {
|
|
485
|
+
const pathWithTemplateTokens = pathTemplate.replace(/\{[^}]+\}/g, "__OPENAPI_PATH_PARAM__");
|
|
486
|
+
const escapedPathTemplate = pathWithTemplateTokens.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
487
|
+
const templatePattern = escapedPathTemplate.replace(/__OPENAPI_PATH_PARAM__/g, "[^/]+");
|
|
488
|
+
return new RegExp(`^${templatePattern}$`);
|
|
489
|
+
}
|
|
484
490
|
function bindCollectionToApiItems(items, postmanCollection) {
|
|
491
|
+
const apiMatchers = items
|
|
492
|
+
.filter((item) => item.type === "api")
|
|
493
|
+
.map((item) => ({
|
|
494
|
+
apiItem: item,
|
|
495
|
+
method: item.api.method.toLowerCase(),
|
|
496
|
+
pathMatcher: pathTemplateToRegex(item.api.path),
|
|
497
|
+
}));
|
|
485
498
|
postmanCollection.forEachItem((item) => {
|
|
486
499
|
const method = item.request.method.toLowerCase();
|
|
487
|
-
const
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
if (item.type === "info" ||
|
|
492
|
-
item.type === "tag" ||
|
|
493
|
-
item.type === "schema") {
|
|
494
|
-
return false;
|
|
495
|
-
}
|
|
496
|
-
return item.api.path === path && item.api.method === method;
|
|
497
|
-
});
|
|
498
|
-
if ((apiItem === null || apiItem === void 0 ? void 0 : apiItem.type) === "api") {
|
|
499
|
-
apiItem.api.postman = item.request;
|
|
500
|
+
const postmanPath = item.request.url.getPath({ unresolved: true });
|
|
501
|
+
const match = apiMatchers.find(({ method: itemMethod, pathMatcher }) => itemMethod === method && pathMatcher.test(postmanPath));
|
|
502
|
+
if (match) {
|
|
503
|
+
match.apiItem.api.postman = item.request;
|
|
500
504
|
}
|
|
501
505
|
});
|
|
502
506
|
}
|
|
@@ -78,4 +78,156 @@ describe("openapi", () => {
|
|
|
78
78
|
expect(schemaItems[0].id).toBe("without-tags");
|
|
79
79
|
});
|
|
80
80
|
});
|
|
81
|
+
describe("path template and custom verb handling", () => {
|
|
82
|
+
it("binds postman requests for OpenAPI templates and path verbs", async () => {
|
|
83
|
+
const openapiData = {
|
|
84
|
+
openapi: "3.0.0",
|
|
85
|
+
info: {
|
|
86
|
+
title: "Path Template API",
|
|
87
|
+
version: "1.0.0",
|
|
88
|
+
},
|
|
89
|
+
paths: {
|
|
90
|
+
"/api/resource:customVerb": {
|
|
91
|
+
post: {
|
|
92
|
+
summary: "Custom verb endpoint",
|
|
93
|
+
operationId: "customVerbOperation",
|
|
94
|
+
responses: {
|
|
95
|
+
"200": {
|
|
96
|
+
description: "OK",
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
"/api/users/{id}": {
|
|
102
|
+
get: {
|
|
103
|
+
summary: "Get user by ID",
|
|
104
|
+
operationId: "getUserById",
|
|
105
|
+
parameters: [
|
|
106
|
+
{
|
|
107
|
+
name: "id",
|
|
108
|
+
in: "path",
|
|
109
|
+
required: true,
|
|
110
|
+
schema: {
|
|
111
|
+
type: "string",
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
],
|
|
115
|
+
responses: {
|
|
116
|
+
"200": {
|
|
117
|
+
description: "OK",
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
"/api/users/{userId}/posts/{postId}": {
|
|
123
|
+
get: {
|
|
124
|
+
summary: "Get user post",
|
|
125
|
+
operationId: "getUserPost",
|
|
126
|
+
parameters: [
|
|
127
|
+
{
|
|
128
|
+
name: "userId",
|
|
129
|
+
in: "path",
|
|
130
|
+
required: true,
|
|
131
|
+
schema: {
|
|
132
|
+
type: "string",
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
name: "postId",
|
|
137
|
+
in: "path",
|
|
138
|
+
required: true,
|
|
139
|
+
schema: {
|
|
140
|
+
type: "string",
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
],
|
|
144
|
+
responses: {
|
|
145
|
+
"200": {
|
|
146
|
+
description: "OK",
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
"/files/{name}.{ext}": {
|
|
152
|
+
get: {
|
|
153
|
+
summary: "Get file by name and extension",
|
|
154
|
+
operationId: "getFileByNameAndExt",
|
|
155
|
+
parameters: [
|
|
156
|
+
{
|
|
157
|
+
name: "name",
|
|
158
|
+
in: "path",
|
|
159
|
+
required: true,
|
|
160
|
+
schema: {
|
|
161
|
+
type: "string",
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
name: "ext",
|
|
166
|
+
in: "path",
|
|
167
|
+
required: true,
|
|
168
|
+
schema: {
|
|
169
|
+
type: "string",
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
],
|
|
173
|
+
responses: {
|
|
174
|
+
"200": {
|
|
175
|
+
description: "OK",
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
"/jobs/{id}:cancel": {
|
|
181
|
+
post: {
|
|
182
|
+
summary: "Cancel job",
|
|
183
|
+
operationId: "cancelJob",
|
|
184
|
+
parameters: [
|
|
185
|
+
{
|
|
186
|
+
name: "id",
|
|
187
|
+
in: "path",
|
|
188
|
+
required: true,
|
|
189
|
+
schema: {
|
|
190
|
+
type: "string",
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
],
|
|
194
|
+
responses: {
|
|
195
|
+
"200": {
|
|
196
|
+
description: "OK",
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
};
|
|
203
|
+
const options = {
|
|
204
|
+
specPath: "dummy",
|
|
205
|
+
outputDir: "build",
|
|
206
|
+
};
|
|
207
|
+
const sidebarOptions = {};
|
|
208
|
+
const [items] = await (0, openapi_1.processOpenapiFile)(openapiData, options, sidebarOptions);
|
|
209
|
+
const apiItems = items.filter((item) => item.type === "api");
|
|
210
|
+
expect(apiItems).toHaveLength(5);
|
|
211
|
+
const customVerbItem = apiItems.find((item) => item.type === "api" && item.id === "custom-verb-operation");
|
|
212
|
+
expect(customVerbItem.api.path).toBe("/api/resource:customVerb");
|
|
213
|
+
expect(customVerbItem.api.method).toBe("post");
|
|
214
|
+
expect(customVerbItem.api.postman).toBeDefined();
|
|
215
|
+
const standardItem = apiItems.find((item) => item.type === "api" && item.id === "get-user-by-id");
|
|
216
|
+
expect(standardItem.api.path).toBe("/api/users/{id}");
|
|
217
|
+
expect(standardItem.api.method).toBe("get");
|
|
218
|
+
expect(standardItem.api.postman).toBeDefined();
|
|
219
|
+
const multiParamItem = apiItems.find((item) => item.type === "api" && item.id === "get-user-post");
|
|
220
|
+
expect(multiParamItem.api.path).toBe("/api/users/{userId}/posts/{postId}");
|
|
221
|
+
expect(multiParamItem.api.method).toBe("get");
|
|
222
|
+
expect(multiParamItem.api.postman).toBeDefined();
|
|
223
|
+
const sameSegmentItem = apiItems.find((item) => item.type === "api" && item.id === "get-file-by-name-and-ext");
|
|
224
|
+
expect(sameSegmentItem.api.path).toBe("/files/{name}.{ext}");
|
|
225
|
+
expect(sameSegmentItem.api.method).toBe("get");
|
|
226
|
+
expect(sameSegmentItem.api.postman).toBeDefined();
|
|
227
|
+
const templatedVerbItem = apiItems.find((item) => item.type === "api" && item.id === "cancel-job");
|
|
228
|
+
expect(templatedVerbItem.api.path).toBe("/jobs/{id}:cancel");
|
|
229
|
+
expect(templatedVerbItem.api.method).toBe("post");
|
|
230
|
+
expect(templatedVerbItem.api.postman).toBeDefined();
|
|
231
|
+
});
|
|
232
|
+
});
|
|
81
233
|
});
|
package/lib/openapi/types.d.ts
CHANGED
|
@@ -104,7 +104,7 @@ async function resolveJsonRefs(specUrlOrObject) {
|
|
|
104
104
|
}
|
|
105
105
|
}
|
|
106
106
|
async function loadAndResolveSpec(specUrlOrObject) {
|
|
107
|
-
const config =
|
|
107
|
+
const config = await (0, openapi_core_1.createConfig)({});
|
|
108
108
|
const bundleOpts = {
|
|
109
109
|
config,
|
|
110
110
|
base: process.cwd(),
|
|
@@ -121,9 +121,10 @@ async function loadAndResolveSpec(specUrlOrObject) {
|
|
|
121
121
|
// Force dereference ?
|
|
122
122
|
// bundleOpts["dereference"] = true;
|
|
123
123
|
const { bundle: { parsed }, } = await (0, openapi_core_1.bundle)(bundleOpts);
|
|
124
|
+
const parsedSpec = parsed;
|
|
124
125
|
//Pre-processing before resolving JSON refs
|
|
125
|
-
if (
|
|
126
|
-
for (let [component, type] of Object.entries(
|
|
126
|
+
if (parsedSpec.components) {
|
|
127
|
+
for (let [component, type] of Object.entries(parsedSpec.components)) {
|
|
127
128
|
if (component === "schemas") {
|
|
128
129
|
for (let [schemaKey, schemaValue] of Object.entries(type)) {
|
|
129
130
|
const title = schemaValue["title"];
|
|
@@ -134,7 +135,7 @@ async function loadAndResolveSpec(specUrlOrObject) {
|
|
|
134
135
|
}
|
|
135
136
|
}
|
|
136
137
|
}
|
|
137
|
-
const resolved = await resolveJsonRefs(
|
|
138
|
+
const resolved = await resolveJsonRefs(parsedSpec);
|
|
138
139
|
// Force serialization and replace circular $ref pointers
|
|
139
140
|
// @ts-ignore
|
|
140
141
|
const serialized = JSON.stringify(resolved, serializer());
|
|
@@ -19,8 +19,6 @@ export declare function getSerializedValue(field: any, example: any): any;
|
|
|
19
19
|
export declare function langFromMime(contentType: string): string;
|
|
20
20
|
export declare function isNamedDefinition(pointer?: string): boolean;
|
|
21
21
|
export declare function getDefinitionName(pointer?: string): string | undefined;
|
|
22
|
-
export declare function humanizeNumberRange(schema: OpenAPISchema): string | undefined;
|
|
23
|
-
export declare function humanizeConstraints(schema: OpenAPISchema): string[];
|
|
24
22
|
export declare function sortByRequired(fields: any[], order?: string[]): any[];
|
|
25
23
|
export declare function sortByField(fields: any[], param: "name" | "description" | "kind"): any[];
|
|
26
24
|
export declare function mergeParams(parser: OpenAPIParser, pathParams?: Array<Referenced<OpenAPIParameter>>, operationParams?: Array<Referenced<OpenAPIParameter>>): Array<Referenced<OpenAPIParameter>>;
|