@stoplight/elements-core 7.5.12 → 7.5.13
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/TryIt/Body/FormDataBody.d.ts +3 -1
- package/components/TryIt/Body/request-body-utils.d.ts +3 -2
- package/components/TryIt/Parameters/ParameterEditor.d.ts +3 -0
- package/core.css +10 -0
- package/index.esm.js +52 -18
- package/index.js +52 -18
- package/index.mjs +52 -18
- package/package.json +1 -1
- package/styles.min.css +1 -1
- package/utils/guards.d.ts +1 -1
- package/utils/http-spec/IServer.d.ts +1 -1
package/index.mjs
CHANGED
|
@@ -141,9 +141,9 @@ function isHttpService(maybeHttpService) {
|
|
|
141
141
|
function isHttpOperation(maybeHttpOperation) {
|
|
142
142
|
return isStoplightNode(maybeHttpOperation) && 'method' in maybeHttpOperation && 'path' in maybeHttpOperation;
|
|
143
143
|
}
|
|
144
|
+
const properUrl = new RegExp(/((([A-Za-z]{3,9}:(?:\/\/)?)(?:[\-;:&=\+\$,\w]+@)?[A-Za-z0-9\.\-]+|(?:www\.|[\-;:&=\+\$,\w]+@)[A-Za-z0-9\.\-]+)((?:\/[\+~%\/\.\w\-_]*)?\??(?:[\-\+=&;%@\.\w_]*)#?(?:[\.\!\/\\\w]*))?)/);
|
|
144
145
|
function isProperUrl(url) {
|
|
145
|
-
|
|
146
|
-
return url.match(properUrl);
|
|
146
|
+
return properUrl.test(url);
|
|
147
147
|
}
|
|
148
148
|
|
|
149
149
|
function useParsedData(nodeType, data) {
|
|
@@ -357,13 +357,16 @@ function createNamedContext(name, defaultValue) {
|
|
|
357
357
|
|
|
358
358
|
const chosenServerAtom = atom(undefined);
|
|
359
359
|
|
|
360
|
+
function isValidServer(server) {
|
|
361
|
+
return server.url !== null && isProperUrl(server.url);
|
|
362
|
+
}
|
|
360
363
|
const getServersToDisplay = (originalServers, mockUrl) => {
|
|
361
364
|
const servers = originalServers
|
|
362
365
|
.map((server, i) => {
|
|
363
366
|
const fallbackDescription = originalServers.length === 1 ? 'Live Server' : `Server ${i + 1}`;
|
|
364
367
|
return Object.assign(Object.assign({}, server), { url: getServerUrlWithDefaultValues(server), description: server.description || fallbackDescription });
|
|
365
368
|
})
|
|
366
|
-
.filter(
|
|
369
|
+
.filter(isValidServer);
|
|
367
370
|
if (mockUrl) {
|
|
368
371
|
servers.push({
|
|
369
372
|
description: 'Mock Server',
|
|
@@ -379,7 +382,13 @@ const getServerUrlWithDefaultValues = (server) => {
|
|
|
379
382
|
variables.forEach(([variableName, variableInfo]) => {
|
|
380
383
|
urlString = urlString.replace(`{${variableName}}`, variableInfo.default);
|
|
381
384
|
});
|
|
382
|
-
let url
|
|
385
|
+
let url;
|
|
386
|
+
try {
|
|
387
|
+
url = URI(urlString);
|
|
388
|
+
}
|
|
389
|
+
catch (_b) {
|
|
390
|
+
return null;
|
|
391
|
+
}
|
|
383
392
|
if (url.is('relative') && typeof window !== 'undefined') {
|
|
384
393
|
url = url.absoluteTo(window.location.origin);
|
|
385
394
|
}
|
|
@@ -969,9 +978,10 @@ function mapSchemaPropertiesToParameters(properties, required) {
|
|
|
969
978
|
return Object.entries(properties).map(([name, schema]) => (Object.assign({ name, schema: typeof schema !== 'boolean' ? schema : undefined, examples: typeof schema !== 'boolean' && schema.examples ? [{ key: 'example', value: schema.examples }] : undefined }, ((required === null || required === void 0 ? void 0 : required.includes(name)) && { required: true }))));
|
|
970
979
|
}
|
|
971
980
|
|
|
972
|
-
const ParameterEditor = ({ parameter, value, onChange, validate }) => {
|
|
981
|
+
const ParameterEditor = ({ parameter, value, onChange, isOptional, onChangeOptional, canChangeOptional, validate, }) => {
|
|
973
982
|
var _a, _b;
|
|
974
983
|
const inputId = useUniqueId(`id_${parameter.name}_`);
|
|
984
|
+
const inputCheckId = useUniqueId(`id_${parameter.name}_checked`);
|
|
975
985
|
const parameterValueOptions = parameterOptions(parameter);
|
|
976
986
|
const examples = exampleOptions(parameter);
|
|
977
987
|
const selectedExample = (_a = examples === null || examples === void 0 ? void 0 : examples.find(e => e.value === value)) !== null && _a !== void 0 ? _a : selectExampleOption;
|
|
@@ -982,10 +992,19 @@ const ParameterEditor = ({ parameter, value, onChange, validate }) => {
|
|
|
982
992
|
React.createElement(Text, { mx: 3 }, ":"),
|
|
983
993
|
React.createElement("div", null, parameterValueOptions ? (React.createElement(Select, { flex: 1, "aria-label": parameter.name, options: parameterValueOptions, value: value || '', onChange: onChange })) : (React.createElement(Flex, { flex: 1 },
|
|
984
994
|
React.createElement(Input, { id: inputId, "aria-label": parameter.name, appearance: requiredButEmpty ? 'default' : 'minimal', flex: 1, placeholder: getPlaceholderForParameter(parameter), type: ((_b = parameter.schema) === null || _b === void 0 ? void 0 : _b.type) === 'number' ? 'number' : 'text', required: true, intent: requiredButEmpty ? 'danger' : 'default', value: value || '', onChange: e => onChange && onChange(e.currentTarget.value) }),
|
|
985
|
-
examples && (React.createElement(Select, { "aria-label": `${parameter.name}-select`, flex: 1, value: selectedExample.value, options: examples, onChange: onChange })))))
|
|
995
|
+
examples && (React.createElement(Select, { "aria-label": `${parameter.name}-select`, flex: 1, value: selectedExample.value, options: examples, onChange: onChange }))))),
|
|
996
|
+
canChangeOptional && !parameter.required && (React.createElement(React.Fragment, null,
|
|
997
|
+
React.createElement("div", null),
|
|
998
|
+
React.createElement("div", null),
|
|
999
|
+
React.createElement("div", null,
|
|
1000
|
+
React.createElement(Flex, { flex: 1 },
|
|
1001
|
+
React.createElement(Input, { className: "Checkbox", "aria-label": `${parameter.name}-checkbox`, id: inputCheckId, flex: 1, type: "checkbox", intent: "success", size: "sm", checked: isOptional, onChange: e => onChangeOptional(!e.target.checked) }),
|
|
1002
|
+
React.createElement(Text, { className: "TextForCheckBox", flex: 1, as: "label", "aria-hidden": "true", "data-testid": "param-check", htmlFor: inputCheckId, fontSize: "base" },
|
|
1003
|
+
"Omit ",
|
|
1004
|
+
parameterDisplayName)))))));
|
|
986
1005
|
};
|
|
987
1006
|
|
|
988
|
-
const FormDataBody = ({ specification, values, onChangeValues }) => {
|
|
1007
|
+
const FormDataBody = ({ specification, values, onChangeValues, onChangeParameterAllow, isAllowedEmptyValues, }) => {
|
|
989
1008
|
const schema = specification.schema;
|
|
990
1009
|
const parameters = schema === null || schema === void 0 ? void 0 : schema.properties;
|
|
991
1010
|
const required = schema === null || schema === void 0 ? void 0 : schema.required;
|
|
@@ -1000,6 +1019,7 @@ const FormDataBody = ({ specification, values, onChangeValues }) => {
|
|
|
1000
1019
|
return (React.createElement(Panel, { defaultIsOpen: true },
|
|
1001
1020
|
React.createElement(Panel.Titlebar, null, "Body"),
|
|
1002
1021
|
React.createElement(Panel.Content, { className: "sl-overflow-y-auto ParameterGrid OperationParametersContent" }, mapSchemaPropertiesToParameters(parameters, required).map(parameter => {
|
|
1022
|
+
var _a;
|
|
1003
1023
|
const supportsFileUpload = parameterSupportsFileUpload(parameter);
|
|
1004
1024
|
const value = values[parameter.name];
|
|
1005
1025
|
if (supportsFileUpload) {
|
|
@@ -1007,7 +1027,7 @@ const FormDataBody = ({ specification, values, onChangeValues }) => {
|
|
|
1007
1027
|
? onChangeValues(Object.assign(Object.assign({}, values), { [parameter.name]: newValue }))
|
|
1008
1028
|
: onChangeValues(omit(values, parameter.name)) }));
|
|
1009
1029
|
}
|
|
1010
|
-
return (React.createElement(ParameterEditor, { key: parameter.name, parameter: parameter, value: typeof value === 'string' ? value : undefined, onChange: (value) => onChangeValues(Object.assign(Object.assign({}, values), { [parameter.name]: typeof value === 'number' ? String(value) : value })) }));
|
|
1030
|
+
return (React.createElement(ParameterEditor, { key: parameter.name, parameter: parameter, value: typeof value === 'string' ? value : undefined, onChange: (value) => onChangeValues(Object.assign(Object.assign({}, values), { [parameter.name]: typeof value === 'number' ? String(value) : value })), onChangeOptional: value => onChangeParameterAllow(Object.assign(Object.assign({}, isAllowedEmptyValues), { [parameter.name]: value })), canChangeOptional: true, isOptional: (_a = isAllowedEmptyValues[parameter.name]) !== null && _a !== void 0 ? _a : false }));
|
|
1011
1031
|
}))));
|
|
1012
1032
|
};
|
|
1013
1033
|
|
|
@@ -1081,6 +1101,7 @@ const useBodyParameterState = (mediaTypeContent) => {
|
|
|
1081
1101
|
return initialParameterValues(parameters);
|
|
1082
1102
|
}, [isFormDataBody, mediaTypeContent]);
|
|
1083
1103
|
const [bodyParameterValues, setBodyParameterValues] = React.useState(initialState);
|
|
1104
|
+
const [isAllowedEmptyValue, setAllowedEmptyValue] = React.useState({});
|
|
1084
1105
|
React.useEffect(() => {
|
|
1085
1106
|
setBodyParameterValues(initialState);
|
|
1086
1107
|
}, [initialState]);
|
|
@@ -1088,6 +1109,8 @@ const useBodyParameterState = (mediaTypeContent) => {
|
|
|
1088
1109
|
return [
|
|
1089
1110
|
bodyParameterValues,
|
|
1090
1111
|
setBodyParameterValues,
|
|
1112
|
+
isAllowedEmptyValue,
|
|
1113
|
+
setAllowedEmptyValue,
|
|
1091
1114
|
{ isFormDataBody: true, bodySpecification: mediaTypeContent },
|
|
1092
1115
|
];
|
|
1093
1116
|
}
|
|
@@ -1095,6 +1118,8 @@ const useBodyParameterState = (mediaTypeContent) => {
|
|
|
1095
1118
|
return [
|
|
1096
1119
|
bodyParameterValues,
|
|
1097
1120
|
setBodyParameterValues,
|
|
1121
|
+
isAllowedEmptyValue,
|
|
1122
|
+
setAllowedEmptyValue,
|
|
1098
1123
|
{ isFormDataBody: false, bodySpecification: undefined },
|
|
1099
1124
|
];
|
|
1100
1125
|
}
|
|
@@ -1231,14 +1256,14 @@ function buildFetchRequest({ httpOperation, mediaTypeContent, bodyInput, paramet
|
|
|
1231
1256
|
.filter(({ value }) => value.length > 0);
|
|
1232
1257
|
const [queryParamsWithAuth, headersWithAuth] = runAuthRequestEhancements(auth, queryParams, rawHeaders);
|
|
1233
1258
|
const expandedPath = uriExpand(httpOperation.path, parameterValues);
|
|
1234
|
-
const
|
|
1235
|
-
|
|
1259
|
+
const urlObject = new URL(serverUrl + expandedPath);
|
|
1260
|
+
urlObject.search = new URLSearchParams(queryParamsWithAuth.map(nameAndValueObjectToPair)).toString();
|
|
1236
1261
|
const body = typeof bodyInput === 'object' ? yield createRequestBody(mediaTypeContent, bodyInput) : bodyInput;
|
|
1237
1262
|
const headers = Object.assign(Object.assign(Object.assign({}, ((mediaTypeContent === null || mediaTypeContent === void 0 ? void 0 : mediaTypeContent.mediaType) !== 'multipart/form-data' && {
|
|
1238
1263
|
'Content-Type': (_f = mediaTypeContent === null || mediaTypeContent === void 0 ? void 0 : mediaTypeContent.mediaType) !== null && _f !== void 0 ? _f : 'application/json',
|
|
1239
1264
|
})), Object.fromEntries(headersWithAuth.map(nameAndValueObjectToPair))), mockData === null || mockData === void 0 ? void 0 : mockData.header);
|
|
1240
1265
|
return [
|
|
1241
|
-
|
|
1266
|
+
urlObject.href,
|
|
1242
1267
|
{
|
|
1243
1268
|
credentials,
|
|
1244
1269
|
method: httpOperation.method.toUpperCase(),
|
|
@@ -1306,7 +1331,8 @@ function buildHarRequest({ httpOperation, bodyInput, parameterValues, mediaTypeC
|
|
|
1306
1331
|
headerParams.push({ name: 'Prefer', value: mockData.header.Prefer });
|
|
1307
1332
|
}
|
|
1308
1333
|
const [queryParamsWithAuth, headerParamsWithAuth] = runAuthRequestEhancements(auth, queryParams, headerParams);
|
|
1309
|
-
const
|
|
1334
|
+
const expandedPath = uriExpand(httpOperation.path, parameterValues);
|
|
1335
|
+
const urlObject = new URL(serverUrl + expandedPath);
|
|
1310
1336
|
let postData = undefined;
|
|
1311
1337
|
if (shouldIncludeBody && typeof bodyInput === 'string') {
|
|
1312
1338
|
postData = { mimeType, text: bodyInput };
|
|
@@ -1331,7 +1357,7 @@ function buildHarRequest({ httpOperation, bodyInput, parameterValues, mediaTypeC
|
|
|
1331
1357
|
}
|
|
1332
1358
|
return {
|
|
1333
1359
|
method: httpOperation.method.toUpperCase(),
|
|
1334
|
-
url:
|
|
1360
|
+
url: urlObject.href,
|
|
1335
1361
|
httpVersion: 'HTTP/1.1',
|
|
1336
1362
|
cookies: [],
|
|
1337
1363
|
headers: [{ name: 'Content-Type', value: mimeType }, ...headerParamsWithAuth],
|
|
@@ -1465,7 +1491,7 @@ const useMockingOptions = () => useAtom(mockingOptionsAtom);
|
|
|
1465
1491
|
const OperationParameters = ({ parameters, values, onChangeValue, validate, }) => {
|
|
1466
1492
|
return (React.createElement(Panel, { defaultIsOpen: true },
|
|
1467
1493
|
React.createElement(Panel.Titlebar, null, "Parameters"),
|
|
1468
|
-
React.createElement(Panel.Content, { className: "sl-overflow-y-auto ParameterGrid OperationParametersContent" }, parameters.map(parameter => (React.createElement(ParameterEditor, { key: parameter.name, parameter: parameter, value: values[parameter.name], onChange: (value) => onChangeValue(parameter.name, String(value)), validate: validate }))))));
|
|
1494
|
+
React.createElement(Panel.Content, { className: "sl-overflow-y-auto ParameterGrid OperationParametersContent" }, parameters.map(parameter => (React.createElement(ParameterEditor, { key: parameter.name, parameter: parameter, value: values[parameter.name], onChange: (value) => onChangeValue(parameter.name, String(value)), validate: validate, isOptional: false, canChangeOptional: false, onChangeOptional: () => { } }))))));
|
|
1469
1495
|
};
|
|
1470
1496
|
|
|
1471
1497
|
const persistedParameterValuesAtom = atom({});
|
|
@@ -1617,6 +1643,7 @@ ServersDropdown.displayName = 'ServersDropdown';
|
|
|
1617
1643
|
const defaultServers = [];
|
|
1618
1644
|
const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embeddedInMd = false, tryItCredentialsPolicy, corsProxy, }) => {
|
|
1619
1645
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
1646
|
+
TryIt.displayName = 'TryIt';
|
|
1620
1647
|
const isDark = useThemeIsDark();
|
|
1621
1648
|
const [response, setResponse] = React.useState();
|
|
1622
1649
|
const [requestData, setRequestData] = React.useState();
|
|
@@ -1625,7 +1652,7 @@ const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embe
|
|
|
1625
1652
|
const mediaTypeContent = (_c = (_b = (_a = httpOperation.request) === null || _a === void 0 ? void 0 : _a.body) === null || _b === void 0 ? void 0 : _b.contents) === null || _c === void 0 ? void 0 : _c[requestBodyIndex !== null && requestBodyIndex !== void 0 ? requestBodyIndex : 0];
|
|
1626
1653
|
const { allParameters, updateParameterValue, parameterValuesWithDefaults } = useRequestParameters(httpOperation);
|
|
1627
1654
|
const [mockingOptions, setMockingOptions] = useMockingOptions();
|
|
1628
|
-
const [bodyParameterValues, setBodyParameterValues, formDataState] = useBodyParameterState(mediaTypeContent);
|
|
1655
|
+
const [bodyParameterValues, setBodyParameterValues, isAllowedEmptyValues, setAllowedEmptyValues, formDataState] = useBodyParameterState(mediaTypeContent);
|
|
1629
1656
|
const [textRequestBody, setTextRequestBody] = useTextRequestBodyState(mediaTypeContent);
|
|
1630
1657
|
const [operationAuthValue, setOperationAuthValue] = usePersistedSecuritySchemeWithValues();
|
|
1631
1658
|
const servers = React.useMemo(() => {
|
|
@@ -1636,6 +1663,12 @@ const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embe
|
|
|
1636
1663
|
const [chosenServer, setChosenServer] = useAtom(chosenServerAtom);
|
|
1637
1664
|
const isMockingEnabled = mockUrl && (chosenServer === null || chosenServer === void 0 ? void 0 : chosenServer.url) === mockUrl;
|
|
1638
1665
|
const hasRequiredButEmptyParameters = allParameters.some(parameter => parameter.required && !parameterValuesWithDefaults[parameter.name]);
|
|
1666
|
+
const getValues = () => Object.keys(bodyParameterValues)
|
|
1667
|
+
.filter(param => { var _a; return (_a = !isAllowedEmptyValues[param]) !== null && _a !== void 0 ? _a : true; })
|
|
1668
|
+
.reduce((previousValue, currentValue) => {
|
|
1669
|
+
previousValue[currentValue] = bodyParameterValues[currentValue];
|
|
1670
|
+
return previousValue;
|
|
1671
|
+
}, {});
|
|
1639
1672
|
React.useEffect(() => {
|
|
1640
1673
|
const currentUrl = chosenServer === null || chosenServer === void 0 ? void 0 : chosenServer.url;
|
|
1641
1674
|
const exists = currentUrl && servers.find(s => s.url === currentUrl);
|
|
@@ -1649,7 +1682,7 @@ const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embe
|
|
|
1649
1682
|
React.useEffect(() => {
|
|
1650
1683
|
let isMounted = true;
|
|
1651
1684
|
if (onRequestChange || embeddedInMd) {
|
|
1652
|
-
buildHarRequest(Object.assign(Object.assign({ mediaTypeContent, parameterValues: parameterValuesWithDefaults, httpOperation, bodyInput: formDataState.isFormDataBody ?
|
|
1685
|
+
buildHarRequest(Object.assign(Object.assign({ mediaTypeContent, parameterValues: parameterValuesWithDefaults, httpOperation, bodyInput: formDataState.isFormDataBody ? getValues() : textRequestBody, auth: operationAuthValue }, (isMockingEnabled && { mockData: getMockData(mockUrl, httpOperation, mockingOptions) })), { chosenServer,
|
|
1653
1686
|
corsProxy })).then(request => {
|
|
1654
1687
|
if (isMounted) {
|
|
1655
1688
|
if (onRequestChange) {
|
|
@@ -1669,6 +1702,7 @@ const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embe
|
|
|
1669
1702
|
parameterValuesWithDefaults,
|
|
1670
1703
|
formDataState.isFormDataBody,
|
|
1671
1704
|
bodyParameterValues,
|
|
1705
|
+
isAllowedEmptyValues,
|
|
1672
1706
|
textRequestBody,
|
|
1673
1707
|
operationAuthValue,
|
|
1674
1708
|
mockingOptions,
|
|
@@ -1687,7 +1721,7 @@ const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embe
|
|
|
1687
1721
|
parameterValues: parameterValuesWithDefaults,
|
|
1688
1722
|
httpOperation,
|
|
1689
1723
|
mediaTypeContent,
|
|
1690
|
-
bodyInput: formDataState.isFormDataBody ?
|
|
1724
|
+
bodyInput: formDataState.isFormDataBody ? getValues() : textRequestBody,
|
|
1691
1725
|
mockData,
|
|
1692
1726
|
auth: operationAuthValue,
|
|
1693
1727
|
chosenServer,
|
|
@@ -1723,7 +1757,7 @@ const TryIt = ({ httpOperation, mockUrl, onRequestChange, requestBodyIndex, embe
|
|
|
1723
1757
|
const tryItPanelContents = (React.createElement(React.Fragment, null,
|
|
1724
1758
|
((_e = httpOperation.security) === null || _e === void 0 ? void 0 : _e.length) ? (React.createElement(TryItAuth, { onChange: setOperationAuthValue, operationSecurityScheme: (_f = httpOperation.security) !== null && _f !== void 0 ? _f : [], value: operationAuthValue })) : null,
|
|
1725
1759
|
allParameters.length > 0 && (React.createElement(OperationParameters, { parameters: allParameters, values: parameterValuesWithDefaults, onChangeValue: updateParameterValue, validate: validateParameters })),
|
|
1726
|
-
formDataState.isFormDataBody ? (React.createElement(FormDataBody, { specification: formDataState.bodySpecification, values: bodyParameterValues, onChangeValues: setBodyParameterValues })) : mediaTypeContent ? (React.createElement(RequestBody, { examples: (_g = mediaTypeContent.examples) !== null && _g !== void 0 ? _g : [], requestBody: textRequestBody, onChange: setTextRequestBody })) : null,
|
|
1760
|
+
formDataState.isFormDataBody ? (React.createElement(FormDataBody, { specification: formDataState.bodySpecification, values: bodyParameterValues, onChangeValues: setBodyParameterValues, onChangeParameterAllow: setAllowedEmptyValues, isAllowedEmptyValues: isAllowedEmptyValues })) : mediaTypeContent ? (React.createElement(RequestBody, { examples: (_g = mediaTypeContent.examples) !== null && _g !== void 0 ? _g : [], requestBody: textRequestBody, onChange: setTextRequestBody })) : null,
|
|
1727
1761
|
React.createElement(Panel.Content, { className: "SendButtonHolder", mt: 4, pt: !isOnlySendButton && !embeddedInMd ? 0 : undefined },
|
|
1728
1762
|
React.createElement(HStack, { alignItems: "center", spacing: 2 },
|
|
1729
1763
|
React.createElement(Button, { appearance: "primary", loading: loading, disabled: loading, onPress: handleSendRequest, size: "sm" }, "Send API Request"),
|