@stoplight/elements-core 7.5.9 → 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/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
- const properUrl = new RegExp(/((([A-Za-z]{3,9}:(?:\/\/)?)(?:[\-;:&=\+\$,\w]+@)?[A-Za-z0-9\.\-]+|(?:www\.|[\-;:&=\+\$,\w]+@)[A-Za-z0-9\.\-]+)((?:\/[\+~%\/\.\w\-_]*)?\??(?:[\-\+=&;%@\.\w_]*)#?(?:[\.\!\/\\\w]*))?)/);
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(server => isProperUrl(server.url));
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 = URI(urlString);
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 url = new URL(URI(serverUrl).segment(expandedPath).toString());
1235
- url.search = new URLSearchParams(queryParamsWithAuth.map(nameAndValueObjectToPair)).toString();
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
- url.toString(),
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 extendedPath = uriExpand(httpOperation.path, parameterValues);
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: URI(serverUrl).segment(extendedPath).toString(),
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 ? bodyParameterValues : textRequestBody, auth: operationAuthValue }, (isMockingEnabled && { mockData: getMockData(mockUrl, httpOperation, mockingOptions) })), { chosenServer,
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 ? bodyParameterValues : textRequestBody,
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"),
@@ -2295,7 +2329,7 @@ const SidebarLayout = React.forwardRef(({ sidebar, children, maxContentWidth = M
2295
2329
  paddingLeft: `calc((100% - ${maxContentWidth}px) / 2)`,
2296
2330
  minWidth: `${sidebarWidth}px`,
2297
2331
  } }, sidebar),
2298
- React.createElement(Box, { ref: scrollRef, bg: "canvas", px: 24, flex: 1, w: "full" },
2332
+ React.createElement(Box, { ref: scrollRef, bg: "canvas", px: 24, flex: 1, w: "full", overflowY: "auto" },
2299
2333
  React.createElement(Box, { style: { maxWidth: `${maxContentWidth - sidebarWidth}px` }, py: 16 }, children))));
2300
2334
  });
2301
2335
 
@@ -2350,8 +2384,8 @@ const SchemaAndDescription = ({ title: titleProp, schema }) => {
2350
2384
  React__default.createElement(JsonSchemaViewer, { resolveRef: resolveRef, schema: getOriginalObject(schema) })));
2351
2385
  };
2352
2386
  const CodeComponent = props => {
2353
- const { title, jsonSchema, http, children } = props;
2354
- const value = String(Array.isArray(children) ? children[0] : children);
2387
+ const { title, jsonSchema, http, resolved, children } = props;
2388
+ const value = resolved || String(Array.isArray(children) ? children[0] : children);
2355
2389
  const parsedValue = useParsedValue(value);
2356
2390
  if (jsonSchema) {
2357
2391
  if (!isJSONSchema(parsedValue)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stoplight/elements-core",
3
- "version": "7.5.9",
3
+ "version": "7.5.13",
4
4
  "main": "./index.js",
5
5
  "sideEffects": [
6
6
  "web-components.min.js",
@@ -29,10 +29,10 @@
29
29
  "@stoplight/json-schema-ref-parser": "^9.0.5",
30
30
  "@stoplight/json-schema-sampler": "0.2.2",
31
31
  "@stoplight/json-schema-viewer": "^4.5.0",
32
- "@stoplight/markdown-viewer": "^5.4.1",
33
- "@stoplight/mosaic": "^1.15.2",
34
- "@stoplight/mosaic-code-editor": "^1.15.2",
35
- "@stoplight/mosaic-code-viewer": "^1.15.2",
32
+ "@stoplight/markdown-viewer": "^5.4.2",
33
+ "@stoplight/mosaic": "^1.15.4",
34
+ "@stoplight/mosaic-code-editor": "^1.15.4",
35
+ "@stoplight/mosaic-code-viewer": "^1.15.4",
36
36
  "@stoplight/path": "^1.3.2",
37
37
  "@stoplight/react-error-boundary": "^2.0.0",
38
38
  "@stoplight/types": "^12.0.0",