@api-components/api-navigation 4.3.5 → 4.3.19
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/package.json +4 -3
- package/src/ApiNavigation.d.ts +7 -0
- package/src/ApiNavigation.js +159 -13
- package/src/types.d.ts +4 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@api-components/api-navigation",
|
|
3
3
|
"description": "An element to display the response body",
|
|
4
|
-
"version": "4.3.
|
|
4
|
+
"version": "4.3.19",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"module": "index.js",
|
|
@@ -26,10 +26,11 @@
|
|
|
26
26
|
"email": "arc@mulesoft.com"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
+
"@advanced-rest-client/arc-icons": "^3.3.4",
|
|
29
30
|
"@advanced-rest-client/icons": "^4.0.2",
|
|
30
|
-
"@anypoint-web-components/anypoint-button": "^1.
|
|
31
|
+
"@anypoint-web-components/anypoint-button": "^1.1.1",
|
|
31
32
|
"@anypoint-web-components/anypoint-collapse": "^0.1.0",
|
|
32
|
-
"@api-components/amf-helper-mixin": "^4.5.
|
|
33
|
+
"@api-components/amf-helper-mixin": "^4.5.34",
|
|
33
34
|
"@api-components/http-method-label": "^3.1.5",
|
|
34
35
|
"@api-components/raml-aware": "^3.0.0",
|
|
35
36
|
"lit-element": "^2.3.1",
|
package/src/ApiNavigation.d.ts
CHANGED
|
@@ -388,6 +388,13 @@ export declare class ApiNavigation {
|
|
|
388
388
|
*/
|
|
389
389
|
_createOperationModel(item: object): MethodItem;
|
|
390
390
|
|
|
391
|
+
/** Detects whether current API is gRPC by inspecting media types */
|
|
392
|
+
__detectGrpcInternal(): boolean;
|
|
393
|
+
/** Maps AMF operation to gRPC stream type, defaults to 'unary' */
|
|
394
|
+
__getGrpcStreamTypeInternal(operation: object): 'unary' | 'server_streaming' | 'client_streaming' | 'bidi_streaming';
|
|
395
|
+
/** Returns request/response schema names for an operation */
|
|
396
|
+
__getOperationSchemasInternal(operationOrId: object | string): { request?: string; response?: string } | undefined;
|
|
397
|
+
|
|
391
398
|
/**
|
|
392
399
|
* Click handler for section name item.
|
|
393
400
|
* Toggles the view.
|
package/src/ApiNavigation.js
CHANGED
|
@@ -3,7 +3,7 @@ import { LitElement, html } from 'lit-element';
|
|
|
3
3
|
import { AmfHelperMixin } from '@api-components/amf-helper-mixin/amf-helper-mixin.js';
|
|
4
4
|
import '@api-components/raml-aware/raml-aware.js';
|
|
5
5
|
import '@anypoint-web-components/anypoint-button/anypoint-icon-button.js';
|
|
6
|
-
import {
|
|
6
|
+
import { codegenie, keyboardArrowDown, openInNew } from '@advanced-rest-client/icons/ArcIcons.js';
|
|
7
7
|
import '@anypoint-web-components/anypoint-collapse/anypoint-collapse.js';
|
|
8
8
|
import httpMethodStyles from '@api-components/http-method-label/http-method-label-common-styles.js';
|
|
9
9
|
import navStyles from './Styles.js';
|
|
@@ -479,6 +479,7 @@ export class ApiNavigation extends AmfHelperMixin(LitElement) {
|
|
|
479
479
|
this.summary = false;
|
|
480
480
|
this.noink = false;
|
|
481
481
|
this.allowPaths = false;
|
|
482
|
+
this._isGrpc = false;
|
|
482
483
|
this.compatibility = false;
|
|
483
484
|
this.rearrangeEndpoints = false;
|
|
484
485
|
this.indentSize = 8;
|
|
@@ -547,7 +548,8 @@ export class ApiNavigation extends AmfHelperMixin(LitElement) {
|
|
|
547
548
|
* @override
|
|
548
549
|
*/
|
|
549
550
|
__amfChanged(api) {
|
|
550
|
-
|
|
551
|
+
// Guard against initial empty-array AMF updates from data loaders
|
|
552
|
+
if (!api || (Array.isArray(api) && (api.length === 0 || !api[0]))) {
|
|
551
553
|
return;
|
|
552
554
|
}
|
|
553
555
|
let model = api;
|
|
@@ -555,13 +557,17 @@ export class ApiNavigation extends AmfHelperMixin(LitElement) {
|
|
|
555
557
|
[model] = model;
|
|
556
558
|
}
|
|
557
559
|
let data = {};
|
|
560
|
+
this.__operationById = {};
|
|
558
561
|
let isFragment = true;
|
|
559
562
|
this._items = null;
|
|
560
563
|
const moduleKey = this._getAmfKey(this.ns.aml.vocabularies.document.Module);
|
|
561
564
|
if (this._hasType(model, this.ns.aml.vocabularies.document.Document)) {
|
|
562
565
|
isFragment = false;
|
|
563
566
|
model = this._ensureAmfModel(model);
|
|
564
|
-
|
|
567
|
+
// Decide collection strategy based on whether this is a gRPC API
|
|
568
|
+
const isGrpcApi = typeof this._isGrpcApi === 'function' ? !!this._isGrpcApi(model) : false;
|
|
569
|
+
this._isGrpc = isGrpcApi;
|
|
570
|
+
data = isGrpcApi ? this._collectGrpcNavigationData(model) : this._collectData(model);
|
|
565
571
|
} else if (
|
|
566
572
|
this._hasType(
|
|
567
573
|
model,
|
|
@@ -593,6 +599,13 @@ export class ApiNavigation extends AmfHelperMixin(LitElement) {
|
|
|
593
599
|
this._types = data.types;
|
|
594
600
|
this._security = data.securitySchemes;
|
|
595
601
|
this._endpoints = data.endpoints;
|
|
602
|
+
try {
|
|
603
|
+
const webApi = this._computeApi(model);
|
|
604
|
+
const apiName = webApi ? this._getValue(webApi, this.ns.aml.vocabularies.core.name) : undefined;
|
|
605
|
+
if (this._renderSummary && apiName) {
|
|
606
|
+
this.summaryLabel = `${apiName} Overview`;
|
|
607
|
+
}
|
|
608
|
+
} catch (_) {}
|
|
596
609
|
this._closeCollapses();
|
|
597
610
|
setTimeout(() => {
|
|
598
611
|
this._selectedChanged(this.selected);
|
|
@@ -618,6 +631,10 @@ export class ApiNavigation extends AmfHelperMixin(LitElement) {
|
|
|
618
631
|
if (!model) {
|
|
619
632
|
return result;
|
|
620
633
|
}
|
|
634
|
+
// Initialize __operationById if not already initialized
|
|
635
|
+
if (!this.__operationById) {
|
|
636
|
+
this.__operationById = {};
|
|
637
|
+
}
|
|
621
638
|
result._typeIds = [];
|
|
622
639
|
result._basePaths = [];
|
|
623
640
|
this._traverseDeclarations(model, result);
|
|
@@ -628,6 +645,92 @@ export class ApiNavigation extends AmfHelperMixin(LitElement) {
|
|
|
628
645
|
return result;
|
|
629
646
|
}
|
|
630
647
|
|
|
648
|
+
/**
|
|
649
|
+
* Collects navigation data for gRPC APIs using AmfHelperMixin helpers.
|
|
650
|
+
* Produces the same view-model shape used by the renderer.
|
|
651
|
+
*
|
|
652
|
+
* @param {object} model AMF model
|
|
653
|
+
* @return {TargetModel}
|
|
654
|
+
*/
|
|
655
|
+
_collectGrpcNavigationData(model) {
|
|
656
|
+
const result = {
|
|
657
|
+
documentation: [],
|
|
658
|
+
types: [],
|
|
659
|
+
securitySchemes: [],
|
|
660
|
+
endpoints: [],
|
|
661
|
+
};
|
|
662
|
+
if (!model) {
|
|
663
|
+
return result;
|
|
664
|
+
}
|
|
665
|
+
const webApi = this._computeApi(model);
|
|
666
|
+
if (!webApi) {
|
|
667
|
+
return result;
|
|
668
|
+
}
|
|
669
|
+
// Build services -> methods as endpoint-like items
|
|
670
|
+
const services = typeof this._computeGrpcServices === 'function' ? this._computeGrpcServices(webApi) : undefined;
|
|
671
|
+
const servicesArray = services || [];
|
|
672
|
+
if (servicesArray && servicesArray.length) {
|
|
673
|
+
servicesArray.forEach(service => {
|
|
674
|
+
const serviceId = service && service['@id'];
|
|
675
|
+
const serviceName = typeof this._computeGrpcServiceName === 'function'
|
|
676
|
+
? this._computeGrpcServiceName(service)
|
|
677
|
+
: this._getValue(service, this.ns.aml.vocabularies.core.name);
|
|
678
|
+
const operations = typeof this._computeGrpcMethods === 'function' ? this._computeGrpcMethods(service) : undefined;
|
|
679
|
+
const opsArray = operations || [];
|
|
680
|
+
const methods = opsArray.map(op => {
|
|
681
|
+
if (op && op['@id']) {
|
|
682
|
+
this.__operationById[op['@id']] = op;
|
|
683
|
+
}
|
|
684
|
+
const methodModel = this._createOperationModel(op);
|
|
685
|
+
// Replace method chip label with simplified type for gRPC
|
|
686
|
+
if (methodModel && methodModel.grpcStreamType) {
|
|
687
|
+
// Map to HTTP method colors: unary→patch(violet), client→publish(green), server→subscribe(blue), bidi→options(gray)
|
|
688
|
+
const colorMethodMap = {
|
|
689
|
+
'unary': 'patch',
|
|
690
|
+
'client_streaming': 'publish',
|
|
691
|
+
'server_streaming': 'subscribe',
|
|
692
|
+
'bidi_streaming': 'options'
|
|
693
|
+
};
|
|
694
|
+
const labelMap = {
|
|
695
|
+
'unary': 'UNARY',
|
|
696
|
+
'client_streaming': 'CLIENT',
|
|
697
|
+
'server_streaming': 'SERVER',
|
|
698
|
+
'bidi_streaming': 'BIDIRECTIONAL'
|
|
699
|
+
};
|
|
700
|
+
methodModel.method = labelMap[methodModel.grpcStreamType] || 'UNARY';
|
|
701
|
+
methodModel.methodForColor = colorMethodMap[methodModel.grpcStreamType] || 'patch';
|
|
702
|
+
}
|
|
703
|
+
return methodModel;
|
|
704
|
+
});
|
|
705
|
+
result.endpoints.push({
|
|
706
|
+
label: String(serviceName || 'Service'),
|
|
707
|
+
id: serviceId,
|
|
708
|
+
indent: 0,
|
|
709
|
+
methods,
|
|
710
|
+
});
|
|
711
|
+
});
|
|
712
|
+
}
|
|
713
|
+
// Populate Messages in the Types section
|
|
714
|
+
const messages = this._computeGrpcMessageTypes(model);
|
|
715
|
+
const msgArray = messages || [];
|
|
716
|
+
if (msgArray && msgArray.length) {
|
|
717
|
+
msgArray.forEach(shape => {
|
|
718
|
+
const id = shape && shape['@id'];
|
|
719
|
+
let name = this._getValue(shape, this.ns.aml.vocabularies.core.name);
|
|
720
|
+
if (!name) {
|
|
721
|
+
name = this._getValue(shape, this.ns.w3.shacl.name);
|
|
722
|
+
}
|
|
723
|
+
if (id && name) {
|
|
724
|
+
result.types.push({
|
|
725
|
+
label: String(name),
|
|
726
|
+
id,
|
|
727
|
+
});
|
|
728
|
+
}
|
|
729
|
+
});
|
|
730
|
+
}
|
|
731
|
+
return result;
|
|
732
|
+
}
|
|
733
|
+
|
|
631
734
|
/**
|
|
632
735
|
* Collects the data from the security fragment
|
|
633
736
|
* @param {object} model Security fragment model
|
|
@@ -917,10 +1020,13 @@ export class ApiNavigation extends AmfHelperMixin(LitElement) {
|
|
|
917
1020
|
const result = {};
|
|
918
1021
|
|
|
919
1022
|
let name = this._getValue(item, this.ns.aml.vocabularies.core.name);
|
|
920
|
-
|
|
1023
|
+
let path = /** @type string */ (this._getValue(
|
|
921
1024
|
item,
|
|
922
1025
|
this.ns.raml.vocabularies.apiContract.path
|
|
923
1026
|
));
|
|
1027
|
+
if (!path && name) {
|
|
1028
|
+
path = `/${name}`;
|
|
1029
|
+
}
|
|
924
1030
|
result.path = path;
|
|
925
1031
|
|
|
926
1032
|
let tmpPath = path;
|
|
@@ -964,7 +1070,13 @@ export class ApiNavigation extends AmfHelperMixin(LitElement) {
|
|
|
964
1070
|
const id = item['@id'];
|
|
965
1071
|
const key = this._getAmfKey(this.ns.aml.vocabularies.apiContract.supportedOperation);
|
|
966
1072
|
const operations = this._ensureArray(item[key]) || [];
|
|
967
|
-
const methods = operations.map(op =>
|
|
1073
|
+
const methods = operations.map(op => {
|
|
1074
|
+
const model = this._createOperationModel(op);
|
|
1075
|
+
if (op && op['@id']) {
|
|
1076
|
+
this.__operationById[op['@id']] = op;
|
|
1077
|
+
}
|
|
1078
|
+
return model;
|
|
1079
|
+
});
|
|
968
1080
|
result.label = String(name);
|
|
969
1081
|
result.id = id;
|
|
970
1082
|
result.indent = indent;
|
|
@@ -985,11 +1097,37 @@ export class ApiNavigation extends AmfHelperMixin(LitElement) {
|
|
|
985
1097
|
));
|
|
986
1098
|
const methodKey = this.ns.aml.vocabularies.apiContract.method;
|
|
987
1099
|
const id = item['@id'];
|
|
988
|
-
|
|
1100
|
+
let method = /** @type string */ (this._getValue(item, methodKey));
|
|
1101
|
+
// Populate gRPC fields via helpers when available
|
|
1102
|
+
/** @type {'unary'|'server_streaming'|'client_streaming'|'bidi_streaming'|undefined} */
|
|
1103
|
+
const grpcStreamType = this._isGrpc && /** @type any */ (this._getGrpcStreamType(item))
|
|
1104
|
+
const requestShape = this._isGrpc && this._computeGrpcRequestSchema(item)
|
|
1105
|
+
const responseShape = this._isGrpc && this._computeGrpcResponseSchema(item)
|
|
1106
|
+
|
|
1107
|
+
let requestSchema;
|
|
1108
|
+
if (requestShape) {
|
|
1109
|
+
const rn = this._getValue(requestShape, this.ns.aml.vocabularies.core.name) || this._getValue(requestShape, this.ns.w3.shacl.name);
|
|
1110
|
+
if (typeof rn === 'string') {
|
|
1111
|
+
requestSchema = rn;
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
let responseSchema;
|
|
1115
|
+
if (responseShape) {
|
|
1116
|
+
const rsn = this._getValue(responseShape, this.ns.aml.vocabularies.core.name) || this._getValue(responseShape, this.ns.w3.shacl.name);
|
|
1117
|
+
if (typeof rsn === 'string') {
|
|
1118
|
+
responseSchema = rsn;
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
if (this._isGrpc && grpcStreamType) {
|
|
1122
|
+
method = this._getGrpcStreamTypeDisplayName(grpcStreamType);
|
|
1123
|
+
}
|
|
989
1124
|
return {
|
|
990
1125
|
label,
|
|
991
1126
|
id,
|
|
992
1127
|
method,
|
|
1128
|
+
grpcStreamType,
|
|
1129
|
+
requestSchema,
|
|
1130
|
+
responseSchema,
|
|
993
1131
|
};
|
|
994
1132
|
}
|
|
995
1133
|
|
|
@@ -1298,7 +1436,7 @@ export class ApiNavigation extends AmfHelperMixin(LitElement) {
|
|
|
1298
1436
|
}
|
|
1299
1437
|
node.classList.add('passive-selected');
|
|
1300
1438
|
this.__hasPassiveSelection = true;
|
|
1301
|
-
const collapse = /** @type
|
|
1439
|
+
const collapse = /** @type AnypointCollapseElement */ (node.parentElement);
|
|
1302
1440
|
if (!collapse.opened) {
|
|
1303
1441
|
collapse.opened = true;
|
|
1304
1442
|
}
|
|
@@ -1847,7 +1985,14 @@ export class ApiNavigation extends AmfHelperMixin(LitElement) {
|
|
|
1847
1985
|
}
|
|
1848
1986
|
const toggleState = this.endpointsOpened ? 'Expanded' : 'Collapsed';
|
|
1849
1987
|
|
|
1850
|
-
|
|
1988
|
+
let sectionLabel;
|
|
1989
|
+
if (this._isGrpc) {
|
|
1990
|
+
sectionLabel = 'Methods';
|
|
1991
|
+
} else if (this._isWebAPI(this.amf)) {
|
|
1992
|
+
sectionLabel = 'Endpoints';
|
|
1993
|
+
} else {
|
|
1994
|
+
sectionLabel = 'Channels';
|
|
1995
|
+
}
|
|
1851
1996
|
const lowercaseSectionLabel = sectionLabel.toLowerCase();
|
|
1852
1997
|
|
|
1853
1998
|
return html` <section
|
|
@@ -1895,7 +2040,7 @@ export class ApiNavigation extends AmfHelperMixin(LitElement) {
|
|
|
1895
2040
|
*/
|
|
1896
2041
|
_overviewTemplate(item) {
|
|
1897
2042
|
if (this.noOverview) {
|
|
1898
|
-
return
|
|
2043
|
+
return html``;
|
|
1899
2044
|
}
|
|
1900
2045
|
return html`<div
|
|
1901
2046
|
part="api-navigation-list-item"
|
|
@@ -2003,13 +2148,13 @@ export class ApiNavigation extends AmfHelperMixin(LitElement) {
|
|
|
2003
2148
|
class="method-label ${methodItem.hasAgent
|
|
2004
2149
|
? 'method-label-with-icon'
|
|
2005
2150
|
: ''}"
|
|
2006
|
-
data-method="${methodItem.method}"
|
|
2151
|
+
data-method="${methodItem.methodForColor || methodItem.method}"
|
|
2007
2152
|
>${methodItem.method}
|
|
2008
2153
|
${methodItem.hasAgent
|
|
2009
2154
|
? html`<span class="method-icon">${codegenie}</span>`
|
|
2010
2155
|
: ''}</span
|
|
2011
2156
|
>
|
|
2012
|
-
${methodItem.label}
|
|
2157
|
+
${!this._isGrpc ? methodItem.label : ''}
|
|
2013
2158
|
</div>`;
|
|
2014
2159
|
}
|
|
2015
2160
|
|
|
@@ -2108,6 +2253,7 @@ export class ApiNavigation extends AmfHelperMixin(LitElement) {
|
|
|
2108
2253
|
return '';
|
|
2109
2254
|
}
|
|
2110
2255
|
const toggleState = this.typesOpened ? 'Expanded' : 'Collapsed';
|
|
2256
|
+
const typesLabel = this._isGrpc ? 'Messages' : 'Types';
|
|
2111
2257
|
|
|
2112
2258
|
return html`
|
|
2113
2259
|
<section class="types" ?data-opened="${this.typesOpened}">
|
|
@@ -2117,7 +2263,7 @@ export class ApiNavigation extends AmfHelperMixin(LitElement) {
|
|
|
2117
2263
|
@click="${this._toggleSectionHandler}"
|
|
2118
2264
|
title="Toggle types list"
|
|
2119
2265
|
>
|
|
2120
|
-
<div class="title-h3"
|
|
2266
|
+
<div class="title-h3">${typesLabel}</div>
|
|
2121
2267
|
<anypoint-icon-button
|
|
2122
2268
|
part="toggle-button"
|
|
2123
2269
|
class="toggle-button"
|
|
@@ -2128,7 +2274,7 @@ export class ApiNavigation extends AmfHelperMixin(LitElement) {
|
|
|
2128
2274
|
data-toggle="types"
|
|
2129
2275
|
>
|
|
2130
2276
|
<span class="icon" aria-label="${toggleState}"
|
|
2131
|
-
|
|
2277
|
+
>${keyboardArrowDown}</span
|
|
2132
2278
|
>
|
|
2133
2279
|
</anypoint-icon-button>
|
|
2134
2280
|
</div>
|
package/src/types.d.ts
CHANGED
|
@@ -5,7 +5,11 @@ export declare interface NavigationItem {
|
|
|
5
5
|
|
|
6
6
|
export declare interface MethodItem extends NavigationItem {
|
|
7
7
|
method: string;
|
|
8
|
+
methodForColor?: string;
|
|
8
9
|
hasAgent?: boolean;
|
|
10
|
+
grpcStreamType?: 'unary' | 'server_streaming' | 'client_streaming' | 'bidi_streaming';
|
|
11
|
+
requestSchema?: string;
|
|
12
|
+
responseSchema?: string;
|
|
9
13
|
}
|
|
10
14
|
|
|
11
15
|
export declare interface EndpointItem extends NavigationItem {
|