@stoplight/elements-core 8.1.3 → 8.2.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/__fixtures__/operations/x-code-samples.d.ts +2 -0
- package/components/Docs/HttpOperation/HttpOperation.stories.d.ts +3 -0
- package/components/RequestSamples/RequestSamples.d.ts +2 -0
- package/components/RequestSamples/RequestSamples.stories.d.ts +1 -0
- package/components/RequestSamples/extractCodeSamples.d.ts +7 -0
- package/components/RequestSamples/index.d.ts +1 -0
- package/components/RequestSamples/requestSampleConfigs.d.ts +5 -7
- package/index.esm.js +152 -51
- package/index.js +155 -51
- package/index.mjs +152 -51
- package/package.json +2 -2
|
@@ -5,3 +5,6 @@ export default meta;
|
|
|
5
5
|
export declare const Story: import("@storybook/types").AnnotatedStoryFn<import("@storybook/react/dist/types-0a347bb9").R, {
|
|
6
6
|
data: any;
|
|
7
7
|
} & import("@stoplight/react-error-boundary").ErrorBoundaryProps<{}>>;
|
|
8
|
+
export declare const StoryWithCustomCodeSamples: import("@storybook/types").AnnotatedStoryFn<import("@storybook/react/dist/types-0a347bb9").R, {
|
|
9
|
+
data: any;
|
|
10
|
+
} & import("@stoplight/react-error-boundary").ErrorBoundaryProps<{}>>;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { Request } from 'har-format';
|
|
2
2
|
import React from 'react';
|
|
3
|
+
import { CodeSample } from './extractCodeSamples';
|
|
3
4
|
export interface RequestSamplesProps {
|
|
4
5
|
request: Request;
|
|
6
|
+
customCodeSamples?: CodeSample[];
|
|
5
7
|
embeddedInMd?: boolean;
|
|
6
8
|
}
|
|
7
9
|
export declare const RequestSamples: React.NamedExoticComponent<RequestSamplesProps>;
|
|
@@ -2,3 +2,4 @@ import { RequestSamplesProps } from './RequestSamples';
|
|
|
2
2
|
declare const _default: import("@storybook/types").ComponentAnnotations<import("@storybook/react/dist/types-0a347bb9").R, RequestSamplesProps>;
|
|
3
3
|
export default _default;
|
|
4
4
|
export declare const HoistedStory: import("@storybook/types").AnnotatedStoryFn<import("@storybook/react/dist/types-0a347bb9").R, RequestSamplesProps>;
|
|
5
|
+
export declare const RequestSampleWithCustomCodes: import("@storybook/types").AnnotatedStoryFn<import("@storybook/react/dist/types-0a347bb9").R, RequestSamplesProps>;
|
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
import { CodeViewerLanguage } from '@stoplight/mosaic-code-viewer';
|
|
2
2
|
import { Dictionary } from '@stoplight/types';
|
|
3
|
-
declare type SupportedLanguage = string;
|
|
4
|
-
declare type SupportedLibrary = string;
|
|
5
|
-
interface LibraryConfig {
|
|
3
|
+
export declare type SupportedLanguage = string;
|
|
4
|
+
export declare type SupportedLibrary = string;
|
|
5
|
+
export interface LibraryConfig {
|
|
6
6
|
httpSnippetLibrary: string;
|
|
7
7
|
}
|
|
8
|
-
interface LanguageConfig {
|
|
8
|
+
export interface LanguageConfig {
|
|
9
9
|
mosaicCodeViewerLanguage: CodeViewerLanguage;
|
|
10
10
|
httpSnippetLanguage: string;
|
|
11
11
|
libraries?: Dictionary<LibraryConfig, SupportedLibrary>;
|
|
12
12
|
}
|
|
13
|
-
declare type RequestSampleConfigs = Dictionary<LanguageConfig, SupportedLanguage>;
|
|
13
|
+
export declare type RequestSampleConfigs = Dictionary<LanguageConfig, SupportedLanguage>;
|
|
14
14
|
export declare const requestSampleConfigs: RequestSampleConfigs;
|
|
15
|
-
export declare const getConfigFor: (language: string, library: string) => LanguageConfig & Partial<LibraryConfig>;
|
|
16
|
-
export {};
|
package/index.esm.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { __rest, __awaiter } from 'tslib';
|
|
2
2
|
import * as React from 'react';
|
|
3
|
-
import React__default, { useContext, useMemo } from 'react';
|
|
3
|
+
import React__default, { useContext, memo, useMemo, useState, useEffect } from 'react';
|
|
4
4
|
import { convertToJsonSchema } from '@stoplight/http-spec/oas';
|
|
5
5
|
import { resolveInlineRef, hasRef, isPlainObject as isPlainObject$1, safeParse, safeStringify } from '@stoplight/json';
|
|
6
6
|
import isArray from 'lodash/isArray.js';
|
|
@@ -17,7 +17,11 @@ import cn from 'classnames';
|
|
|
17
17
|
import { atomWithStorage, useAtomValue } from 'jotai/utils';
|
|
18
18
|
import { atom, useAtom, Provider } from 'jotai';
|
|
19
19
|
import URI from 'urijs';
|
|
20
|
+
import isString from 'lodash/isString.js';
|
|
20
21
|
import { CodeViewer } from '@stoplight/mosaic-code-viewer';
|
|
22
|
+
import cloneDeep from 'lodash/cloneDeep.js';
|
|
23
|
+
import find from 'lodash/find.js';
|
|
24
|
+
import findKey from 'lodash/findKey.js';
|
|
21
25
|
import { isValidTargetId, HTTPSnippet } from 'httpsnippet-lite';
|
|
22
26
|
import { hash } from '@stoplight/http-spec/hash';
|
|
23
27
|
import capitalize from 'lodash/capitalize.js';
|
|
@@ -32,7 +36,6 @@ import keyBy from 'lodash/keyBy.js';
|
|
|
32
36
|
import last from 'lodash/last.js';
|
|
33
37
|
import map from 'lodash/map.js';
|
|
34
38
|
import mapValues from 'lodash/mapValues.js';
|
|
35
|
-
import isString from 'lodash/isString.js';
|
|
36
39
|
import pickBy from 'lodash/pickBy.js';
|
|
37
40
|
import { CodeEditor } from '@stoplight/mosaic-code-editor';
|
|
38
41
|
import * as Sampler from '@stoplight/json-schema-sampler';
|
|
@@ -620,6 +623,29 @@ const getServerUrlWithVariableValues = (server, values) => {
|
|
|
620
623
|
return urlString;
|
|
621
624
|
};
|
|
622
625
|
|
|
626
|
+
const extractCodeSamples = (obj) => {
|
|
627
|
+
if (!isPlainObject$1(obj) || !isPlainObject$1(obj.extensions)) {
|
|
628
|
+
return [];
|
|
629
|
+
}
|
|
630
|
+
const codeSamples = obj.extensions['x-codeSamples'];
|
|
631
|
+
if (!Array.isArray(codeSamples)) {
|
|
632
|
+
return [];
|
|
633
|
+
}
|
|
634
|
+
return codeSamples.reduce((extracted, item) => {
|
|
635
|
+
if (isPlainObject$1(item) && isString(item['lang']) && isString(item['source'])) {
|
|
636
|
+
const lib = isString(item['lib']) ? item['lib'] : undefined;
|
|
637
|
+
const label = isString(item['label']) ? item['label'] : lib !== null && lib !== void 0 ? lib : item['lang'];
|
|
638
|
+
extracted.push({
|
|
639
|
+
lang: item['lang'],
|
|
640
|
+
lib,
|
|
641
|
+
label,
|
|
642
|
+
source: item['source'],
|
|
643
|
+
});
|
|
644
|
+
}
|
|
645
|
+
return extracted;
|
|
646
|
+
}, []);
|
|
647
|
+
};
|
|
648
|
+
|
|
623
649
|
const persistAtom = (key, atomInstance) => {
|
|
624
650
|
if (typeof window === 'undefined' || window.localStorage === undefined) {
|
|
625
651
|
return atomInstance;
|
|
@@ -825,76 +851,149 @@ const requestSampleConfigs = {
|
|
|
825
851
|
mosaicCodeViewerLanguage: 'swift',
|
|
826
852
|
httpSnippetLanguage: 'swift',
|
|
827
853
|
},
|
|
828
|
-
};
|
|
829
|
-
const getConfigFor = (language, library) => {
|
|
830
|
-
var _a;
|
|
831
|
-
const languageConfig = requestSampleConfigs[language];
|
|
832
|
-
const libraryConfig = ((_a = languageConfig.libraries) === null || _a === void 0 ? void 0 : _a[library]) || {};
|
|
833
|
-
return Object.assign(Object.assign({}, languageConfig), libraryConfig);
|
|
834
854
|
};
|
|
835
855
|
|
|
836
|
-
const selectedLanguageAtom = persistAtom('RequestSamples_selectedLanguage', atom('
|
|
837
|
-
const selectedLibraryAtom = persistAtom('RequestSamples_selectedLibrary', atom('
|
|
856
|
+
const selectedLanguageAtom = persistAtom('RequestSamples_selectedLanguage', atom('shell'));
|
|
857
|
+
const selectedLibraryAtom = persistAtom('RequestSamples_selectedLibrary', atom('curl'));
|
|
838
858
|
const fallbackText = 'Unable to generate code example';
|
|
839
|
-
const RequestSamples =
|
|
859
|
+
const RequestSamples = memo(({ request, embeddedInMd = false, customCodeSamples = [] }) => {
|
|
840
860
|
const [selectedLanguage, setSelectedLanguage] = useAtom(selectedLanguageAtom);
|
|
841
861
|
const [selectedLibrary, setSelectedLibrary] = useAtom(selectedLibraryAtom);
|
|
842
|
-
const
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
.
|
|
848
|
-
|
|
849
|
-
|
|
862
|
+
const allRequestSamples = useMemo(() => {
|
|
863
|
+
var _a;
|
|
864
|
+
const requestSamples = cloneDeep(requestSampleConfigs);
|
|
865
|
+
Object.entries(requestSamples).forEach(([languageKey, value]) => {
|
|
866
|
+
var _a;
|
|
867
|
+
value.displayText = languageKey;
|
|
868
|
+
Object.entries(((_a = value.libraries) !== null && _a !== void 0 ? _a : (value.libraries = {}))).forEach(([libKey, value]) => {
|
|
869
|
+
value.displayText = `${languageKey} / ${libKey}`;
|
|
870
|
+
});
|
|
871
|
+
});
|
|
872
|
+
for (const customCodeSample of customCodeSamples) {
|
|
873
|
+
const existingLanguageSampleKey = findKey(requestSamples, {
|
|
874
|
+
httpSnippetLanguage: customCodeSample.lang.toLowerCase(),
|
|
875
|
+
});
|
|
876
|
+
const existingLanguageSample = requestSamples[existingLanguageSampleKey];
|
|
877
|
+
if (!existingLanguageSample) {
|
|
878
|
+
const newLanguageSample = {
|
|
879
|
+
displayText: customCodeSample.lang,
|
|
880
|
+
mosaicCodeViewerLanguage: customCodeSample.lang,
|
|
881
|
+
httpSnippetLanguage: customCodeSample.lang,
|
|
882
|
+
libraries: {},
|
|
883
|
+
};
|
|
884
|
+
if (customCodeSample.lib) {
|
|
885
|
+
newLanguageSample.libraries[customCodeSample.lib] = {
|
|
886
|
+
displayText: `${customCodeSample.lang} / ${customCodeSample.lib}`,
|
|
887
|
+
httpSnippetLibrary: customCodeSample.lib,
|
|
888
|
+
sampleCode: customCodeSample.source,
|
|
889
|
+
};
|
|
890
|
+
}
|
|
891
|
+
else {
|
|
892
|
+
newLanguageSample.sampleCode = customCodeSample.source;
|
|
893
|
+
}
|
|
894
|
+
requestSamples[customCodeSample.label] = newLanguageSample;
|
|
850
895
|
}
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
896
|
+
else {
|
|
897
|
+
(_a = existingLanguageSample.libraries) !== null && _a !== void 0 ? _a : (existingLanguageSample.libraries = {});
|
|
898
|
+
if (customCodeSample.lib) {
|
|
899
|
+
const existingLibrarySampleKey = findKey(existingLanguageSample.libraries, {
|
|
900
|
+
httpSnippetLibrary: customCodeSample.lib,
|
|
901
|
+
});
|
|
902
|
+
const existingLibrarySample = existingLanguageSample.libraries[existingLibrarySampleKey];
|
|
903
|
+
if (!existingLibrarySample) {
|
|
904
|
+
const newLibrarySample = {
|
|
905
|
+
displayText: `${existingLanguageSample} / ${customCodeSample.lib}`,
|
|
906
|
+
httpSnippetLibrary: customCodeSample.lib,
|
|
907
|
+
sampleCode: customCodeSample.source,
|
|
908
|
+
};
|
|
909
|
+
existingLanguageSample.libraries[customCodeSample.lib] = newLibrarySample;
|
|
910
|
+
}
|
|
911
|
+
else {
|
|
912
|
+
existingLibrarySample.displayText = `${existingLanguageSampleKey} / ${existingLibrarySampleKey}`;
|
|
913
|
+
existingLibrarySample.sampleCode = customCodeSample.source;
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
else {
|
|
917
|
+
existingLanguageSample.sampleCode = customCodeSample.source;
|
|
918
|
+
}
|
|
855
919
|
}
|
|
856
|
-
}
|
|
857
|
-
return
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
const hasLibraries =
|
|
920
|
+
}
|
|
921
|
+
return requestSamples;
|
|
922
|
+
}, [customCodeSamples]);
|
|
923
|
+
const [menuItems, selectedSampleConfig] = useMemo(() => {
|
|
924
|
+
var _a, _b;
|
|
925
|
+
const items = Object.entries(allRequestSamples).map(([languageLabel, languageConfig]) => {
|
|
926
|
+
var _a;
|
|
927
|
+
const hasLibraries = Object.keys((_a = languageConfig.libraries) !== null && _a !== void 0 ? _a : {}).length > 0;
|
|
864
928
|
return {
|
|
865
|
-
id:
|
|
866
|
-
title:
|
|
867
|
-
isChecked: selectedLanguage ===
|
|
929
|
+
id: languageLabel,
|
|
930
|
+
title: languageLabel,
|
|
931
|
+
isChecked: selectedLanguage === languageConfig.httpSnippetLanguage,
|
|
932
|
+
closeOnPress: !hasLibraries,
|
|
868
933
|
onPress: hasLibraries
|
|
869
934
|
? undefined
|
|
870
935
|
: () => {
|
|
871
|
-
setSelectedLanguage(
|
|
936
|
+
setSelectedLanguage(languageConfig.httpSnippetLanguage);
|
|
872
937
|
setSelectedLibrary('');
|
|
873
938
|
},
|
|
874
|
-
children:
|
|
875
|
-
? Object.
|
|
876
|
-
id: `${
|
|
877
|
-
title:
|
|
878
|
-
isChecked: selectedLanguage ===
|
|
939
|
+
children: hasLibraries
|
|
940
|
+
? Object.entries(languageConfig.libraries).map(([libraryLabel, libraryConfig]) => ({
|
|
941
|
+
id: `${languageLabel}-${libraryLabel}`,
|
|
942
|
+
title: libraryLabel,
|
|
943
|
+
isChecked: selectedLanguage === languageConfig.httpSnippetLanguage &&
|
|
944
|
+
selectedLibrary === libraryConfig.httpSnippetLibrary,
|
|
879
945
|
onPress: () => {
|
|
880
|
-
setSelectedLanguage(
|
|
881
|
-
setSelectedLibrary(
|
|
946
|
+
setSelectedLanguage(languageConfig.httpSnippetLanguage);
|
|
947
|
+
setSelectedLibrary(libraryConfig.httpSnippetLibrary);
|
|
882
948
|
},
|
|
883
949
|
}))
|
|
884
950
|
: undefined,
|
|
885
951
|
};
|
|
886
952
|
});
|
|
887
|
-
|
|
888
|
-
|
|
953
|
+
const selectedLanguageSample = find(allRequestSamples, { httpSnippetLanguage: selectedLanguage });
|
|
954
|
+
const selectedLibrarySample = find((_a = selectedLanguageSample === null || selectedLanguageSample === void 0 ? void 0 : selectedLanguageSample.libraries) !== null && _a !== void 0 ? _a : {}, {
|
|
955
|
+
httpSnippetLibrary: selectedLibrary,
|
|
956
|
+
});
|
|
957
|
+
return [
|
|
958
|
+
items,
|
|
959
|
+
Object.assign(Object.assign(Object.assign({}, selectedLibrarySample), selectedLanguageSample), { displayText: (_b = selectedLibrarySample === null || selectedLibrarySample === void 0 ? void 0 : selectedLibrarySample.displayText) !== null && _b !== void 0 ? _b : selectedLanguageSample === null || selectedLanguageSample === void 0 ? void 0 : selectedLanguageSample.displayText }),
|
|
960
|
+
];
|
|
961
|
+
}, [allRequestSamples, selectedLanguage, selectedLibrary, setSelectedLanguage, setSelectedLibrary]);
|
|
962
|
+
const [requestSample, setRequestSample] = useState(null);
|
|
963
|
+
useEffect(() => {
|
|
964
|
+
let isStale = false;
|
|
965
|
+
if (selectedSampleConfig) {
|
|
966
|
+
if (selectedSampleConfig.sampleCode) {
|
|
967
|
+
setRequestSample(selectedSampleConfig.sampleCode);
|
|
968
|
+
}
|
|
969
|
+
else {
|
|
970
|
+
convertRequestToSample(selectedSampleConfig.httpSnippetLanguage, selectedSampleConfig.httpSnippetLibrary, request)
|
|
971
|
+
.then(example => {
|
|
972
|
+
if (!isStale) {
|
|
973
|
+
setRequestSample(example);
|
|
974
|
+
}
|
|
975
|
+
})
|
|
976
|
+
.catch(() => {
|
|
977
|
+
if (!isStale) {
|
|
978
|
+
setRequestSample(fallbackText);
|
|
979
|
+
}
|
|
980
|
+
});
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
else {
|
|
984
|
+
setRequestSample(fallbackText);
|
|
985
|
+
}
|
|
986
|
+
return () => {
|
|
987
|
+
isStale = true;
|
|
988
|
+
};
|
|
989
|
+
}, [request, selectedSampleConfig]);
|
|
889
990
|
return (React__default.createElement(Panel, { rounded: embeddedInMd ? undefined : true, isCollapsible: embeddedInMd },
|
|
890
991
|
React__default.createElement(Panel.Titlebar, { rightComponent: React__default.createElement(CopyButton, { size: "sm", copyValue: requestSample || '' }) },
|
|
891
992
|
React__default.createElement(Box, { ml: -2 },
|
|
892
993
|
React__default.createElement(Menu, { "aria-label": "Request Sample Language", closeOnPress: true, items: menuItems, renderTrigger: ({ isOpen }) => (React__default.createElement(Button, { size: "sm", iconRight: "chevron-down", appearance: "minimal", active: isOpen },
|
|
893
994
|
"Request Sample: ",
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
selectedLibrary ? ` / ${selectedLibrary}` : '')) }))),
|
|
897
|
-
React__default.createElement(Panel.Content, { p: 0 }, requestSample !== null && (React__default.createElement(CodeViewer, { "aria-label": requestSample, noCopyButton: true, maxHeight: "400px", language: mosaicCodeViewerLanguage, value: requestSample, style: embeddedInMd
|
|
995
|
+
selectedSampleConfig.displayText)) }))),
|
|
996
|
+
React__default.createElement(Panel.Content, { p: 0 }, requestSample !== null && (React__default.createElement(CodeViewer, { "aria-label": requestSample, noCopyButton: true, maxHeight: "400px", language: selectedSampleConfig === null || selectedSampleConfig === void 0 ? void 0 : selectedSampleConfig.mosaicCodeViewerLanguage, value: requestSample, style: embeddedInMd
|
|
898
997
|
? undefined
|
|
899
998
|
:
|
|
900
999
|
{
|
|
@@ -2158,6 +2257,7 @@ const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embe
|
|
|
2158
2257
|
const { serverVariables: serverVariableValues, updateServerVariableValue } = useServerVariables();
|
|
2159
2258
|
const isMockingEnabled = mockUrl && (chosenServer === null || chosenServer === void 0 ? void 0 : chosenServer.url) === mockUrl;
|
|
2160
2259
|
const hasRequiredButEmptyParameters = allParameters.some(parameter => parameter.required && !parameterValuesWithDefaults[parameter.name]);
|
|
2260
|
+
const customCodeSamples = extractCodeSamples(httpOperation);
|
|
2161
2261
|
const getValues = () => Object.keys(bodyParameterValues)
|
|
2162
2262
|
.filter(param => { var _a; return (_a = !isAllowedEmptyValues[param]) !== null && _a !== void 0 ? _a : true; })
|
|
2163
2263
|
.reduce((previousValue, currentValue) => {
|
|
@@ -2287,11 +2387,11 @@ const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embe
|
|
|
2287
2387
|
tryItPanelContents));
|
|
2288
2388
|
}
|
|
2289
2389
|
else {
|
|
2290
|
-
tryItPanelElem = (React.createElement(Box, { className: "TryItPanel", bg: "canvas-100"
|
|
2390
|
+
tryItPanelElem = (React.createElement(Box, { className: "TryItPanel", bg: "canvas-100" }, tryItPanelContents));
|
|
2291
2391
|
}
|
|
2292
2392
|
return (React.createElement(Box, { rounded: "lg", overflowY: "hidden" },
|
|
2293
2393
|
tryItPanelElem,
|
|
2294
|
-
requestData && embeddedInMd && React.createElement(RequestSamples, { request: requestData, embeddedInMd: true }),
|
|
2394
|
+
requestData && embeddedInMd && (React.createElement(RequestSamples, { request: requestData, customCodeSamples: customCodeSamples, embeddedInMd: true })),
|
|
2295
2395
|
response && !('error' in response) && React.createElement(TryItResponse, { response: response }),
|
|
2296
2396
|
response && 'error' in response && React.createElement(ResponseError, { state: response })));
|
|
2297
2397
|
};
|
|
@@ -2335,11 +2435,12 @@ const ResponseExamples = ({ httpOperation, responseMediaType, responseStatusCode
|
|
|
2335
2435
|
const TryItWithRequestSamples = (_a) => {
|
|
2336
2436
|
var { hideTryIt } = _a, props = __rest(_a, ["hideTryIt"]);
|
|
2337
2437
|
const [requestData, setRequestData] = React.useState();
|
|
2438
|
+
const customCodeSamples = extractCodeSamples(props.httpOperation);
|
|
2338
2439
|
return (React.createElement(VStack, { spacing: 6 },
|
|
2339
2440
|
!hideTryIt && (React.createElement(InvertTheme, null,
|
|
2340
2441
|
React.createElement(Box, null,
|
|
2341
2442
|
React.createElement(TryIt, Object.assign({}, props, { onRequestChange: setRequestData }))))),
|
|
2342
|
-
requestData && React.createElement(RequestSamples, { request: requestData }),
|
|
2443
|
+
requestData && React.createElement(RequestSamples, { request: requestData, customCodeSamples: customCodeSamples }),
|
|
2343
2444
|
React.createElement(ResponseExamples, Object.assign({}, props))));
|
|
2344
2445
|
};
|
|
2345
2446
|
|
package/index.js
CHANGED
|
@@ -19,7 +19,11 @@ var cn = require('classnames');
|
|
|
19
19
|
var utils = require('jotai/utils');
|
|
20
20
|
var jotai = require('jotai');
|
|
21
21
|
var URI = require('urijs');
|
|
22
|
+
var isString = require('lodash/isString.js');
|
|
22
23
|
var mosaicCodeViewer = require('@stoplight/mosaic-code-viewer');
|
|
24
|
+
var cloneDeep = require('lodash/cloneDeep.js');
|
|
25
|
+
var find = require('lodash/find.js');
|
|
26
|
+
var findKey = require('lodash/findKey.js');
|
|
23
27
|
var httpsnippetLite = require('httpsnippet-lite');
|
|
24
28
|
var hash = require('@stoplight/http-spec/hash');
|
|
25
29
|
var capitalize = require('lodash/capitalize.js');
|
|
@@ -34,7 +38,6 @@ var keyBy = require('lodash/keyBy.js');
|
|
|
34
38
|
var last = require('lodash/last.js');
|
|
35
39
|
var map = require('lodash/map.js');
|
|
36
40
|
var mapValues = require('lodash/mapValues.js');
|
|
37
|
-
var isString = require('lodash/isString.js');
|
|
38
41
|
var pickBy = require('lodash/pickBy.js');
|
|
39
42
|
var mosaicCodeEditor = require('@stoplight/mosaic-code-editor');
|
|
40
43
|
var Sampler = require('@stoplight/json-schema-sampler');
|
|
@@ -83,6 +86,10 @@ var isPlainObject__default = /*#__PURE__*/_interopDefaultLegacy(isPlainObject);
|
|
|
83
86
|
var isObject__default = /*#__PURE__*/_interopDefaultLegacy(isObject);
|
|
84
87
|
var cn__default = /*#__PURE__*/_interopDefaultLegacy(cn);
|
|
85
88
|
var URI__default = /*#__PURE__*/_interopDefaultLegacy(URI);
|
|
89
|
+
var isString__default = /*#__PURE__*/_interopDefaultLegacy(isString);
|
|
90
|
+
var cloneDeep__default = /*#__PURE__*/_interopDefaultLegacy(cloneDeep);
|
|
91
|
+
var find__default = /*#__PURE__*/_interopDefaultLegacy(find);
|
|
92
|
+
var findKey__default = /*#__PURE__*/_interopDefaultLegacy(findKey);
|
|
86
93
|
var capitalize__default = /*#__PURE__*/_interopDefaultLegacy(capitalize);
|
|
87
94
|
var filter__default = /*#__PURE__*/_interopDefaultLegacy(filter);
|
|
88
95
|
var flatten__default = /*#__PURE__*/_interopDefaultLegacy(flatten);
|
|
@@ -92,7 +99,6 @@ var keyBy__default = /*#__PURE__*/_interopDefaultLegacy(keyBy);
|
|
|
92
99
|
var last__default = /*#__PURE__*/_interopDefaultLegacy(last);
|
|
93
100
|
var map__default = /*#__PURE__*/_interopDefaultLegacy(map);
|
|
94
101
|
var mapValues__default = /*#__PURE__*/_interopDefaultLegacy(mapValues);
|
|
95
|
-
var isString__default = /*#__PURE__*/_interopDefaultLegacy(isString);
|
|
96
102
|
var pickBy__default = /*#__PURE__*/_interopDefaultLegacy(pickBy);
|
|
97
103
|
var Sampler__namespace = /*#__PURE__*/_interopNamespace(Sampler);
|
|
98
104
|
var compact__default = /*#__PURE__*/_interopDefaultLegacy(compact);
|
|
@@ -677,6 +683,29 @@ const getServerUrlWithVariableValues = (server, values) => {
|
|
|
677
683
|
return urlString;
|
|
678
684
|
};
|
|
679
685
|
|
|
686
|
+
const extractCodeSamples = (obj) => {
|
|
687
|
+
if (!json.isPlainObject(obj) || !json.isPlainObject(obj.extensions)) {
|
|
688
|
+
return [];
|
|
689
|
+
}
|
|
690
|
+
const codeSamples = obj.extensions['x-codeSamples'];
|
|
691
|
+
if (!Array.isArray(codeSamples)) {
|
|
692
|
+
return [];
|
|
693
|
+
}
|
|
694
|
+
return codeSamples.reduce((extracted, item) => {
|
|
695
|
+
if (json.isPlainObject(item) && isString__default["default"](item['lang']) && isString__default["default"](item['source'])) {
|
|
696
|
+
const lib = isString__default["default"](item['lib']) ? item['lib'] : undefined;
|
|
697
|
+
const label = isString__default["default"](item['label']) ? item['label'] : lib !== null && lib !== void 0 ? lib : item['lang'];
|
|
698
|
+
extracted.push({
|
|
699
|
+
lang: item['lang'],
|
|
700
|
+
lib,
|
|
701
|
+
label,
|
|
702
|
+
source: item['source'],
|
|
703
|
+
});
|
|
704
|
+
}
|
|
705
|
+
return extracted;
|
|
706
|
+
}, []);
|
|
707
|
+
};
|
|
708
|
+
|
|
680
709
|
const persistAtom = (key, atomInstance) => {
|
|
681
710
|
if (typeof window === 'undefined' || window.localStorage === undefined) {
|
|
682
711
|
return atomInstance;
|
|
@@ -882,76 +911,149 @@ const requestSampleConfigs = {
|
|
|
882
911
|
mosaicCodeViewerLanguage: 'swift',
|
|
883
912
|
httpSnippetLanguage: 'swift',
|
|
884
913
|
},
|
|
885
|
-
};
|
|
886
|
-
const getConfigFor = (language, library) => {
|
|
887
|
-
var _a;
|
|
888
|
-
const languageConfig = requestSampleConfigs[language];
|
|
889
|
-
const libraryConfig = ((_a = languageConfig.libraries) === null || _a === void 0 ? void 0 : _a[library]) || {};
|
|
890
|
-
return Object.assign(Object.assign({}, languageConfig), libraryConfig);
|
|
891
914
|
};
|
|
892
915
|
|
|
893
|
-
const selectedLanguageAtom = persistAtom('RequestSamples_selectedLanguage', jotai.atom('
|
|
894
|
-
const selectedLibraryAtom = persistAtom('RequestSamples_selectedLibrary', jotai.atom('
|
|
916
|
+
const selectedLanguageAtom = persistAtom('RequestSamples_selectedLanguage', jotai.atom('shell'));
|
|
917
|
+
const selectedLibraryAtom = persistAtom('RequestSamples_selectedLibrary', jotai.atom('curl'));
|
|
895
918
|
const fallbackText = 'Unable to generate code example';
|
|
896
|
-
const RequestSamples =
|
|
919
|
+
const RequestSamples = React.memo(({ request, embeddedInMd = false, customCodeSamples = [] }) => {
|
|
897
920
|
const [selectedLanguage, setSelectedLanguage] = jotai.useAtom(selectedLanguageAtom);
|
|
898
921
|
const [selectedLibrary, setSelectedLibrary] = jotai.useAtom(selectedLibraryAtom);
|
|
899
|
-
const
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
.
|
|
905
|
-
|
|
906
|
-
|
|
922
|
+
const allRequestSamples = React.useMemo(() => {
|
|
923
|
+
var _a;
|
|
924
|
+
const requestSamples = cloneDeep__default["default"](requestSampleConfigs);
|
|
925
|
+
Object.entries(requestSamples).forEach(([languageKey, value]) => {
|
|
926
|
+
var _a;
|
|
927
|
+
value.displayText = languageKey;
|
|
928
|
+
Object.entries(((_a = value.libraries) !== null && _a !== void 0 ? _a : (value.libraries = {}))).forEach(([libKey, value]) => {
|
|
929
|
+
value.displayText = `${languageKey} / ${libKey}`;
|
|
930
|
+
});
|
|
931
|
+
});
|
|
932
|
+
for (const customCodeSample of customCodeSamples) {
|
|
933
|
+
const existingLanguageSampleKey = findKey__default["default"](requestSamples, {
|
|
934
|
+
httpSnippetLanguage: customCodeSample.lang.toLowerCase(),
|
|
935
|
+
});
|
|
936
|
+
const existingLanguageSample = requestSamples[existingLanguageSampleKey];
|
|
937
|
+
if (!existingLanguageSample) {
|
|
938
|
+
const newLanguageSample = {
|
|
939
|
+
displayText: customCodeSample.lang,
|
|
940
|
+
mosaicCodeViewerLanguage: customCodeSample.lang,
|
|
941
|
+
httpSnippetLanguage: customCodeSample.lang,
|
|
942
|
+
libraries: {},
|
|
943
|
+
};
|
|
944
|
+
if (customCodeSample.lib) {
|
|
945
|
+
newLanguageSample.libraries[customCodeSample.lib] = {
|
|
946
|
+
displayText: `${customCodeSample.lang} / ${customCodeSample.lib}`,
|
|
947
|
+
httpSnippetLibrary: customCodeSample.lib,
|
|
948
|
+
sampleCode: customCodeSample.source,
|
|
949
|
+
};
|
|
950
|
+
}
|
|
951
|
+
else {
|
|
952
|
+
newLanguageSample.sampleCode = customCodeSample.source;
|
|
953
|
+
}
|
|
954
|
+
requestSamples[customCodeSample.label] = newLanguageSample;
|
|
907
955
|
}
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
956
|
+
else {
|
|
957
|
+
(_a = existingLanguageSample.libraries) !== null && _a !== void 0 ? _a : (existingLanguageSample.libraries = {});
|
|
958
|
+
if (customCodeSample.lib) {
|
|
959
|
+
const existingLibrarySampleKey = findKey__default["default"](existingLanguageSample.libraries, {
|
|
960
|
+
httpSnippetLibrary: customCodeSample.lib,
|
|
961
|
+
});
|
|
962
|
+
const existingLibrarySample = existingLanguageSample.libraries[existingLibrarySampleKey];
|
|
963
|
+
if (!existingLibrarySample) {
|
|
964
|
+
const newLibrarySample = {
|
|
965
|
+
displayText: `${existingLanguageSample} / ${customCodeSample.lib}`,
|
|
966
|
+
httpSnippetLibrary: customCodeSample.lib,
|
|
967
|
+
sampleCode: customCodeSample.source,
|
|
968
|
+
};
|
|
969
|
+
existingLanguageSample.libraries[customCodeSample.lib] = newLibrarySample;
|
|
970
|
+
}
|
|
971
|
+
else {
|
|
972
|
+
existingLibrarySample.displayText = `${existingLanguageSampleKey} / ${existingLibrarySampleKey}`;
|
|
973
|
+
existingLibrarySample.sampleCode = customCodeSample.source;
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
else {
|
|
977
|
+
existingLanguageSample.sampleCode = customCodeSample.source;
|
|
978
|
+
}
|
|
912
979
|
}
|
|
913
|
-
}
|
|
914
|
-
return
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
const hasLibraries =
|
|
980
|
+
}
|
|
981
|
+
return requestSamples;
|
|
982
|
+
}, [customCodeSamples]);
|
|
983
|
+
const [menuItems, selectedSampleConfig] = React.useMemo(() => {
|
|
984
|
+
var _a, _b;
|
|
985
|
+
const items = Object.entries(allRequestSamples).map(([languageLabel, languageConfig]) => {
|
|
986
|
+
var _a;
|
|
987
|
+
const hasLibraries = Object.keys((_a = languageConfig.libraries) !== null && _a !== void 0 ? _a : {}).length > 0;
|
|
921
988
|
return {
|
|
922
|
-
id:
|
|
923
|
-
title:
|
|
924
|
-
isChecked: selectedLanguage ===
|
|
989
|
+
id: languageLabel,
|
|
990
|
+
title: languageLabel,
|
|
991
|
+
isChecked: selectedLanguage === languageConfig.httpSnippetLanguage,
|
|
992
|
+
closeOnPress: !hasLibraries,
|
|
925
993
|
onPress: hasLibraries
|
|
926
994
|
? undefined
|
|
927
995
|
: () => {
|
|
928
|
-
setSelectedLanguage(
|
|
996
|
+
setSelectedLanguage(languageConfig.httpSnippetLanguage);
|
|
929
997
|
setSelectedLibrary('');
|
|
930
998
|
},
|
|
931
|
-
children:
|
|
932
|
-
? Object.
|
|
933
|
-
id: `${
|
|
934
|
-
title:
|
|
935
|
-
isChecked: selectedLanguage ===
|
|
999
|
+
children: hasLibraries
|
|
1000
|
+
? Object.entries(languageConfig.libraries).map(([libraryLabel, libraryConfig]) => ({
|
|
1001
|
+
id: `${languageLabel}-${libraryLabel}`,
|
|
1002
|
+
title: libraryLabel,
|
|
1003
|
+
isChecked: selectedLanguage === languageConfig.httpSnippetLanguage &&
|
|
1004
|
+
selectedLibrary === libraryConfig.httpSnippetLibrary,
|
|
936
1005
|
onPress: () => {
|
|
937
|
-
setSelectedLanguage(
|
|
938
|
-
setSelectedLibrary(
|
|
1006
|
+
setSelectedLanguage(languageConfig.httpSnippetLanguage);
|
|
1007
|
+
setSelectedLibrary(libraryConfig.httpSnippetLibrary);
|
|
939
1008
|
},
|
|
940
1009
|
}))
|
|
941
1010
|
: undefined,
|
|
942
1011
|
};
|
|
943
1012
|
});
|
|
944
|
-
|
|
945
|
-
|
|
1013
|
+
const selectedLanguageSample = find__default["default"](allRequestSamples, { httpSnippetLanguage: selectedLanguage });
|
|
1014
|
+
const selectedLibrarySample = find__default["default"]((_a = selectedLanguageSample === null || selectedLanguageSample === void 0 ? void 0 : selectedLanguageSample.libraries) !== null && _a !== void 0 ? _a : {}, {
|
|
1015
|
+
httpSnippetLibrary: selectedLibrary,
|
|
1016
|
+
});
|
|
1017
|
+
return [
|
|
1018
|
+
items,
|
|
1019
|
+
Object.assign(Object.assign(Object.assign({}, selectedLibrarySample), selectedLanguageSample), { displayText: (_b = selectedLibrarySample === null || selectedLibrarySample === void 0 ? void 0 : selectedLibrarySample.displayText) !== null && _b !== void 0 ? _b : selectedLanguageSample === null || selectedLanguageSample === void 0 ? void 0 : selectedLanguageSample.displayText }),
|
|
1020
|
+
];
|
|
1021
|
+
}, [allRequestSamples, selectedLanguage, selectedLibrary, setSelectedLanguage, setSelectedLibrary]);
|
|
1022
|
+
const [requestSample, setRequestSample] = React.useState(null);
|
|
1023
|
+
React.useEffect(() => {
|
|
1024
|
+
let isStale = false;
|
|
1025
|
+
if (selectedSampleConfig) {
|
|
1026
|
+
if (selectedSampleConfig.sampleCode) {
|
|
1027
|
+
setRequestSample(selectedSampleConfig.sampleCode);
|
|
1028
|
+
}
|
|
1029
|
+
else {
|
|
1030
|
+
convertRequestToSample(selectedSampleConfig.httpSnippetLanguage, selectedSampleConfig.httpSnippetLibrary, request)
|
|
1031
|
+
.then(example => {
|
|
1032
|
+
if (!isStale) {
|
|
1033
|
+
setRequestSample(example);
|
|
1034
|
+
}
|
|
1035
|
+
})
|
|
1036
|
+
.catch(() => {
|
|
1037
|
+
if (!isStale) {
|
|
1038
|
+
setRequestSample(fallbackText);
|
|
1039
|
+
}
|
|
1040
|
+
});
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
else {
|
|
1044
|
+
setRequestSample(fallbackText);
|
|
1045
|
+
}
|
|
1046
|
+
return () => {
|
|
1047
|
+
isStale = true;
|
|
1048
|
+
};
|
|
1049
|
+
}, [request, selectedSampleConfig]);
|
|
946
1050
|
return (React__default["default"].createElement(mosaic.Panel, { rounded: embeddedInMd ? undefined : true, isCollapsible: embeddedInMd },
|
|
947
1051
|
React__default["default"].createElement(mosaic.Panel.Titlebar, { rightComponent: React__default["default"].createElement(mosaic.CopyButton, { size: "sm", copyValue: requestSample || '' }) },
|
|
948
1052
|
React__default["default"].createElement(mosaic.Box, { ml: -2 },
|
|
949
1053
|
React__default["default"].createElement(mosaic.Menu, { "aria-label": "Request Sample Language", closeOnPress: true, items: menuItems, renderTrigger: ({ isOpen }) => (React__default["default"].createElement(mosaic.Button, { size: "sm", iconRight: "chevron-down", appearance: "minimal", active: isOpen },
|
|
950
1054
|
"Request Sample: ",
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
selectedLibrary ? ` / ${selectedLibrary}` : '')) }))),
|
|
954
|
-
React__default["default"].createElement(mosaic.Panel.Content, { p: 0 }, requestSample !== null && (React__default["default"].createElement(mosaicCodeViewer.CodeViewer, { "aria-label": requestSample, noCopyButton: true, maxHeight: "400px", language: mosaicCodeViewerLanguage, value: requestSample, style: embeddedInMd
|
|
1055
|
+
selectedSampleConfig.displayText)) }))),
|
|
1056
|
+
React__default["default"].createElement(mosaic.Panel.Content, { p: 0 }, requestSample !== null && (React__default["default"].createElement(mosaicCodeViewer.CodeViewer, { "aria-label": requestSample, noCopyButton: true, maxHeight: "400px", language: selectedSampleConfig === null || selectedSampleConfig === void 0 ? void 0 : selectedSampleConfig.mosaicCodeViewerLanguage, value: requestSample, style: embeddedInMd
|
|
955
1057
|
? undefined
|
|
956
1058
|
:
|
|
957
1059
|
{
|
|
@@ -2215,6 +2317,7 @@ const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embe
|
|
|
2215
2317
|
const { serverVariables: serverVariableValues, updateServerVariableValue } = useServerVariables();
|
|
2216
2318
|
const isMockingEnabled = mockUrl && (chosenServer === null || chosenServer === void 0 ? void 0 : chosenServer.url) === mockUrl;
|
|
2217
2319
|
const hasRequiredButEmptyParameters = allParameters.some(parameter => parameter.required && !parameterValuesWithDefaults[parameter.name]);
|
|
2320
|
+
const customCodeSamples = extractCodeSamples(httpOperation);
|
|
2218
2321
|
const getValues = () => Object.keys(bodyParameterValues)
|
|
2219
2322
|
.filter(param => { var _a; return (_a = !isAllowedEmptyValues[param]) !== null && _a !== void 0 ? _a : true; })
|
|
2220
2323
|
.reduce((previousValue, currentValue) => {
|
|
@@ -2344,11 +2447,11 @@ const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embe
|
|
|
2344
2447
|
tryItPanelContents));
|
|
2345
2448
|
}
|
|
2346
2449
|
else {
|
|
2347
|
-
tryItPanelElem = (React__namespace.createElement(mosaic.Box, { className: "TryItPanel", bg: "canvas-100"
|
|
2450
|
+
tryItPanelElem = (React__namespace.createElement(mosaic.Box, { className: "TryItPanel", bg: "canvas-100" }, tryItPanelContents));
|
|
2348
2451
|
}
|
|
2349
2452
|
return (React__namespace.createElement(mosaic.Box, { rounded: "lg", overflowY: "hidden" },
|
|
2350
2453
|
tryItPanelElem,
|
|
2351
|
-
requestData && embeddedInMd && React__namespace.createElement(RequestSamples, { request: requestData, embeddedInMd: true }),
|
|
2454
|
+
requestData && embeddedInMd && (React__namespace.createElement(RequestSamples, { request: requestData, customCodeSamples: customCodeSamples, embeddedInMd: true })),
|
|
2352
2455
|
response && !('error' in response) && React__namespace.createElement(TryItResponse, { response: response }),
|
|
2353
2456
|
response && 'error' in response && React__namespace.createElement(ResponseError, { state: response })));
|
|
2354
2457
|
};
|
|
@@ -2392,11 +2495,12 @@ const ResponseExamples = ({ httpOperation, responseMediaType, responseStatusCode
|
|
|
2392
2495
|
const TryItWithRequestSamples = (_a) => {
|
|
2393
2496
|
var { hideTryIt } = _a, props = tslib.__rest(_a, ["hideTryIt"]);
|
|
2394
2497
|
const [requestData, setRequestData] = React__namespace.useState();
|
|
2498
|
+
const customCodeSamples = extractCodeSamples(props.httpOperation);
|
|
2395
2499
|
return (React__namespace.createElement(mosaic.VStack, { spacing: 6 },
|
|
2396
2500
|
!hideTryIt && (React__namespace.createElement(mosaic.InvertTheme, null,
|
|
2397
2501
|
React__namespace.createElement(mosaic.Box, null,
|
|
2398
2502
|
React__namespace.createElement(TryIt, Object.assign({}, props, { onRequestChange: setRequestData }))))),
|
|
2399
|
-
requestData && React__namespace.createElement(RequestSamples, { request: requestData }),
|
|
2503
|
+
requestData && React__namespace.createElement(RequestSamples, { request: requestData, customCodeSamples: customCodeSamples }),
|
|
2400
2504
|
React__namespace.createElement(ResponseExamples, Object.assign({}, props))));
|
|
2401
2505
|
};
|
|
2402
2506
|
|
package/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { __rest, __awaiter } from 'tslib';
|
|
2
2
|
import * as React from 'react';
|
|
3
|
-
import React__default, { useContext, useMemo } from 'react';
|
|
3
|
+
import React__default, { useContext, memo, useMemo, useState, useEffect } from 'react';
|
|
4
4
|
import { convertToJsonSchema } from '@stoplight/http-spec/oas';
|
|
5
5
|
import { resolveInlineRef, hasRef, isPlainObject as isPlainObject$1, safeParse, safeStringify } from '@stoplight/json';
|
|
6
6
|
import isArray from 'lodash/isArray.js';
|
|
@@ -17,7 +17,11 @@ import cn from 'classnames';
|
|
|
17
17
|
import { atomWithStorage, useAtomValue } from 'jotai/utils';
|
|
18
18
|
import { atom, useAtom, Provider } from 'jotai';
|
|
19
19
|
import URI from 'urijs';
|
|
20
|
+
import isString from 'lodash/isString.js';
|
|
20
21
|
import { CodeViewer } from '@stoplight/mosaic-code-viewer';
|
|
22
|
+
import cloneDeep from 'lodash/cloneDeep.js';
|
|
23
|
+
import find from 'lodash/find.js';
|
|
24
|
+
import findKey from 'lodash/findKey.js';
|
|
21
25
|
import { isValidTargetId, HTTPSnippet } from 'httpsnippet-lite';
|
|
22
26
|
import { hash } from '@stoplight/http-spec/hash';
|
|
23
27
|
import capitalize from 'lodash/capitalize.js';
|
|
@@ -32,7 +36,6 @@ import keyBy from 'lodash/keyBy.js';
|
|
|
32
36
|
import last from 'lodash/last.js';
|
|
33
37
|
import map from 'lodash/map.js';
|
|
34
38
|
import mapValues from 'lodash/mapValues.js';
|
|
35
|
-
import isString from 'lodash/isString.js';
|
|
36
39
|
import pickBy from 'lodash/pickBy.js';
|
|
37
40
|
import { CodeEditor } from '@stoplight/mosaic-code-editor';
|
|
38
41
|
import * as Sampler from '@stoplight/json-schema-sampler';
|
|
@@ -620,6 +623,29 @@ const getServerUrlWithVariableValues = (server, values) => {
|
|
|
620
623
|
return urlString;
|
|
621
624
|
};
|
|
622
625
|
|
|
626
|
+
const extractCodeSamples = (obj) => {
|
|
627
|
+
if (!isPlainObject$1(obj) || !isPlainObject$1(obj.extensions)) {
|
|
628
|
+
return [];
|
|
629
|
+
}
|
|
630
|
+
const codeSamples = obj.extensions['x-codeSamples'];
|
|
631
|
+
if (!Array.isArray(codeSamples)) {
|
|
632
|
+
return [];
|
|
633
|
+
}
|
|
634
|
+
return codeSamples.reduce((extracted, item) => {
|
|
635
|
+
if (isPlainObject$1(item) && isString(item['lang']) && isString(item['source'])) {
|
|
636
|
+
const lib = isString(item['lib']) ? item['lib'] : undefined;
|
|
637
|
+
const label = isString(item['label']) ? item['label'] : lib !== null && lib !== void 0 ? lib : item['lang'];
|
|
638
|
+
extracted.push({
|
|
639
|
+
lang: item['lang'],
|
|
640
|
+
lib,
|
|
641
|
+
label,
|
|
642
|
+
source: item['source'],
|
|
643
|
+
});
|
|
644
|
+
}
|
|
645
|
+
return extracted;
|
|
646
|
+
}, []);
|
|
647
|
+
};
|
|
648
|
+
|
|
623
649
|
const persistAtom = (key, atomInstance) => {
|
|
624
650
|
if (typeof window === 'undefined' || window.localStorage === undefined) {
|
|
625
651
|
return atomInstance;
|
|
@@ -825,76 +851,149 @@ const requestSampleConfigs = {
|
|
|
825
851
|
mosaicCodeViewerLanguage: 'swift',
|
|
826
852
|
httpSnippetLanguage: 'swift',
|
|
827
853
|
},
|
|
828
|
-
};
|
|
829
|
-
const getConfigFor = (language, library) => {
|
|
830
|
-
var _a;
|
|
831
|
-
const languageConfig = requestSampleConfigs[language];
|
|
832
|
-
const libraryConfig = ((_a = languageConfig.libraries) === null || _a === void 0 ? void 0 : _a[library]) || {};
|
|
833
|
-
return Object.assign(Object.assign({}, languageConfig), libraryConfig);
|
|
834
854
|
};
|
|
835
855
|
|
|
836
|
-
const selectedLanguageAtom = persistAtom('RequestSamples_selectedLanguage', atom('
|
|
837
|
-
const selectedLibraryAtom = persistAtom('RequestSamples_selectedLibrary', atom('
|
|
856
|
+
const selectedLanguageAtom = persistAtom('RequestSamples_selectedLanguage', atom('shell'));
|
|
857
|
+
const selectedLibraryAtom = persistAtom('RequestSamples_selectedLibrary', atom('curl'));
|
|
838
858
|
const fallbackText = 'Unable to generate code example';
|
|
839
|
-
const RequestSamples =
|
|
859
|
+
const RequestSamples = memo(({ request, embeddedInMd = false, customCodeSamples = [] }) => {
|
|
840
860
|
const [selectedLanguage, setSelectedLanguage] = useAtom(selectedLanguageAtom);
|
|
841
861
|
const [selectedLibrary, setSelectedLibrary] = useAtom(selectedLibraryAtom);
|
|
842
|
-
const
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
.
|
|
848
|
-
|
|
849
|
-
|
|
862
|
+
const allRequestSamples = useMemo(() => {
|
|
863
|
+
var _a;
|
|
864
|
+
const requestSamples = cloneDeep(requestSampleConfigs);
|
|
865
|
+
Object.entries(requestSamples).forEach(([languageKey, value]) => {
|
|
866
|
+
var _a;
|
|
867
|
+
value.displayText = languageKey;
|
|
868
|
+
Object.entries(((_a = value.libraries) !== null && _a !== void 0 ? _a : (value.libraries = {}))).forEach(([libKey, value]) => {
|
|
869
|
+
value.displayText = `${languageKey} / ${libKey}`;
|
|
870
|
+
});
|
|
871
|
+
});
|
|
872
|
+
for (const customCodeSample of customCodeSamples) {
|
|
873
|
+
const existingLanguageSampleKey = findKey(requestSamples, {
|
|
874
|
+
httpSnippetLanguage: customCodeSample.lang.toLowerCase(),
|
|
875
|
+
});
|
|
876
|
+
const existingLanguageSample = requestSamples[existingLanguageSampleKey];
|
|
877
|
+
if (!existingLanguageSample) {
|
|
878
|
+
const newLanguageSample = {
|
|
879
|
+
displayText: customCodeSample.lang,
|
|
880
|
+
mosaicCodeViewerLanguage: customCodeSample.lang,
|
|
881
|
+
httpSnippetLanguage: customCodeSample.lang,
|
|
882
|
+
libraries: {},
|
|
883
|
+
};
|
|
884
|
+
if (customCodeSample.lib) {
|
|
885
|
+
newLanguageSample.libraries[customCodeSample.lib] = {
|
|
886
|
+
displayText: `${customCodeSample.lang} / ${customCodeSample.lib}`,
|
|
887
|
+
httpSnippetLibrary: customCodeSample.lib,
|
|
888
|
+
sampleCode: customCodeSample.source,
|
|
889
|
+
};
|
|
890
|
+
}
|
|
891
|
+
else {
|
|
892
|
+
newLanguageSample.sampleCode = customCodeSample.source;
|
|
893
|
+
}
|
|
894
|
+
requestSamples[customCodeSample.label] = newLanguageSample;
|
|
850
895
|
}
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
896
|
+
else {
|
|
897
|
+
(_a = existingLanguageSample.libraries) !== null && _a !== void 0 ? _a : (existingLanguageSample.libraries = {});
|
|
898
|
+
if (customCodeSample.lib) {
|
|
899
|
+
const existingLibrarySampleKey = findKey(existingLanguageSample.libraries, {
|
|
900
|
+
httpSnippetLibrary: customCodeSample.lib,
|
|
901
|
+
});
|
|
902
|
+
const existingLibrarySample = existingLanguageSample.libraries[existingLibrarySampleKey];
|
|
903
|
+
if (!existingLibrarySample) {
|
|
904
|
+
const newLibrarySample = {
|
|
905
|
+
displayText: `${existingLanguageSample} / ${customCodeSample.lib}`,
|
|
906
|
+
httpSnippetLibrary: customCodeSample.lib,
|
|
907
|
+
sampleCode: customCodeSample.source,
|
|
908
|
+
};
|
|
909
|
+
existingLanguageSample.libraries[customCodeSample.lib] = newLibrarySample;
|
|
910
|
+
}
|
|
911
|
+
else {
|
|
912
|
+
existingLibrarySample.displayText = `${existingLanguageSampleKey} / ${existingLibrarySampleKey}`;
|
|
913
|
+
existingLibrarySample.sampleCode = customCodeSample.source;
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
else {
|
|
917
|
+
existingLanguageSample.sampleCode = customCodeSample.source;
|
|
918
|
+
}
|
|
855
919
|
}
|
|
856
|
-
}
|
|
857
|
-
return
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
const hasLibraries =
|
|
920
|
+
}
|
|
921
|
+
return requestSamples;
|
|
922
|
+
}, [customCodeSamples]);
|
|
923
|
+
const [menuItems, selectedSampleConfig] = useMemo(() => {
|
|
924
|
+
var _a, _b;
|
|
925
|
+
const items = Object.entries(allRequestSamples).map(([languageLabel, languageConfig]) => {
|
|
926
|
+
var _a;
|
|
927
|
+
const hasLibraries = Object.keys((_a = languageConfig.libraries) !== null && _a !== void 0 ? _a : {}).length > 0;
|
|
864
928
|
return {
|
|
865
|
-
id:
|
|
866
|
-
title:
|
|
867
|
-
isChecked: selectedLanguage ===
|
|
929
|
+
id: languageLabel,
|
|
930
|
+
title: languageLabel,
|
|
931
|
+
isChecked: selectedLanguage === languageConfig.httpSnippetLanguage,
|
|
932
|
+
closeOnPress: !hasLibraries,
|
|
868
933
|
onPress: hasLibraries
|
|
869
934
|
? undefined
|
|
870
935
|
: () => {
|
|
871
|
-
setSelectedLanguage(
|
|
936
|
+
setSelectedLanguage(languageConfig.httpSnippetLanguage);
|
|
872
937
|
setSelectedLibrary('');
|
|
873
938
|
},
|
|
874
|
-
children:
|
|
875
|
-
? Object.
|
|
876
|
-
id: `${
|
|
877
|
-
title:
|
|
878
|
-
isChecked: selectedLanguage ===
|
|
939
|
+
children: hasLibraries
|
|
940
|
+
? Object.entries(languageConfig.libraries).map(([libraryLabel, libraryConfig]) => ({
|
|
941
|
+
id: `${languageLabel}-${libraryLabel}`,
|
|
942
|
+
title: libraryLabel,
|
|
943
|
+
isChecked: selectedLanguage === languageConfig.httpSnippetLanguage &&
|
|
944
|
+
selectedLibrary === libraryConfig.httpSnippetLibrary,
|
|
879
945
|
onPress: () => {
|
|
880
|
-
setSelectedLanguage(
|
|
881
|
-
setSelectedLibrary(
|
|
946
|
+
setSelectedLanguage(languageConfig.httpSnippetLanguage);
|
|
947
|
+
setSelectedLibrary(libraryConfig.httpSnippetLibrary);
|
|
882
948
|
},
|
|
883
949
|
}))
|
|
884
950
|
: undefined,
|
|
885
951
|
};
|
|
886
952
|
});
|
|
887
|
-
|
|
888
|
-
|
|
953
|
+
const selectedLanguageSample = find(allRequestSamples, { httpSnippetLanguage: selectedLanguage });
|
|
954
|
+
const selectedLibrarySample = find((_a = selectedLanguageSample === null || selectedLanguageSample === void 0 ? void 0 : selectedLanguageSample.libraries) !== null && _a !== void 0 ? _a : {}, {
|
|
955
|
+
httpSnippetLibrary: selectedLibrary,
|
|
956
|
+
});
|
|
957
|
+
return [
|
|
958
|
+
items,
|
|
959
|
+
Object.assign(Object.assign(Object.assign({}, selectedLibrarySample), selectedLanguageSample), { displayText: (_b = selectedLibrarySample === null || selectedLibrarySample === void 0 ? void 0 : selectedLibrarySample.displayText) !== null && _b !== void 0 ? _b : selectedLanguageSample === null || selectedLanguageSample === void 0 ? void 0 : selectedLanguageSample.displayText }),
|
|
960
|
+
];
|
|
961
|
+
}, [allRequestSamples, selectedLanguage, selectedLibrary, setSelectedLanguage, setSelectedLibrary]);
|
|
962
|
+
const [requestSample, setRequestSample] = useState(null);
|
|
963
|
+
useEffect(() => {
|
|
964
|
+
let isStale = false;
|
|
965
|
+
if (selectedSampleConfig) {
|
|
966
|
+
if (selectedSampleConfig.sampleCode) {
|
|
967
|
+
setRequestSample(selectedSampleConfig.sampleCode);
|
|
968
|
+
}
|
|
969
|
+
else {
|
|
970
|
+
convertRequestToSample(selectedSampleConfig.httpSnippetLanguage, selectedSampleConfig.httpSnippetLibrary, request)
|
|
971
|
+
.then(example => {
|
|
972
|
+
if (!isStale) {
|
|
973
|
+
setRequestSample(example);
|
|
974
|
+
}
|
|
975
|
+
})
|
|
976
|
+
.catch(() => {
|
|
977
|
+
if (!isStale) {
|
|
978
|
+
setRequestSample(fallbackText);
|
|
979
|
+
}
|
|
980
|
+
});
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
else {
|
|
984
|
+
setRequestSample(fallbackText);
|
|
985
|
+
}
|
|
986
|
+
return () => {
|
|
987
|
+
isStale = true;
|
|
988
|
+
};
|
|
989
|
+
}, [request, selectedSampleConfig]);
|
|
889
990
|
return (React__default.createElement(Panel, { rounded: embeddedInMd ? undefined : true, isCollapsible: embeddedInMd },
|
|
890
991
|
React__default.createElement(Panel.Titlebar, { rightComponent: React__default.createElement(CopyButton, { size: "sm", copyValue: requestSample || '' }) },
|
|
891
992
|
React__default.createElement(Box, { ml: -2 },
|
|
892
993
|
React__default.createElement(Menu, { "aria-label": "Request Sample Language", closeOnPress: true, items: menuItems, renderTrigger: ({ isOpen }) => (React__default.createElement(Button, { size: "sm", iconRight: "chevron-down", appearance: "minimal", active: isOpen },
|
|
893
994
|
"Request Sample: ",
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
selectedLibrary ? ` / ${selectedLibrary}` : '')) }))),
|
|
897
|
-
React__default.createElement(Panel.Content, { p: 0 }, requestSample !== null && (React__default.createElement(CodeViewer, { "aria-label": requestSample, noCopyButton: true, maxHeight: "400px", language: mosaicCodeViewerLanguage, value: requestSample, style: embeddedInMd
|
|
995
|
+
selectedSampleConfig.displayText)) }))),
|
|
996
|
+
React__default.createElement(Panel.Content, { p: 0 }, requestSample !== null && (React__default.createElement(CodeViewer, { "aria-label": requestSample, noCopyButton: true, maxHeight: "400px", language: selectedSampleConfig === null || selectedSampleConfig === void 0 ? void 0 : selectedSampleConfig.mosaicCodeViewerLanguage, value: requestSample, style: embeddedInMd
|
|
898
997
|
? undefined
|
|
899
998
|
:
|
|
900
999
|
{
|
|
@@ -2158,6 +2257,7 @@ const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embe
|
|
|
2158
2257
|
const { serverVariables: serverVariableValues, updateServerVariableValue } = useServerVariables();
|
|
2159
2258
|
const isMockingEnabled = mockUrl && (chosenServer === null || chosenServer === void 0 ? void 0 : chosenServer.url) === mockUrl;
|
|
2160
2259
|
const hasRequiredButEmptyParameters = allParameters.some(parameter => parameter.required && !parameterValuesWithDefaults[parameter.name]);
|
|
2260
|
+
const customCodeSamples = extractCodeSamples(httpOperation);
|
|
2161
2261
|
const getValues = () => Object.keys(bodyParameterValues)
|
|
2162
2262
|
.filter(param => { var _a; return (_a = !isAllowedEmptyValues[param]) !== null && _a !== void 0 ? _a : true; })
|
|
2163
2263
|
.reduce((previousValue, currentValue) => {
|
|
@@ -2287,11 +2387,11 @@ const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embe
|
|
|
2287
2387
|
tryItPanelContents));
|
|
2288
2388
|
}
|
|
2289
2389
|
else {
|
|
2290
|
-
tryItPanelElem = (React.createElement(Box, { className: "TryItPanel", bg: "canvas-100"
|
|
2390
|
+
tryItPanelElem = (React.createElement(Box, { className: "TryItPanel", bg: "canvas-100" }, tryItPanelContents));
|
|
2291
2391
|
}
|
|
2292
2392
|
return (React.createElement(Box, { rounded: "lg", overflowY: "hidden" },
|
|
2293
2393
|
tryItPanelElem,
|
|
2294
|
-
requestData && embeddedInMd && React.createElement(RequestSamples, { request: requestData, embeddedInMd: true }),
|
|
2394
|
+
requestData && embeddedInMd && (React.createElement(RequestSamples, { request: requestData, customCodeSamples: customCodeSamples, embeddedInMd: true })),
|
|
2295
2395
|
response && !('error' in response) && React.createElement(TryItResponse, { response: response }),
|
|
2296
2396
|
response && 'error' in response && React.createElement(ResponseError, { state: response })));
|
|
2297
2397
|
};
|
|
@@ -2335,11 +2435,12 @@ const ResponseExamples = ({ httpOperation, responseMediaType, responseStatusCode
|
|
|
2335
2435
|
const TryItWithRequestSamples = (_a) => {
|
|
2336
2436
|
var { hideTryIt } = _a, props = __rest(_a, ["hideTryIt"]);
|
|
2337
2437
|
const [requestData, setRequestData] = React.useState();
|
|
2438
|
+
const customCodeSamples = extractCodeSamples(props.httpOperation);
|
|
2338
2439
|
return (React.createElement(VStack, { spacing: 6 },
|
|
2339
2440
|
!hideTryIt && (React.createElement(InvertTheme, null,
|
|
2340
2441
|
React.createElement(Box, null,
|
|
2341
2442
|
React.createElement(TryIt, Object.assign({}, props, { onRequestChange: setRequestData }))))),
|
|
2342
|
-
requestData && React.createElement(RequestSamples, { request: requestData }),
|
|
2443
|
+
requestData && React.createElement(RequestSamples, { request: requestData, customCodeSamples: customCodeSamples }),
|
|
2343
2444
|
React.createElement(ResponseExamples, Object.assign({}, props))));
|
|
2344
2445
|
};
|
|
2345
2446
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stoplight/elements-core",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.2.0",
|
|
4
4
|
"main": "./index.js",
|
|
5
5
|
"sideEffects": [
|
|
6
6
|
"web-components.min.js",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"@stoplight/json-schema-ref-parser": "^9.0.5",
|
|
30
30
|
"@stoplight/json-schema-sampler": "0.2.3",
|
|
31
31
|
"@stoplight/json-schema-tree": "^4.0.0",
|
|
32
|
-
"@stoplight/json-schema-viewer": "
|
|
32
|
+
"@stoplight/json-schema-viewer": "4.16.1",
|
|
33
33
|
"@stoplight/markdown-viewer": "^5.7.0",
|
|
34
34
|
"@stoplight/mosaic": "^1.53.1",
|
|
35
35
|
"@stoplight/mosaic-code-editor": "^1.53.1",
|