@stoplight/elements 7.16.6 → 8.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/components/API/APIWithSidebarLayout.d.ts +9 -1
- package/components/API/utils.d.ts +7 -6
- package/index.esm.js +127 -21
- package/index.js +126 -20
- package/index.mjs +127 -21
- package/package.json +4 -4
- package/utils/oas/types.d.ts +5 -2
- package/web-components.min.js +1 -1
package/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isHttpOperation, isHttpService, HttpMethodColors, DeprecatedBadge, ParsedDocs, TryItWithRequestSamples, Docs, Logo, TableOfContents, PoweredByLink,
|
|
1
|
+
import { isHttpOperation, isHttpWebhookOperation, isHttpService, HttpMethodColors, DeprecatedBadge, ParsedDocs, TryItWithRequestSamples, Docs, SidebarLayout, Logo, TableOfContents, PoweredByLink, slugify, withRouter, withStyles, withPersistenceBoundary, withMosaicProvider, withQueryClientProvider, useParsedValue, useBundleRefsIntoDocument, NonIdealState, InlineRefResolverProvider } from '@stoplight/elements-core';
|
|
2
2
|
import { Box, Flex, Icon, Tabs, TabList, Tab, TabPanels, TabPanel, Heading } from '@stoplight/mosaic';
|
|
3
3
|
import { NodeType } from '@stoplight/types';
|
|
4
4
|
import cn from 'classnames';
|
|
@@ -9,6 +9,7 @@ import { useQuery } from 'react-query';
|
|
|
9
9
|
import { useLocation, Redirect, Link } from 'react-router-dom';
|
|
10
10
|
import { safeStringify } from '@stoplight/yaml';
|
|
11
11
|
import saver from 'file-saver';
|
|
12
|
+
import { OPERATION_CONFIG, WEBHOOK_CONFIG } from '@stoplight/http-spec/oas';
|
|
12
13
|
import { transformOas2Service, transformOas2Operation } from '@stoplight/http-spec/oas2';
|
|
13
14
|
import { transformOas3Service, transformOas3Operation } from '@stoplight/http-spec/oas3';
|
|
14
15
|
import { encodePointerFragment, pointerToPath } from '@stoplight/json';
|
|
@@ -16,13 +17,12 @@ import get from 'lodash/get.js';
|
|
|
16
17
|
import isObject from 'lodash/isObject.js';
|
|
17
18
|
import last from 'lodash/last.js';
|
|
18
19
|
|
|
19
|
-
|
|
20
|
+
function computeTagGroups(serviceNode, nodeType) {
|
|
20
21
|
const groupsByTagId = {};
|
|
21
22
|
const ungrouped = [];
|
|
22
23
|
const lowerCaseServiceTags = serviceNode.tags.map(tn => tn.toLowerCase());
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
continue;
|
|
24
|
+
const groupableNodes = serviceNode.children.filter(n => n.type === nodeType);
|
|
25
|
+
for (const node of groupableNodes) {
|
|
26
26
|
const tagName = node.tags[0];
|
|
27
27
|
if (tagName) {
|
|
28
28
|
const tagId = tagName.toLowerCase();
|
|
@@ -58,7 +58,7 @@ const computeTagGroups = (serviceNode) => {
|
|
|
58
58
|
})
|
|
59
59
|
.map(([, tagGroup]) => tagGroup);
|
|
60
60
|
return { groups: orderedTagGroups, ungrouped };
|
|
61
|
-
}
|
|
61
|
+
}
|
|
62
62
|
const defaultComputerAPITreeConfig = {
|
|
63
63
|
hideSchemas: false,
|
|
64
64
|
hideInternal: false,
|
|
@@ -73,12 +73,52 @@ const computeAPITree = (serviceNode, config = {}) => {
|
|
|
73
73
|
type: 'overview',
|
|
74
74
|
meta: '',
|
|
75
75
|
});
|
|
76
|
-
const
|
|
77
|
-
if (
|
|
76
|
+
const hasOperationNodes = serviceNode.children.some(node => node.type === NodeType.HttpOperation);
|
|
77
|
+
if (hasOperationNodes) {
|
|
78
78
|
tree.push({
|
|
79
79
|
title: 'Endpoints',
|
|
80
80
|
});
|
|
81
|
-
const { groups, ungrouped } = computeTagGroups(serviceNode);
|
|
81
|
+
const { groups, ungrouped } = computeTagGroups(serviceNode, NodeType.HttpOperation);
|
|
82
|
+
ungrouped.forEach(operationNode => {
|
|
83
|
+
if (mergedConfig.hideInternal && operationNode.data.internal) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
tree.push({
|
|
87
|
+
id: operationNode.uri,
|
|
88
|
+
slug: operationNode.uri,
|
|
89
|
+
title: operationNode.name,
|
|
90
|
+
type: operationNode.type,
|
|
91
|
+
meta: operationNode.data.method,
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
groups.forEach(group => {
|
|
95
|
+
const items = group.items.flatMap(operationNode => {
|
|
96
|
+
if (mergedConfig.hideInternal && operationNode.data.internal) {
|
|
97
|
+
return [];
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
id: operationNode.uri,
|
|
101
|
+
slug: operationNode.uri,
|
|
102
|
+
title: operationNode.name,
|
|
103
|
+
type: operationNode.type,
|
|
104
|
+
meta: operationNode.data.method,
|
|
105
|
+
};
|
|
106
|
+
});
|
|
107
|
+
if (items.length > 0) {
|
|
108
|
+
tree.push({
|
|
109
|
+
title: group.title,
|
|
110
|
+
items,
|
|
111
|
+
itemsType: 'http_operation',
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
const hasWebhookNodes = serviceNode.children.some(node => node.type === NodeType.HttpWebhook);
|
|
117
|
+
if (hasWebhookNodes) {
|
|
118
|
+
tree.push({
|
|
119
|
+
title: 'Webhooks',
|
|
120
|
+
});
|
|
121
|
+
const { groups, ungrouped } = computeTagGroups(serviceNode, NodeType.HttpWebhook);
|
|
82
122
|
ungrouped.forEach(operationNode => {
|
|
83
123
|
if (mergedConfig.hideInternal && operationNode.data.internal) {
|
|
84
124
|
return;
|
|
@@ -108,13 +148,14 @@ const computeAPITree = (serviceNode, config = {}) => {
|
|
|
108
148
|
tree.push({
|
|
109
149
|
title: group.title,
|
|
110
150
|
items,
|
|
151
|
+
itemsType: 'http_webhook',
|
|
111
152
|
});
|
|
112
153
|
}
|
|
113
154
|
});
|
|
114
155
|
}
|
|
115
156
|
let schemaNodes = serviceNode.children.filter(node => node.type === NodeType.Model);
|
|
116
157
|
if (mergedConfig.hideInternal) {
|
|
117
|
-
schemaNodes = schemaNodes.filter(
|
|
158
|
+
schemaNodes = schemaNodes.filter(n => !isInternal(n));
|
|
118
159
|
}
|
|
119
160
|
if (!mergedConfig.hideSchemas && schemaNodes.length) {
|
|
120
161
|
tree.push({
|
|
@@ -148,7 +189,7 @@ const findFirstNodeSlug = (tree) => {
|
|
|
148
189
|
};
|
|
149
190
|
const isInternal = (node) => {
|
|
150
191
|
const data = node.data;
|
|
151
|
-
if (isHttpOperation(data)) {
|
|
192
|
+
if (isHttpOperation(data) || isHttpWebhookOperation(data)) {
|
|
152
193
|
return !!data.internal;
|
|
153
194
|
}
|
|
154
195
|
if (isHttpService(data)) {
|
|
@@ -158,7 +199,12 @@ const isInternal = (node) => {
|
|
|
158
199
|
};
|
|
159
200
|
|
|
160
201
|
const itemMatchesHash = (hash, item) => {
|
|
161
|
-
|
|
202
|
+
if (item.type === NodeType.HttpOperation) {
|
|
203
|
+
return hash.substr(1) === `${item.data.path}-${item.data.method}`;
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
return hash.substr(1) === `${item.data.name}-${item.data.method}`;
|
|
207
|
+
}
|
|
162
208
|
};
|
|
163
209
|
const TryItContext = React.createContext({
|
|
164
210
|
hideTryIt: false,
|
|
@@ -176,14 +222,19 @@ const LocationContext = React.createContext({
|
|
|
176
222
|
});
|
|
177
223
|
LocationContext.displayName = 'LocationContext';
|
|
178
224
|
const APIWithStackedLayout = ({ serviceNode, hideTryIt, hideExport, exportProps, tryItCredentialsPolicy, tryItCorsProxy, showPoweredByLink = true, location, }) => {
|
|
179
|
-
const { groups } = computeTagGroups(serviceNode);
|
|
225
|
+
const { groups: operationGroups } = computeTagGroups(serviceNode, NodeType.HttpOperation);
|
|
226
|
+
const { groups: webhookGroups } = computeTagGroups(serviceNode, NodeType.HttpWebhook);
|
|
180
227
|
return (React.createElement(LocationContext.Provider, { value: { location } },
|
|
181
228
|
React.createElement(TryItContext.Provider, { value: { hideTryIt, tryItCredentialsPolicy, corsProxy: tryItCorsProxy } },
|
|
182
229
|
React.createElement(Flex, { w: "full", flexDirection: "col", m: "auto", className: "sl-max-w-4xl" },
|
|
183
230
|
React.createElement(Box, { w: "full", borderB: true },
|
|
184
231
|
React.createElement(Docs, { className: "sl-mx-auto", nodeData: serviceNode.data, nodeTitle: serviceNode.name, nodeType: NodeType.HttpService, location: location, layoutOptions: { showPoweredByLink, hideExport }, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy })),
|
|
185
|
-
|
|
232
|
+
operationGroups.length > 0 && webhookGroups.length > 0 ? React.createElement(Heading, { size: 2 }, "Endpoints") : null,
|
|
233
|
+
operationGroups.map(group => (React.createElement(Group, { key: group.title, group: group }))),
|
|
234
|
+
webhookGroups.length > 0 ? React.createElement(Heading, { size: 2 }, "Webhooks") : null,
|
|
235
|
+
webhookGroups.map(group => (React.createElement(Group, { key: group.title, group: group })))))));
|
|
186
236
|
};
|
|
237
|
+
APIWithStackedLayout.displayName = 'APIWithStackedLayout';
|
|
187
238
|
const Group = React.memo(({ group }) => {
|
|
188
239
|
const [isExpanded, setIsExpanded] = React.useState(false);
|
|
189
240
|
const scrollRef = React.useRef(null);
|
|
@@ -210,6 +261,7 @@ const Group = React.memo(({ group }) => {
|
|
|
210
261
|
return React.createElement(Item, { key: item.uri, item: item });
|
|
211
262
|
}))));
|
|
212
263
|
});
|
|
264
|
+
Group.displayName = 'Group';
|
|
213
265
|
const Item = React.memo(({ item }) => {
|
|
214
266
|
const { location } = React.useContext(LocationContext);
|
|
215
267
|
const { hash } = location;
|
|
@@ -231,7 +283,7 @@ const Item = React.memo(({ item }) => {
|
|
|
231
283
|
return (React.createElement(Box, { ref: scrollRef, w: "full", my: 2, border: true, borderColor: { default: isExpanded ? 'light' : 'transparent', hover: 'light' }, bg: { default: isExpanded ? 'code' : 'transparent', hover: 'code' } },
|
|
232
284
|
React.createElement(Flex, { mx: "auto", alignItems: "center", cursor: "pointer", fontSize: "lg", p: 2, onClick: onClick, color: "current" },
|
|
233
285
|
React.createElement(Box, { w: 24, textTransform: "uppercase", textAlign: "center", fontWeight: "semibold", border: true, rounded: true, px: 2, bg: "canvas", className: cn(`sl-mr-5 sl-text-base`, `sl-text-${color}`, `sl-border-${color}`) }, item.data.method || 'UNKNOWN'),
|
|
234
|
-
React.createElement(Box, { flex: 1, fontWeight: "medium", wordBreak: "all" }, item.data.path),
|
|
286
|
+
React.createElement(Box, { flex: 1, fontWeight: "medium", wordBreak: "all" }, item.type === NodeType.HttpOperation ? item.data.path : item.name),
|
|
235
287
|
isDeprecated && React.createElement(DeprecatedBadge, null)),
|
|
236
288
|
React.createElement(Collapse, { isOpen: isExpanded },
|
|
237
289
|
React.createElement(Box, { flex: 1, p: 2, fontWeight: "medium", mx: "auto", fontSize: "xl" }, item.name),
|
|
@@ -245,11 +297,13 @@ const Item = React.memo(({ item }) => {
|
|
|
245
297
|
React.createElement(TabPanel, null,
|
|
246
298
|
React.createElement(TryItWithRequestSamples, { httpOperation: item.data, tryItCredentialsPolicy: tryItCredentialsPolicy, corsProxy: corsProxy }))))))));
|
|
247
299
|
});
|
|
300
|
+
Item.displayName = 'Item';
|
|
248
301
|
const Collapse = ({ isOpen, children }) => {
|
|
249
302
|
if (!isOpen)
|
|
250
303
|
return null;
|
|
251
304
|
return React.createElement(Box, null, children);
|
|
252
|
-
};
|
|
305
|
+
};
|
|
306
|
+
Collapse.displayName = 'Collapse';
|
|
253
307
|
|
|
254
308
|
const APIWithSidebarLayout = ({ serviceNode, logo, hideTryIt, hideSchemas, hideInternal, hideExport, exportProps, tryItCredentialsPolicy, tryItCorsProxy, }) => {
|
|
255
309
|
const container = React.useRef(null);
|
|
@@ -268,26 +322,32 @@ const APIWithSidebarLayout = ({ serviceNode, logo, hideTryIt, hideSchemas, hideI
|
|
|
268
322
|
if (hideInternal && node && isInternal(node)) {
|
|
269
323
|
return React.createElement(Redirect, { to: "/" });
|
|
270
324
|
}
|
|
325
|
+
const sidebar = (React.createElement(Sidebar, { serviceNode: serviceNode, logo: logo, container: container, pathname: pathname, tree: tree }));
|
|
326
|
+
return (React.createElement(SidebarLayout, { ref: container, sidebar: sidebar }, node && (React.createElement(ParsedDocs, { key: pathname, uri: pathname, node: node, nodeTitle: node.name, layoutOptions: layoutOptions, location: location, exportProps: exportProps, tryItCredentialsPolicy: tryItCredentialsPolicy, tryItCorsProxy: tryItCorsProxy }))));
|
|
327
|
+
};
|
|
328
|
+
const Sidebar = ({ serviceNode, logo, container, pathname, tree }) => {
|
|
271
329
|
const handleTocClick = () => {
|
|
272
330
|
if (container.current) {
|
|
273
331
|
container.current.scrollIntoView();
|
|
274
332
|
}
|
|
275
333
|
};
|
|
276
|
-
|
|
334
|
+
return (React.createElement(React.Fragment, null,
|
|
277
335
|
React.createElement(Flex, { ml: 4, mb: 5, alignItems: "center" },
|
|
278
336
|
logo ? (React.createElement(Logo, { logo: { url: logo, altText: 'logo' } })) : (serviceNode.data.logo && React.createElement(Logo, { logo: serviceNode.data.logo })),
|
|
279
337
|
React.createElement(Heading, { size: 4 }, serviceNode.name)),
|
|
280
338
|
React.createElement(Flex, { flexGrow: true, flexShrink: true, overflowY: "auto", direction: "col" },
|
|
281
339
|
React.createElement(TableOfContents, { tree: tree, activeId: pathname, Link: Link, onLinkClick: handleTocClick })),
|
|
282
340
|
React.createElement(PoweredByLink, { source: serviceNode.name, pathname: pathname, packageType: "elements" })));
|
|
283
|
-
|
|
284
|
-
|
|
341
|
+
};
|
|
342
|
+
Sidebar.displayName = 'Sidebar';
|
|
285
343
|
|
|
286
344
|
var NodeTypes;
|
|
287
345
|
(function (NodeTypes) {
|
|
288
346
|
NodeTypes["Paths"] = "paths";
|
|
289
347
|
NodeTypes["Path"] = "path";
|
|
290
348
|
NodeTypes["Operation"] = "operation";
|
|
349
|
+
NodeTypes["Webhooks"] = "webhooks";
|
|
350
|
+
NodeTypes["Webhook"] = "webhook";
|
|
291
351
|
NodeTypes["Components"] = "components";
|
|
292
352
|
NodeTypes["Models"] = "models";
|
|
293
353
|
NodeTypes["Model"] = "model";
|
|
@@ -339,6 +399,22 @@ const oas3SourceMap = [
|
|
|
339
399
|
},
|
|
340
400
|
],
|
|
341
401
|
},
|
|
402
|
+
{
|
|
403
|
+
match: 'webhooks',
|
|
404
|
+
type: NodeTypes.Webhooks,
|
|
405
|
+
children: [
|
|
406
|
+
{
|
|
407
|
+
notMatch: '^x-',
|
|
408
|
+
type: NodeTypes.Webhook,
|
|
409
|
+
children: [
|
|
410
|
+
{
|
|
411
|
+
match: 'get|post|put|delete|options|head|patch|trace',
|
|
412
|
+
type: NodeTypes.Webhook,
|
|
413
|
+
},
|
|
414
|
+
],
|
|
415
|
+
},
|
|
416
|
+
],
|
|
417
|
+
},
|
|
342
418
|
{
|
|
343
419
|
match: 'components',
|
|
344
420
|
type: NodeTypes.Components,
|
|
@@ -393,7 +469,7 @@ function computeServiceNode(document, map, transformService, transformOperation)
|
|
|
393
469
|
return serviceNode;
|
|
394
470
|
}
|
|
395
471
|
function computeChildNodes(document, data, map, transformer, parentUri = '') {
|
|
396
|
-
var _a;
|
|
472
|
+
var _a, _b;
|
|
397
473
|
const nodes = [];
|
|
398
474
|
if (!isObject(data))
|
|
399
475
|
return nodes;
|
|
@@ -406,7 +482,12 @@ function computeChildNodes(document, data, map, transformer, parentUri = '') {
|
|
|
406
482
|
if (match.type === NodeTypes.Operation && jsonPath.length === 3) {
|
|
407
483
|
const path = String(jsonPath[1]);
|
|
408
484
|
const method = String(jsonPath[2]);
|
|
409
|
-
const operationDocument = transformer({
|
|
485
|
+
const operationDocument = transformer({
|
|
486
|
+
document,
|
|
487
|
+
name: path,
|
|
488
|
+
method,
|
|
489
|
+
config: OPERATION_CONFIG,
|
|
490
|
+
});
|
|
410
491
|
let parsedUri;
|
|
411
492
|
const encodedPath = String(encodePointerFragment(path));
|
|
412
493
|
if (operationDocument.iid) {
|
|
@@ -423,6 +504,31 @@ function computeChildNodes(document, data, map, transformer, parentUri = '') {
|
|
|
423
504
|
tags: ((_a = operationDocument.tags) === null || _a === void 0 ? void 0 : _a.map(tag => tag.name)) || [],
|
|
424
505
|
});
|
|
425
506
|
}
|
|
507
|
+
else if (match.type === NodeTypes.Webhook && jsonPath.length === 3) {
|
|
508
|
+
const name = String(jsonPath[1]);
|
|
509
|
+
const method = String(jsonPath[2]);
|
|
510
|
+
const webhookDocument = transformer({
|
|
511
|
+
document,
|
|
512
|
+
name,
|
|
513
|
+
method,
|
|
514
|
+
config: WEBHOOK_CONFIG,
|
|
515
|
+
});
|
|
516
|
+
let parsedUri;
|
|
517
|
+
const encodedPath = String(encodePointerFragment(name));
|
|
518
|
+
if (webhookDocument.iid) {
|
|
519
|
+
parsedUri = `/webhooks/${webhookDocument.iid}`;
|
|
520
|
+
}
|
|
521
|
+
else {
|
|
522
|
+
parsedUri = uri.replace(encodedPath, slugify(name));
|
|
523
|
+
}
|
|
524
|
+
nodes.push({
|
|
525
|
+
type: NodeType.HttpWebhook,
|
|
526
|
+
uri: parsedUri,
|
|
527
|
+
data: webhookDocument,
|
|
528
|
+
name: webhookDocument.summary || webhookDocument.name,
|
|
529
|
+
tags: ((_b = webhookDocument.tags) === null || _b === void 0 ? void 0 : _b.map(tag => tag.name)) || [],
|
|
530
|
+
});
|
|
531
|
+
}
|
|
426
532
|
else if (match.type === NodeTypes.Model) {
|
|
427
533
|
const schemaDocument = get(document, jsonPath);
|
|
428
534
|
const parsedUri = uri.replace(OAS_MODEL_REGEXP, 'schemas/');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stoplight/elements",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "8.0.0",
|
|
4
4
|
"description": "UI components for composing beautiful developer documentation.",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"main": "./index.js",
|
|
@@ -26,11 +26,11 @@
|
|
|
26
26
|
"react-dom": ">=16.8"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@stoplight/elements-core": "~
|
|
30
|
-
"@stoplight/http-spec": "^
|
|
29
|
+
"@stoplight/elements-core": "~8.0.0",
|
|
30
|
+
"@stoplight/http-spec": "^7.0.1",
|
|
31
31
|
"@stoplight/json": "^3.18.1",
|
|
32
32
|
"@stoplight/mosaic": "^1.46.1",
|
|
33
|
-
"@stoplight/types": "^14.
|
|
33
|
+
"@stoplight/types": "^14.1.1",
|
|
34
34
|
"@stoplight/yaml": "^4.2.3",
|
|
35
35
|
"classnames": "^2.2.6",
|
|
36
36
|
"file-saver": "^2.0.5",
|
package/utils/oas/types.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import { IHttpOperation, IHttpService, NodeType } from '@stoplight/types';
|
|
1
|
+
import { IHttpOperation, IHttpService, IHttpWebhookOperation, NodeType } from '@stoplight/types';
|
|
2
2
|
import { JSONSchema7 } from 'json-schema';
|
|
3
3
|
export declare enum NodeTypes {
|
|
4
4
|
Paths = "paths",
|
|
5
5
|
Path = "path",
|
|
6
6
|
Operation = "operation",
|
|
7
|
+
Webhooks = "webhooks",
|
|
8
|
+
Webhook = "webhook",
|
|
7
9
|
Components = "components",
|
|
8
10
|
Models = "models",
|
|
9
11
|
Model = "model"
|
|
@@ -24,7 +26,8 @@ declare type Node<T, D> = {
|
|
|
24
26
|
export declare type ServiceNode = Node<NodeType.HttpService, IHttpService> & {
|
|
25
27
|
children: ServiceChildNode[];
|
|
26
28
|
};
|
|
27
|
-
export declare type ServiceChildNode = OperationNode | SchemaNode;
|
|
29
|
+
export declare type ServiceChildNode = OperationNode | WebhookNode | SchemaNode;
|
|
28
30
|
export declare type OperationNode = Node<NodeType.HttpOperation, IHttpOperation>;
|
|
31
|
+
export declare type WebhookNode = Node<NodeType.HttpWebhook, IHttpWebhookOperation>;
|
|
29
32
|
export declare type SchemaNode = Node<NodeType.Model, JSONSchema7>;
|
|
30
33
|
export {};
|