docusaurus-plugin-openapi-docs 4.7.0 → 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
|
@@ -10,7 +10,7 @@ import { LicenseObject } from "../openapi/types";
|
|
|
10
10
|
|
|
11
11
|
export function createLicense(license: LicenseObject) {
|
|
12
12
|
if (!license || !Object.keys(license).length) return "";
|
|
13
|
-
const { name, url } = license;
|
|
13
|
+
const { name, url, identifier } = license;
|
|
14
14
|
|
|
15
15
|
return create("div", {
|
|
16
16
|
style: {
|
|
@@ -29,6 +29,12 @@ export function createLicense(license: LicenseObject) {
|
|
|
29
29
|
children: name ?? url,
|
|
30
30
|
})
|
|
31
31
|
),
|
|
32
|
+
guard(identifier, () =>
|
|
33
|
+
create("a", {
|
|
34
|
+
href: `https://spdx.org/licenses/${identifier}.html`,
|
|
35
|
+
children: name ?? identifier,
|
|
36
|
+
})
|
|
37
|
+
),
|
|
32
38
|
],
|
|
33
39
|
});
|
|
34
40
|
}
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
import { createDescription } from "./createDescription";
|
|
18
18
|
import { createDetails } from "./createDetails";
|
|
19
19
|
import { createDetailsSummary } from "./createDetailsSummary";
|
|
20
|
-
import {
|
|
20
|
+
import { getSchemaName } from "./schema";
|
|
21
21
|
import { create, guard } from "./utils";
|
|
22
22
|
import { SchemaObject } from "../openapi/types";
|
|
23
23
|
|
|
@@ -32,7 +32,7 @@ export function mergeAllOf(allOf: SchemaObject) {
|
|
|
32
32
|
};
|
|
33
33
|
|
|
34
34
|
const mergedSchemas = merge(allOf, { onMergeError }) as SchemaObject;
|
|
35
|
-
return mergedSchemas;
|
|
35
|
+
return mergedSchemas ?? ({} as SchemaObject);
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
/**
|
|
@@ -140,7 +140,6 @@ function createProperties(schema: SchemaObject) {
|
|
|
140
140
|
name: "",
|
|
141
141
|
required: false,
|
|
142
142
|
schemaName: "object",
|
|
143
|
-
qualifierMessage: undefined,
|
|
144
143
|
schema: {},
|
|
145
144
|
});
|
|
146
145
|
}
|
|
@@ -169,7 +168,6 @@ function createAdditionalProperties(schema: SchemaObject) {
|
|
|
169
168
|
name: "property name*",
|
|
170
169
|
required: false,
|
|
171
170
|
schemaName: "any",
|
|
172
|
-
qualifierMessage: getQualifierMessage(schema),
|
|
173
171
|
schema: schema,
|
|
174
172
|
collapsible: false,
|
|
175
173
|
discriminator: false,
|
|
@@ -209,7 +207,6 @@ function createAdditionalProperties(schema: SchemaObject) {
|
|
|
209
207
|
name: "property name*",
|
|
210
208
|
required: false,
|
|
211
209
|
schemaName: schemaName,
|
|
212
|
-
qualifierMessage: getQualifierMessage(schema),
|
|
213
210
|
schema: additionalProperties,
|
|
214
211
|
collapsible: false,
|
|
215
212
|
discriminator: false,
|
|
@@ -399,12 +396,6 @@ function createDetailsNode(
|
|
|
399
396
|
children: createDescription(description),
|
|
400
397
|
})
|
|
401
398
|
),
|
|
402
|
-
guard(getQualifierMessage(schema), (message) =>
|
|
403
|
-
create("div", {
|
|
404
|
-
style: { marginTop: ".5rem", marginBottom: ".5rem" },
|
|
405
|
-
children: createDescription(message),
|
|
406
|
-
})
|
|
407
|
-
),
|
|
408
399
|
createNodes(schema, SCHEMA_TYPE),
|
|
409
400
|
],
|
|
410
401
|
}),
|
|
@@ -545,14 +536,6 @@ function createPropertyDiscriminator(
|
|
|
545
536
|
children: createDescription(description),
|
|
546
537
|
})
|
|
547
538
|
),
|
|
548
|
-
guard(getQualifierMessage(discriminator), (message) =>
|
|
549
|
-
create("div", {
|
|
550
|
-
style: {
|
|
551
|
-
paddingLeft: "1rem",
|
|
552
|
-
},
|
|
553
|
-
children: createDescription(message),
|
|
554
|
-
})
|
|
555
|
-
),
|
|
556
539
|
create("DiscriminatorTabs", {
|
|
557
540
|
className: "openapi-tabs__discriminator",
|
|
558
541
|
children: Object.keys(discriminator?.mapping!).map((key, index) => {
|
|
@@ -727,7 +710,6 @@ function createEdges({
|
|
|
727
710
|
name,
|
|
728
711
|
required: Array.isArray(required) ? required.includes(name) : required,
|
|
729
712
|
schemaName: mergedSchemaName,
|
|
730
|
-
qualifierMessage: getQualifierMessage(mergedSchemas),
|
|
731
713
|
schema: mergedSchemas,
|
|
732
714
|
});
|
|
733
715
|
}
|
|
@@ -738,7 +720,6 @@ function createEdges({
|
|
|
738
720
|
name,
|
|
739
721
|
required: Array.isArray(required) ? required.includes(name) : required,
|
|
740
722
|
schemaName: schemaName,
|
|
741
|
-
qualifierMessage: getQualifierMessage(schema),
|
|
742
723
|
schema: schema,
|
|
743
724
|
});
|
|
744
725
|
}
|
|
@@ -823,17 +804,7 @@ export function createNodes(
|
|
|
823
804
|
marginTop: ".5rem",
|
|
824
805
|
marginBottom: ".5rem",
|
|
825
806
|
},
|
|
826
|
-
children: [
|
|
827
|
-
createDescription(schema.type),
|
|
828
|
-
guard(getQualifierMessage(schema), (message) =>
|
|
829
|
-
create("div", {
|
|
830
|
-
style: {
|
|
831
|
-
paddingTop: "1rem",
|
|
832
|
-
},
|
|
833
|
-
children: createDescription(message),
|
|
834
|
-
})
|
|
835
|
-
),
|
|
836
|
-
],
|
|
807
|
+
children: [createDescription(schema.type)],
|
|
837
808
|
});
|
|
838
809
|
}
|
|
839
810
|
|
|
@@ -844,17 +815,7 @@ export function createNodes(
|
|
|
844
815
|
marginTop: ".5rem",
|
|
845
816
|
marginBottom: ".5rem",
|
|
846
817
|
},
|
|
847
|
-
children: [
|
|
848
|
-
createDescription(schema),
|
|
849
|
-
guard(getQualifierMessage(schema), (message) =>
|
|
850
|
-
create("div", {
|
|
851
|
-
style: {
|
|
852
|
-
paddingTop: "1rem",
|
|
853
|
-
},
|
|
854
|
-
children: createDescription(message),
|
|
855
|
-
})
|
|
856
|
-
),
|
|
857
|
-
],
|
|
818
|
+
children: [createDescription(schema)],
|
|
858
819
|
});
|
|
859
820
|
}
|
|
860
821
|
|
package/src/markdown/schema.ts
CHANGED
|
@@ -66,129 +66,3 @@ export function getSchemaName(
|
|
|
66
66
|
|
|
67
67
|
return prettyName(schema, circular) ?? "";
|
|
68
68
|
}
|
|
69
|
-
|
|
70
|
-
export function getQualifierMessage(schema?: SchemaObject): string | undefined {
|
|
71
|
-
// TODO:
|
|
72
|
-
// - uniqueItems
|
|
73
|
-
// - maxProperties
|
|
74
|
-
// - minProperties
|
|
75
|
-
// - multipleOf
|
|
76
|
-
if (!schema) {
|
|
77
|
-
return undefined;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
if (
|
|
81
|
-
schema.items &&
|
|
82
|
-
schema.minItems === undefined &&
|
|
83
|
-
schema.maxItems === undefined
|
|
84
|
-
) {
|
|
85
|
-
return getQualifierMessage(schema.items);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
let message = "**Possible values:** ";
|
|
89
|
-
|
|
90
|
-
let qualifierGroups = [];
|
|
91
|
-
|
|
92
|
-
if (schema.items && schema.items.enum) {
|
|
93
|
-
if (schema.items.enum) {
|
|
94
|
-
qualifierGroups.push(
|
|
95
|
-
`[${schema.items.enum.map((e) => `\`${e}\``).join(", ")}]`
|
|
96
|
-
);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if (schema.minLength || schema.maxLength) {
|
|
101
|
-
let lengthQualifier = "";
|
|
102
|
-
let minLength;
|
|
103
|
-
let maxLength;
|
|
104
|
-
if (schema.minLength && schema.minLength > 1) {
|
|
105
|
-
minLength = `\`>= ${schema.minLength} characters\``;
|
|
106
|
-
}
|
|
107
|
-
if (schema.minLength && schema.minLength === 1) {
|
|
108
|
-
minLength = `\`non-empty\``;
|
|
109
|
-
}
|
|
110
|
-
if (schema.maxLength) {
|
|
111
|
-
maxLength = `\`<= ${schema.maxLength} characters\``;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
if (minLength && !maxLength) {
|
|
115
|
-
lengthQualifier += minLength;
|
|
116
|
-
}
|
|
117
|
-
if (maxLength && !minLength) {
|
|
118
|
-
lengthQualifier += maxLength;
|
|
119
|
-
}
|
|
120
|
-
if (minLength && maxLength) {
|
|
121
|
-
lengthQualifier += `${minLength} and ${maxLength}`;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
qualifierGroups.push(lengthQualifier);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
if (
|
|
128
|
-
schema.minimum != null ||
|
|
129
|
-
schema.maximum != null ||
|
|
130
|
-
typeof schema.exclusiveMinimum === "number" ||
|
|
131
|
-
typeof schema.exclusiveMaximum === "number"
|
|
132
|
-
) {
|
|
133
|
-
let minmaxQualifier = "";
|
|
134
|
-
let minimum;
|
|
135
|
-
let maximum;
|
|
136
|
-
if (typeof schema.exclusiveMinimum === "number") {
|
|
137
|
-
minimum = `\`> ${schema.exclusiveMinimum}\``;
|
|
138
|
-
} else if (schema.minimum != null && !schema.exclusiveMinimum) {
|
|
139
|
-
minimum = `\`>= ${schema.minimum}\``;
|
|
140
|
-
} else if (schema.minimum != null && schema.exclusiveMinimum === true) {
|
|
141
|
-
minimum = `\`> ${schema.minimum}\``;
|
|
142
|
-
}
|
|
143
|
-
if (typeof schema.exclusiveMaximum === "number") {
|
|
144
|
-
maximum = `\`< ${schema.exclusiveMaximum}\``;
|
|
145
|
-
} else if (schema.maximum != null && !schema.exclusiveMaximum) {
|
|
146
|
-
maximum = `\`<= ${schema.maximum}\``;
|
|
147
|
-
} else if (schema.maximum != null && schema.exclusiveMaximum === true) {
|
|
148
|
-
maximum = `\`< ${schema.maximum}\``;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
if (minimum && !maximum) {
|
|
152
|
-
minmaxQualifier += minimum;
|
|
153
|
-
}
|
|
154
|
-
if (maximum && !minimum) {
|
|
155
|
-
minmaxQualifier += maximum;
|
|
156
|
-
}
|
|
157
|
-
if (minimum && maximum) {
|
|
158
|
-
minmaxQualifier += `${minimum} and ${maximum}`;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
qualifierGroups.push(minmaxQualifier);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
if (schema.pattern) {
|
|
165
|
-
qualifierGroups.push(
|
|
166
|
-
`Value must match regular expression \`${schema.pattern}\``
|
|
167
|
-
);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// Check if discriminator mapping
|
|
171
|
-
const discriminator = schema as any;
|
|
172
|
-
if (discriminator.mapping) {
|
|
173
|
-
const values = Object.keys(discriminator.mapping);
|
|
174
|
-
qualifierGroups.push(`[${values.map((e) => `\`${e}\``).join(", ")}]`);
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
if (schema.enum) {
|
|
178
|
-
qualifierGroups.push(`[${schema.enum.map((e) => `\`${e}\``).join(", ")}]`);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
if (schema.minItems) {
|
|
182
|
-
qualifierGroups.push(`\`>= ${schema.minItems}\``);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
if (schema.maxItems) {
|
|
186
|
-
qualifierGroups.push(`\`<= ${schema.maxItems}\``);
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
if (qualifierGroups.length === 0) {
|
|
190
|
-
return undefined;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
return message + qualifierGroups.join(", ");
|
|
194
|
-
}
|
package/src/markdown/utils.ts
CHANGED
|
@@ -129,7 +129,9 @@ export function create(
|
|
|
129
129
|
} else {
|
|
130
130
|
// Inline props as usual
|
|
131
131
|
for (const [key, value] of Object.entries(rest)) {
|
|
132
|
-
|
|
132
|
+
if (value !== undefined) {
|
|
133
|
+
propString += `\n ${key}={${JSON.stringify(value)}}`;
|
|
134
|
+
}
|
|
133
135
|
}
|
|
134
136
|
}
|
|
135
137
|
|
|
@@ -54,4 +54,36 @@ describe("sampleFromSchema", () => {
|
|
|
54
54
|
expect(result).toBe("dog");
|
|
55
55
|
});
|
|
56
56
|
});
|
|
57
|
+
|
|
58
|
+
describe("allOf with incompatible types", () => {
|
|
59
|
+
it("should return undefined when allOf contains incompatible types", () => {
|
|
60
|
+
const schema: SchemaObject = {
|
|
61
|
+
allOf: [{ type: "string" }, { type: "integer" }],
|
|
62
|
+
};
|
|
63
|
+
const context = { type: "request" as const };
|
|
64
|
+
|
|
65
|
+
const result = sampleFromSchema(schema, context);
|
|
66
|
+
|
|
67
|
+
expect(result).toBeUndefined();
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("should handle incompatible allOf types in a property", () => {
|
|
71
|
+
const schema: SchemaObject = {
|
|
72
|
+
type: "object",
|
|
73
|
+
properties: {
|
|
74
|
+
numero: {
|
|
75
|
+
allOf: [{ type: "string" }, { type: "integer" }],
|
|
76
|
+
},
|
|
77
|
+
name: {
|
|
78
|
+
type: "string",
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
const context = { type: "request" as const };
|
|
83
|
+
|
|
84
|
+
const result = sampleFromSchema(schema, context);
|
|
85
|
+
|
|
86
|
+
expect(result.name).toBe("string");
|
|
87
|
+
});
|
|
88
|
+
});
|
|
57
89
|
});
|
|
@@ -95,4 +95,180 @@ describe("openapi", () => {
|
|
|
95
95
|
expect(schemaItems[0].id).toBe("without-tags");
|
|
96
96
|
});
|
|
97
97
|
});
|
|
98
|
+
|
|
99
|
+
describe("path template and custom verb handling", () => {
|
|
100
|
+
it("binds postman requests for OpenAPI templates and path verbs", async () => {
|
|
101
|
+
const openapiData = {
|
|
102
|
+
openapi: "3.0.0",
|
|
103
|
+
info: {
|
|
104
|
+
title: "Path Template API",
|
|
105
|
+
version: "1.0.0",
|
|
106
|
+
},
|
|
107
|
+
paths: {
|
|
108
|
+
"/api/resource:customVerb": {
|
|
109
|
+
post: {
|
|
110
|
+
summary: "Custom verb endpoint",
|
|
111
|
+
operationId: "customVerbOperation",
|
|
112
|
+
responses: {
|
|
113
|
+
"200": {
|
|
114
|
+
description: "OK",
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
"/api/users/{id}": {
|
|
120
|
+
get: {
|
|
121
|
+
summary: "Get user by ID",
|
|
122
|
+
operationId: "getUserById",
|
|
123
|
+
parameters: [
|
|
124
|
+
{
|
|
125
|
+
name: "id",
|
|
126
|
+
in: "path",
|
|
127
|
+
required: true,
|
|
128
|
+
schema: {
|
|
129
|
+
type: "string",
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
],
|
|
133
|
+
responses: {
|
|
134
|
+
"200": {
|
|
135
|
+
description: "OK",
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
"/api/users/{userId}/posts/{postId}": {
|
|
141
|
+
get: {
|
|
142
|
+
summary: "Get user post",
|
|
143
|
+
operationId: "getUserPost",
|
|
144
|
+
parameters: [
|
|
145
|
+
{
|
|
146
|
+
name: "userId",
|
|
147
|
+
in: "path",
|
|
148
|
+
required: true,
|
|
149
|
+
schema: {
|
|
150
|
+
type: "string",
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
name: "postId",
|
|
155
|
+
in: "path",
|
|
156
|
+
required: true,
|
|
157
|
+
schema: {
|
|
158
|
+
type: "string",
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
],
|
|
162
|
+
responses: {
|
|
163
|
+
"200": {
|
|
164
|
+
description: "OK",
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
"/files/{name}.{ext}": {
|
|
170
|
+
get: {
|
|
171
|
+
summary: "Get file by name and extension",
|
|
172
|
+
operationId: "getFileByNameAndExt",
|
|
173
|
+
parameters: [
|
|
174
|
+
{
|
|
175
|
+
name: "name",
|
|
176
|
+
in: "path",
|
|
177
|
+
required: true,
|
|
178
|
+
schema: {
|
|
179
|
+
type: "string",
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
name: "ext",
|
|
184
|
+
in: "path",
|
|
185
|
+
required: true,
|
|
186
|
+
schema: {
|
|
187
|
+
type: "string",
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
],
|
|
191
|
+
responses: {
|
|
192
|
+
"200": {
|
|
193
|
+
description: "OK",
|
|
194
|
+
},
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
"/jobs/{id}:cancel": {
|
|
199
|
+
post: {
|
|
200
|
+
summary: "Cancel job",
|
|
201
|
+
operationId: "cancelJob",
|
|
202
|
+
parameters: [
|
|
203
|
+
{
|
|
204
|
+
name: "id",
|
|
205
|
+
in: "path",
|
|
206
|
+
required: true,
|
|
207
|
+
schema: {
|
|
208
|
+
type: "string",
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
],
|
|
212
|
+
responses: {
|
|
213
|
+
"200": {
|
|
214
|
+
description: "OK",
|
|
215
|
+
},
|
|
216
|
+
},
|
|
217
|
+
},
|
|
218
|
+
},
|
|
219
|
+
},
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
const options: APIOptions = {
|
|
223
|
+
specPath: "dummy",
|
|
224
|
+
outputDir: "build",
|
|
225
|
+
};
|
|
226
|
+
const sidebarOptions = {} as SidebarOptions;
|
|
227
|
+
const [items] = await processOpenapiFile(
|
|
228
|
+
openapiData as any,
|
|
229
|
+
options,
|
|
230
|
+
sidebarOptions
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
const apiItems = items.filter((item) => item.type === "api");
|
|
234
|
+
expect(apiItems).toHaveLength(5);
|
|
235
|
+
|
|
236
|
+
const customVerbItem = apiItems.find(
|
|
237
|
+
(item) => item.type === "api" && item.id === "custom-verb-operation"
|
|
238
|
+
) as any;
|
|
239
|
+
expect(customVerbItem.api.path).toBe("/api/resource:customVerb");
|
|
240
|
+
expect(customVerbItem.api.method).toBe("post");
|
|
241
|
+
expect(customVerbItem.api.postman).toBeDefined();
|
|
242
|
+
|
|
243
|
+
const standardItem = apiItems.find(
|
|
244
|
+
(item) => item.type === "api" && item.id === "get-user-by-id"
|
|
245
|
+
) as any;
|
|
246
|
+
expect(standardItem.api.path).toBe("/api/users/{id}");
|
|
247
|
+
expect(standardItem.api.method).toBe("get");
|
|
248
|
+
expect(standardItem.api.postman).toBeDefined();
|
|
249
|
+
|
|
250
|
+
const multiParamItem = apiItems.find(
|
|
251
|
+
(item) => item.type === "api" && item.id === "get-user-post"
|
|
252
|
+
) as any;
|
|
253
|
+
expect(multiParamItem.api.path).toBe(
|
|
254
|
+
"/api/users/{userId}/posts/{postId}"
|
|
255
|
+
);
|
|
256
|
+
expect(multiParamItem.api.method).toBe("get");
|
|
257
|
+
expect(multiParamItem.api.postman).toBeDefined();
|
|
258
|
+
|
|
259
|
+
const sameSegmentItem = apiItems.find(
|
|
260
|
+
(item) => item.type === "api" && item.id === "get-file-by-name-and-ext"
|
|
261
|
+
) as any;
|
|
262
|
+
expect(sameSegmentItem.api.path).toBe("/files/{name}.{ext}");
|
|
263
|
+
expect(sameSegmentItem.api.method).toBe("get");
|
|
264
|
+
expect(sameSegmentItem.api.postman).toBeDefined();
|
|
265
|
+
|
|
266
|
+
const templatedVerbItem = apiItems.find(
|
|
267
|
+
(item) => item.type === "api" && item.id === "cancel-job"
|
|
268
|
+
) as any;
|
|
269
|
+
expect(templatedVerbItem.api.path).toBe("/jobs/{id}:cancel");
|
|
270
|
+
expect(templatedVerbItem.api.method).toBe("post");
|
|
271
|
+
expect(templatedVerbItem.api.postman).toBeDefined();
|
|
272
|
+
});
|
|
273
|
+
});
|
|
98
274
|
});
|
package/src/openapi/openapi.ts
CHANGED
|
@@ -561,28 +561,44 @@ function createItems(
|
|
|
561
561
|
/**
|
|
562
562
|
* Attach Postman Request objects to the corresponding ApiItems.
|
|
563
563
|
*/
|
|
564
|
+
function pathTemplateToRegex(pathTemplate: string): RegExp {
|
|
565
|
+
const pathWithTemplateTokens = pathTemplate.replace(
|
|
566
|
+
/\{[^}]+\}/g,
|
|
567
|
+
"__OPENAPI_PATH_PARAM__"
|
|
568
|
+
);
|
|
569
|
+
const escapedPathTemplate = pathWithTemplateTokens.replace(
|
|
570
|
+
/[.*+?^${}()|[\]\\]/g,
|
|
571
|
+
"\\$&"
|
|
572
|
+
);
|
|
573
|
+
const templatePattern = escapedPathTemplate.replace(
|
|
574
|
+
/__OPENAPI_PATH_PARAM__/g,
|
|
575
|
+
"[^/]+"
|
|
576
|
+
);
|
|
577
|
+
return new RegExp(`^${templatePattern}$`);
|
|
578
|
+
}
|
|
579
|
+
|
|
564
580
|
function bindCollectionToApiItems(
|
|
565
581
|
items: ApiMetadata[],
|
|
566
582
|
postmanCollection: sdk.Collection
|
|
567
583
|
) {
|
|
584
|
+
const apiMatchers = items
|
|
585
|
+
.filter((item): item is ApiPageMetadata => item.type === "api")
|
|
586
|
+
.map((item) => ({
|
|
587
|
+
apiItem: item,
|
|
588
|
+
method: item.api.method.toLowerCase(),
|
|
589
|
+
pathMatcher: pathTemplateToRegex(item.api.path),
|
|
590
|
+
}));
|
|
591
|
+
|
|
568
592
|
postmanCollection.forEachItem((item: any) => {
|
|
569
593
|
const method = item.request.method.toLowerCase();
|
|
570
|
-
const
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
item.type === "info" ||
|
|
576
|
-
item.type === "tag" ||
|
|
577
|
-
item.type === "schema"
|
|
578
|
-
) {
|
|
579
|
-
return false;
|
|
580
|
-
}
|
|
581
|
-
return item.api.path === path && item.api.method === method;
|
|
582
|
-
});
|
|
594
|
+
const postmanPath = item.request.url.getPath({ unresolved: true });
|
|
595
|
+
const match = apiMatchers.find(
|
|
596
|
+
({ method: itemMethod, pathMatcher }) =>
|
|
597
|
+
itemMethod === method && pathMatcher.test(postmanPath)
|
|
598
|
+
);
|
|
583
599
|
|
|
584
|
-
if (
|
|
585
|
-
apiItem.api.postman = item.request;
|
|
600
|
+
if (match) {
|
|
601
|
+
match.apiItem.api.postman = item.request;
|
|
586
602
|
}
|
|
587
603
|
});
|
|
588
604
|
}
|
package/src/openapi/types.ts
CHANGED
|
@@ -6,9 +6,8 @@
|
|
|
6
6
|
* ========================================================================== */
|
|
7
7
|
|
|
8
8
|
import $RefParser from "@apidevtools/json-schema-ref-parser";
|
|
9
|
-
import { bundle,
|
|
9
|
+
import { bundle, createConfig } from "@redocly/openapi-core";
|
|
10
10
|
import type { Source, Document } from "@redocly/openapi-core";
|
|
11
|
-
import { ResolvedConfig } from "@redocly/openapi-core/lib/config";
|
|
12
11
|
import chalk from "chalk";
|
|
13
12
|
// @ts-ignore
|
|
14
13
|
import { convertObj } from "swagger2openapi";
|
|
@@ -116,7 +115,7 @@ async function resolveJsonRefs(specUrlOrObject: object | string) {
|
|
|
116
115
|
}
|
|
117
116
|
|
|
118
117
|
export async function loadAndResolveSpec(specUrlOrObject: object | string) {
|
|
119
|
-
const config =
|
|
118
|
+
const config = await createConfig({});
|
|
120
119
|
const bundleOpts = {
|
|
121
120
|
config,
|
|
122
121
|
base: process.cwd(),
|
|
@@ -137,10 +136,13 @@ export async function loadAndResolveSpec(specUrlOrObject: object | string) {
|
|
|
137
136
|
const {
|
|
138
137
|
bundle: { parsed },
|
|
139
138
|
} = await bundle(bundleOpts);
|
|
139
|
+
const parsedSpec = parsed as any;
|
|
140
140
|
|
|
141
141
|
//Pre-processing before resolving JSON refs
|
|
142
|
-
if (
|
|
143
|
-
for (let [component, type] of Object.entries(
|
|
142
|
+
if (parsedSpec.components) {
|
|
143
|
+
for (let [component, type] of Object.entries(
|
|
144
|
+
parsedSpec.components
|
|
145
|
+
) as any) {
|
|
144
146
|
if (component === "schemas") {
|
|
145
147
|
for (let [schemaKey, schemaValue] of Object.entries(type) as any) {
|
|
146
148
|
const title: string | undefined = schemaValue["title"];
|
|
@@ -152,7 +154,7 @@ export async function loadAndResolveSpec(specUrlOrObject: object | string) {
|
|
|
152
154
|
}
|
|
153
155
|
}
|
|
154
156
|
|
|
155
|
-
const resolved = await resolveJsonRefs(
|
|
157
|
+
const resolved = await resolveJsonRefs(parsedSpec);
|
|
156
158
|
|
|
157
159
|
// Force serialization and replace circular $ref pointers
|
|
158
160
|
// @ts-ignore
|