@stoplight/elements-core 7.6.4 → 7.7.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/index.esm.js CHANGED
@@ -1,13 +1,13 @@
1
1
  import { __rest, __awaiter } from 'tslib';
2
2
  import * as React from 'react';
3
3
  import React__default, { useContext, useMemo } from 'react';
4
- import { resolveInlineRef, isPlainObject as isPlainObject$1, safeParse, safeStringify } from '@stoplight/json';
4
+ import { resolveInlineRef, hasRef, isPlainObject as isPlainObject$1, safeParse, safeStringify } from '@stoplight/json';
5
5
  import isArray from 'lodash/isArray.js';
6
- import isObject from 'lodash/isObject.js';
7
6
  import isPlainObject from 'lodash/isPlainObject.js';
8
7
  import { NodeType, HttpParamStyles } from '@stoplight/types';
9
8
  import { parse } from '@stoplight/yaml';
10
- import { isArray as isArray$1, Box, Panel, CopyButton, Menu, Button, Text, Flex, Input, Icon, Select, FieldButton, Image, Link, useThemeIsDark, HStack, VStack, InvertTheme, Tooltip, Badge, LinkHeading, Tabs, TabList, Tab, TabPanels, TabPanel, Heading, useClipboard, useBreakpoints, useMosaicContext, Provider as Provider$1 } from '@stoplight/mosaic';
9
+ import { isArray as isArray$1, Box, Panel, CopyButton, Menu, Button, Text, Flex, Input, Icon, Select, FieldButton, Image, Link, useThemeIsDark, HStack, VStack, InvertTheme, Tooltip, Badge, LinkHeading as LinkHeading$1, NodeAnnotation, Tabs, TabList, Tab, TabPanels, TabPanel, Heading, useClipboard, useBreakpoints, useMosaicContext, Provider as Provider$1 } from '@stoplight/mosaic';
10
+ import isObject from 'lodash/isObject.js';
11
11
  import { withErrorBoundary } from '@stoplight/react-error-boundary';
12
12
  import { MarkdownViewer as MarkdownViewer$1, DefaultSMDComponents, MarkdownViewerProvider } from '@stoplight/markdown-viewer';
13
13
  export { DefaultSMDComponents } from '@stoplight/markdown-viewer';
@@ -37,9 +37,9 @@ import uniqBy from 'lodash/uniqBy.js';
37
37
  import formatXml from 'xml-formatter';
38
38
  import entries from 'lodash/entries.js';
39
39
  import keys from 'lodash/keys.js';
40
+ import { useLocation, BrowserRouter, MemoryRouter, HashRouter, StaticRouter, Route } from 'react-router-dom';
40
41
  import { JsonSchemaViewer } from '@stoplight/json-schema-viewer';
41
42
  import sortBy from 'lodash/sortBy.js';
42
- import { useLocation, BrowserRouter, MemoryRouter, HashRouter, StaticRouter, Route } from 'react-router-dom';
43
43
  import { HashLink } from 'react-router-hash-link';
44
44
  import { QueryClient, useQueryClient, QueryClientProvider } from 'react-query';
45
45
  import $RefParser from '@stoplight/json-schema-ref-parser';
@@ -105,7 +105,7 @@ const isResolvedObjectProxy = (someObject) => {
105
105
  const getOriginalObject = (resolvedObject) => {
106
106
  return resolvedObject[originalObjectSymbol] || resolvedObject;
107
107
  };
108
- const isReference = (value) => isObject(value) && typeof value['$ref'] === 'string';
108
+ const isReference = hasRef;
109
109
 
110
110
  const InlineRefResolverContext = React.createContext(undefined);
111
111
  InlineRefResolverContext.displayName = 'InlineRefResolverContext';
@@ -125,6 +125,15 @@ const useResolvedObject = (currentObject) => {
125
125
  return React.useMemo(() => createResolvedObject(currentObject, { contextObject: document, resolver }), [currentObject, document, resolver]);
126
126
  };
127
127
 
128
+ const DEFAULT_CONTEXT = {};
129
+ const ElementsOptionsContext = React.createContext(DEFAULT_CONTEXT);
130
+ const useOptionsCtx = () => {
131
+ return React.useContext(ElementsOptionsContext) || DEFAULT_CONTEXT;
132
+ };
133
+ function ElementsOptionsProvider({ children, nodeHasChanged }) {
134
+ return (React.createElement(ElementsOptionsContext.Provider, { value: Object.assign({}, DEFAULT_CONTEXT, { nodeHasChanged }) }, children));
135
+ }
136
+
128
137
  function isSMDASTRoot(maybeAst) {
129
138
  return isObject(maybeAst) && maybeAst['type'] === 'root' && isArray$1(maybeAst['children']);
130
139
  }
@@ -158,6 +167,7 @@ const parserMap = {
158
167
  [NodeType.TableOfContents]: parseUnknown,
159
168
  [NodeType.SpectralRuleset]: parseUnknown,
160
169
  [NodeType.Styleguide]: parseUnknown,
170
+ [NodeType.Image]: parseUnknown,
161
171
  [NodeType.Unknown]: parseUnknown,
162
172
  };
163
173
  function parseArticleData(rawData) {
@@ -271,6 +281,11 @@ var faEye = {
271
281
  iconName: 'eye',
272
282
  icon: [576, 512, [128065], "f06e", "M279.6 160.4C282.4 160.1 285.2 160 288 160C341 160 384 202.1 384 256C384 309 341 352 288 352C234.1 352 192 309 192 256C192 253.2 192.1 250.4 192.4 247.6C201.7 252.1 212.5 256 224 256C259.3 256 288 227.3 288 192C288 180.5 284.1 169.7 279.6 160.4zM480.6 112.6C527.4 156 558.7 207.1 573.5 243.7C576.8 251.6 576.8 260.4 573.5 268.3C558.7 304 527.4 355.1 480.6 399.4C433.5 443.2 368.8 480 288 480C207.2 480 142.5 443.2 95.42 399.4C48.62 355.1 17.34 304 2.461 268.3C-.8205 260.4-.8205 251.6 2.461 243.7C17.34 207.1 48.62 156 95.42 112.6C142.5 68.84 207.2 32 288 32C368.8 32 433.5 68.84 480.6 112.6V112.6zM288 112C208.5 112 144 176.5 144 256C144 335.5 208.5 400 288 400C367.5 400 432 335.5 432 256C432 176.5 367.5 112 288 112z"]
273
283
  };
284
+ var faImage = {
285
+ prefix: 'fas',
286
+ iconName: 'image',
287
+ icon: [512, 512, [], "f03e", "M447.1 32h-384C28.64 32-.0091 60.65-.0091 96v320c0 35.35 28.65 64 63.1 64h384c35.35 0 64-28.65 64-64V96C511.1 60.65 483.3 32 447.1 32zM111.1 96c26.51 0 48 21.49 48 48S138.5 192 111.1 192s-48-21.49-48-48S85.48 96 111.1 96zM446.1 407.6C443.3 412.8 437.9 416 432 416H82.01c-6.021 0-11.53-3.379-14.26-8.75c-2.73-5.367-2.215-11.81 1.334-16.68l70-96C142.1 290.4 146.9 288 152 288s9.916 2.441 12.93 6.574l32.46 44.51l93.3-139.1C293.7 194.7 298.7 192 304 192s10.35 2.672 13.31 7.125l128 192C448.6 396 448.9 402.3 446.1 407.6z"]
288
+ };
274
289
  var faServer = {
275
290
  prefix: 'fas',
276
291
  iconName: 'server',
@@ -288,6 +303,7 @@ const NodeTypeColors = {
288
303
  table_of_contents: '',
289
304
  spectral_ruleset: '',
290
305
  styleguide: '',
306
+ image: '',
291
307
  };
292
308
  const NodeTypePrettyName = {
293
309
  http_operation: 'Endpoint',
@@ -300,6 +316,7 @@ const NodeTypePrettyName = {
300
316
  table_of_contents: '',
301
317
  spectral_ruleset: '',
302
318
  styleguide: '',
319
+ image: '',
303
320
  };
304
321
  const NodeTypeIconDefs = {
305
322
  http_operation: faCrosshairs,
@@ -312,6 +329,7 @@ const NodeTypeIconDefs = {
312
329
  table_of_contents: faQuestionCircle,
313
330
  spectral_ruleset: faQuestionCircle,
314
331
  styleguide: faQuestionCircle,
332
+ image: faImage,
315
333
  };
316
334
  const HttpMethodColors = {
317
335
  get: 'success',
@@ -410,6 +428,21 @@ function createNamedContext(name, defaultValue) {
410
428
  return context;
411
429
  }
412
430
 
431
+ const ALPHANUMERIC = /[^A-Za-z0-9]+$/;
432
+ function useChosenServerUrl(chosenServerUrl) {
433
+ const match = ALPHANUMERIC.exec(chosenServerUrl);
434
+ if (match === null) {
435
+ return {
436
+ leading: chosenServerUrl,
437
+ trailing: null,
438
+ };
439
+ }
440
+ return {
441
+ leading: chosenServerUrl.substring(0, match.index),
442
+ trailing: chosenServerUrl.substring(match.index),
443
+ };
444
+ }
445
+
413
446
  const chosenServerAtom = atom(undefined);
414
447
 
415
448
  function isValidServer(server) {
@@ -424,6 +457,7 @@ const getServersToDisplay = (originalServers, mockUrl) => {
424
457
  .filter(isValidServer);
425
458
  if (mockUrl) {
426
459
  servers.push({
460
+ id: 'mock',
427
461
  description: 'Mock Server',
428
462
  url: mockUrl,
429
463
  });
@@ -613,15 +647,12 @@ const requestSampleConfigs = {
613
647
  mosaicCodeViewerLanguage: 'php',
614
648
  httpSnippetLanguage: 'php',
615
649
  libraries: {
616
- 'pecl/http 1': {
617
- httpSnippetLibrary: 'http1',
618
- },
619
- 'pecl/http 2': {
620
- httpSnippetLibrary: 'http2',
621
- },
622
650
  cURL: {
623
651
  httpSnippetLibrary: 'curl',
624
652
  },
653
+ guzzle: {
654
+ httpSnippetLibrary: 'guzzle',
655
+ },
625
656
  },
626
657
  },
627
658
  Powershell: {
@@ -984,9 +1015,12 @@ function parameterSupportsFileUpload(parameter) {
984
1015
  (((_b = parameter.schema) === null || _b === void 0 ? void 0 : _b.contentEncoding) === 'base64' ||
985
1016
  ((_c = parameter.schema) === null || _c === void 0 ? void 0 : _c.contentMediaType) === 'application/octet-stream'));
986
1017
  }
1018
+ function stringifyValue(value) {
1019
+ return typeof value === 'object' ? JSON.stringify(value) : escapeQuotes(String(value));
1020
+ }
987
1021
  function exampleValue(example) {
988
1022
  const value = 'value' in example ? example.value : example.externalValue;
989
- return escapeQuotes(String(value));
1023
+ return stringifyValue(value);
990
1024
  }
991
1025
  function escapeQuotes(value) {
992
1026
  return value.replace(/"/g, '\\"');
@@ -1007,7 +1041,7 @@ const getValueForParameter = (parameter) => {
1007
1041
  var _a, _b, _c;
1008
1042
  const defaultValue = retrieveDefaultFromSchema(parameter);
1009
1043
  if (typeof defaultValue !== 'undefined') {
1010
- return { value: String(defaultValue), isDefault: true };
1044
+ return { value: stringifyValue(defaultValue), isDefault: true };
1011
1045
  }
1012
1046
  const examples = (_a = parameter.examples) !== null && _a !== void 0 ? _a : [];
1013
1047
  if (examples.length > 0) {
@@ -1015,7 +1049,7 @@ const getValueForParameter = (parameter) => {
1015
1049
  }
1016
1050
  const enums = (_c = (_b = parameter.schema) === null || _b === void 0 ? void 0 : _b.enum) !== null && _c !== void 0 ? _c : [];
1017
1051
  if (enums.length > 0) {
1018
- return { value: String(enums[0]) };
1052
+ return { value: stringifyValue(enums[0]) };
1019
1053
  }
1020
1054
  return { value: '' };
1021
1055
  };
@@ -1300,13 +1334,77 @@ const getServerUrl = ({ chosenServer, httpOperation, mockData, corsProxy, }) =>
1300
1334
  }
1301
1335
  return serverUrl;
1302
1336
  };
1337
+ const getQueryParams = ({ httpOperation, parameterValues, }) => {
1338
+ var _a;
1339
+ const query = (_a = httpOperation.request) === null || _a === void 0 ? void 0 : _a.query;
1340
+ if (!query)
1341
+ return [];
1342
+ return query.reduce((acc, param) => {
1343
+ var _a, _b, _c, _d, _e;
1344
+ const value = (_a = parameterValues[param.name]) !== null && _a !== void 0 ? _a : '';
1345
+ if (value.length === 0)
1346
+ return acc;
1347
+ const explode = (_b = param.explode) !== null && _b !== void 0 ? _b : true;
1348
+ if (((_c = param.schema) === null || _c === void 0 ? void 0 : _c.type) === 'object' && param.style === 'form' && value) {
1349
+ let nested;
1350
+ try {
1351
+ nested = JSON.parse(value);
1352
+ if (!(typeof nested === 'object' && nested !== null))
1353
+ throw Error();
1354
+ }
1355
+ catch (e) {
1356
+ throw new Error(`Cannot use param value "${value}". JSON object expected.`);
1357
+ }
1358
+ if (explode) {
1359
+ acc.push(...Object.entries(nested).map(([name, value]) => ({ name, value: value.toString() })));
1360
+ }
1361
+ else {
1362
+ acc.push({
1363
+ name: param.name,
1364
+ value: Object.entries(nested)
1365
+ .map(entry => entry.join(','))
1366
+ .join(','),
1367
+ });
1368
+ }
1369
+ }
1370
+ else if (((_d = param.schema) === null || _d === void 0 ? void 0 : _d.type) === 'array' && value) {
1371
+ let nested;
1372
+ try {
1373
+ nested = JSON.parse(value);
1374
+ if (!Array.isArray(nested))
1375
+ throw Error();
1376
+ }
1377
+ catch (e) {
1378
+ throw new Error(`Cannot use param value "${value}". JSON array expected.`);
1379
+ }
1380
+ if (explode) {
1381
+ acc.push(...nested.map(value => ({ name: param.name, value: value.toString() })));
1382
+ }
1383
+ else {
1384
+ const delimiter = {
1385
+ [HttpParamStyles.Form]: ',',
1386
+ [HttpParamStyles.SpaceDelimited]: ' ',
1387
+ [HttpParamStyles.PipeDelimited]: '|',
1388
+ };
1389
+ acc.push({
1390
+ name: param.name,
1391
+ value: nested.join((_e = delimiter[param.style]) !== null && _e !== void 0 ? _e : delimiter[HttpParamStyles.Form]),
1392
+ });
1393
+ }
1394
+ }
1395
+ else {
1396
+ acc.push({ name: param.name, value });
1397
+ }
1398
+ return acc;
1399
+ }, []);
1400
+ };
1303
1401
  function buildFetchRequest({ httpOperation, mediaTypeContent, bodyInput, parameterValues, mockData, auth, chosenServer, credentials = 'omit', corsProxy, }) {
1304
- var _a, _b, _c, _d, _e, _f;
1402
+ var _a, _b, _c;
1305
1403
  return __awaiter(this, void 0, void 0, function* () {
1306
1404
  const serverUrl = getServerUrl({ httpOperation, mockData, chosenServer, corsProxy });
1307
1405
  const shouldIncludeBody = ['PUT', 'POST', 'PATCH'].includes(httpOperation.method.toUpperCase());
1308
- const queryParams = (_c = (_b = (_a = httpOperation.request) === null || _a === void 0 ? void 0 : _a.query) === null || _b === void 0 ? void 0 : _b.map(param => { var _a; return ({ name: param.name, value: (_a = parameterValues[param.name]) !== null && _a !== void 0 ? _a : '' }); }).filter(({ value }) => value.length > 0)) !== null && _c !== void 0 ? _c : [];
1309
- const rawHeaders = filterOutAuthorizationParams((_e = (_d = httpOperation.request) === null || _d === void 0 ? void 0 : _d.headers) !== null && _e !== void 0 ? _e : [], httpOperation.security)
1406
+ const queryParams = getQueryParams({ httpOperation, parameterValues });
1407
+ const rawHeaders = filterOutAuthorizationParams((_b = (_a = httpOperation.request) === null || _a === void 0 ? void 0 : _a.headers) !== null && _b !== void 0 ? _b : [], httpOperation.security)
1310
1408
  .map(header => { var _a; return ({ name: header.name, value: (_a = parameterValues[header.name]) !== null && _a !== void 0 ? _a : '' }); })
1311
1409
  .filter(({ value }) => value.length > 0);
1312
1410
  const [queryParamsWithAuth, headersWithAuth] = runAuthRequestEhancements(auth, queryParams, rawHeaders);
@@ -1315,7 +1413,7 @@ function buildFetchRequest({ httpOperation, mediaTypeContent, bodyInput, paramet
1315
1413
  urlObject.search = new URLSearchParams(queryParamsWithAuth.map(nameAndValueObjectToPair)).toString();
1316
1414
  const body = typeof bodyInput === 'object' ? yield createRequestBody(mediaTypeContent, bodyInput) : bodyInput;
1317
1415
  const headers = Object.assign(Object.assign(Object.assign({}, ((mediaTypeContent === null || mediaTypeContent === void 0 ? void 0 : mediaTypeContent.mediaType) !== 'multipart/form-data' && {
1318
- 'Content-Type': (_f = mediaTypeContent === null || mediaTypeContent === void 0 ? void 0 : mediaTypeContent.mediaType) !== null && _f !== void 0 ? _f : 'application/json',
1416
+ 'Content-Type': (_c = mediaTypeContent === null || mediaTypeContent === void 0 ? void 0 : mediaTypeContent.mediaType) !== null && _c !== void 0 ? _c : 'application/json',
1319
1417
  })), Object.fromEntries(headersWithAuth.map(nameAndValueObjectToPair))), mockData === null || mockData === void 0 ? void 0 : mockData.header);
1320
1418
  return [
1321
1419
  urlObject.href,
@@ -1375,13 +1473,13 @@ const runAuthRequestEhancements = (auth, queryParams, headers) => {
1375
1473
  return [newQueryParams, newHeaders];
1376
1474
  };
1377
1475
  function buildHarRequest({ httpOperation, bodyInput, parameterValues, mediaTypeContent, auth, mockData, chosenServer, corsProxy, }) {
1378
- var _a, _b, _c, _d, _e, _f, _g;
1476
+ var _a, _b, _c, _d;
1379
1477
  return __awaiter(this, void 0, void 0, function* () {
1380
1478
  const serverUrl = getServerUrl({ httpOperation, mockData, chosenServer, corsProxy });
1381
1479
  const mimeType = (_a = mediaTypeContent === null || mediaTypeContent === void 0 ? void 0 : mediaTypeContent.mediaType) !== null && _a !== void 0 ? _a : 'application/json';
1382
1480
  const shouldIncludeBody = ['PUT', 'POST', 'PATCH'].includes(httpOperation.method.toUpperCase());
1383
- const queryParams = (_d = (_c = (_b = httpOperation.request) === null || _b === void 0 ? void 0 : _b.query) === null || _c === void 0 ? void 0 : _c.map(param => { var _a; return ({ name: param.name, value: (_a = parameterValues[param.name]) !== null && _a !== void 0 ? _a : '' }); }).filter(({ value }) => value.length > 0)) !== null && _d !== void 0 ? _d : [];
1384
- const headerParams = (_g = (_f = (_e = httpOperation.request) === null || _e === void 0 ? void 0 : _e.headers) === null || _f === void 0 ? void 0 : _f.map(header => { var _a; return ({ name: header.name, value: (_a = parameterValues[header.name]) !== null && _a !== void 0 ? _a : '' }); })) !== null && _g !== void 0 ? _g : [];
1481
+ const queryParams = getQueryParams({ httpOperation, parameterValues });
1482
+ const headerParams = (_d = (_c = (_b = httpOperation.request) === null || _b === void 0 ? void 0 : _b.headers) === null || _c === void 0 ? void 0 : _c.map(header => { var _a; return ({ name: header.name, value: (_a = parameterValues[header.name]) !== null && _a !== void 0 ? _a : '' }); })) !== null && _d !== void 0 ? _d : [];
1385
1483
  if (mockData === null || mockData === void 0 ? void 0 : mockData.header) {
1386
1484
  headerParams.push({ name: 'Prefer', value: mockData.header.Prefer });
1387
1485
  }
@@ -1990,6 +2088,17 @@ ${scopes.map(([key, value]) => `- \`${key}\` - ${value}`).join('\n')}`;
1990
2088
  return description;
1991
2089
  }
1992
2090
 
2091
+ const RouterTypeContext = React.createContext('history');
2092
+
2093
+ const LinkHeading = React.memo(function LinkHeading(_a) {
2094
+ var { id: _id } = _a, props = __rest(_a, ["id"]);
2095
+ const { pathname } = useLocation();
2096
+ const routerKind = React.useContext(RouterTypeContext);
2097
+ const route = pathname.split('#')[0];
2098
+ const id = routerKind === 'hash' ? `${route}#${_id}` : _id;
2099
+ return React.createElement(LinkHeading$1, Object.assign({ id: id }, props));
2100
+ });
2101
+
1993
2102
  const SectionTitle = ({ title, id, size = 2, children }) => {
1994
2103
  return (React.createElement(HStack, { spacing: 6 },
1995
2104
  React.createElement(Box, { as: LinkHeading, size: size, "aria-label": title, id: id || slugify(title) }, title),
@@ -2015,6 +2124,7 @@ const Body = ({ body, onChange }) => {
2015
2124
  var _a;
2016
2125
  const refResolver = useInlineRefResolver();
2017
2126
  const [chosenContent, setChosenContent] = React.useState(0);
2127
+ const { nodeHasChanged } = useOptionsCtx();
2018
2128
  React.useEffect(() => {
2019
2129
  onChange(chosenContent);
2020
2130
  }, [chosenContent]);
@@ -2022,11 +2132,14 @@ const Body = ({ body, onChange }) => {
2022
2132
  return null;
2023
2133
  const { contents = [], description } = body;
2024
2134
  const schema = (_a = contents[chosenContent]) === null || _a === void 0 ? void 0 : _a.schema;
2135
+ const descriptionChanged = nodeHasChanged === null || nodeHasChanged === void 0 ? void 0 : nodeHasChanged({ nodeId: body.id, attr: 'description' });
2025
2136
  return (React.createElement(VStack, { spacing: 6 },
2026
2137
  React.createElement(SectionSubtitle, { title: "Body", id: "request-body" }, contents.length > 0 && (React.createElement(Flex, { flex: 1, justify: "end" },
2027
2138
  React.createElement(Select, { "aria-label": "Request Body Content Type", value: String(chosenContent), onChange: (value) => setChosenContent(parseInt(String(value), 10)), options: contents.map((content, index) => ({ label: content.mediaType, value: index })), size: "sm" })))),
2028
- description && React.createElement(MarkdownViewer, { markdown: description }),
2029
- isJSONSchema(schema) && (React.createElement(JsonSchemaViewer, { resolveRef: refResolver, schema: getOriginalObject(schema), viewMode: "write", renderRootTreeLines: true }))));
2139
+ description && (React.createElement(Box, { pos: "relative" },
2140
+ React.createElement(MarkdownViewer, { markdown: description }),
2141
+ React.createElement(NodeAnnotation, { change: descriptionChanged }))),
2142
+ isJSONSchema(schema) && (React.createElement(JsonSchemaViewer, { resolveRef: refResolver, schema: getOriginalObject(schema), viewMode: "write", renderRootTreeLines: true, nodeHasChanged: nodeHasChanged }))));
2030
2143
  };
2031
2144
  Body.displayName = 'HttpOperation.Body';
2032
2145
 
@@ -2050,14 +2163,16 @@ const defaultStyle = {
2050
2163
  cookie: HttpParamStyles.Form,
2051
2164
  };
2052
2165
  const Parameters = ({ parameters, parameterType }) => {
2166
+ const { nodeHasChanged } = useOptionsCtx();
2167
+ const refResolver = useInlineRefResolver();
2053
2168
  const schema = React.useMemo(() => httpOperationParamsToSchema({ parameters, parameterType }), [parameters, parameterType]);
2054
2169
  if (!schema)
2055
2170
  return null;
2056
- return React.createElement(JsonSchemaViewer, { schema: schema, disableCrumbs: true });
2171
+ return React.createElement(JsonSchemaViewer, { resolveRef: refResolver, schema: schema, disableCrumbs: true, nodeHasChanged: nodeHasChanged });
2057
2172
  };
2058
2173
  Parameters.displayName = 'HttpOperation.Parameters';
2059
2174
  const httpOperationParamsToSchema = ({ parameters, parameterType }) => {
2060
- var _a;
2175
+ var _a, _b, _c;
2061
2176
  if (!parameters || !parameters.length)
2062
2177
  return null;
2063
2178
  const schema = {
@@ -2066,8 +2181,6 @@ const httpOperationParamsToSchema = ({ parameters, parameterType }) => {
2066
2181
  };
2067
2182
  const sortedParams = sortBy(parameters, ['required', 'name']);
2068
2183
  for (const p of sortedParams) {
2069
- if (!p.schema)
2070
- continue;
2071
2184
  const { name, description, required, deprecated, examples, style } = p;
2072
2185
  const paramExamples = (examples === null || examples === void 0 ? void 0 : examples.map(example => {
2073
2186
  if (isNodeExample(example)) {
@@ -2077,10 +2190,10 @@ const httpOperationParamsToSchema = ({ parameters, parameterType }) => {
2077
2190
  })) || [];
2078
2191
  const schemaExamples = (_a = p.schema) === null || _a === void 0 ? void 0 : _a.examples;
2079
2192
  const schemaExamplesArray = Array.isArray(schemaExamples) ? schemaExamples : [];
2080
- const paramDescription = description || p.schema.description;
2193
+ const paramDescription = description || ((_b = p.schema) === null || _b === void 0 ? void 0 : _b.description);
2081
2194
  const paramDeprecated = deprecated || p.schema.deprecated;
2082
2195
  const paramStyle = style && defaultStyle[parameterType] !== style ? readableStyles[style] || style : undefined;
2083
- schema.properties[p.name] = Object.assign(Object.assign({}, p.schema), { description: paramDescription, examples: [...paramExamples, ...schemaExamplesArray], deprecated: paramDeprecated, style: paramStyle });
2196
+ schema.properties[p.name] = Object.assign(Object.assign({}, (p.schema || {})), { description: paramDescription, examples: [...paramExamples, ...schemaExamplesArray], deprecated: paramDeprecated, style: paramStyle, 'x-stoplight': Object.assign(Object.assign({}, (((_c = p.schema) === null || _c === void 0 ? void 0 : _c['x-stoplight']) || {})), { id: p.id }) });
2084
2197
  if (required) {
2085
2198
  schema.required.push(name);
2086
2199
  }
@@ -2103,7 +2216,7 @@ const Request = ({ operation: { request, request: { path: pathParams = [], heade
2103
2216
  return null;
2104
2217
  return (React.createElement(VStack, { spacing: 8 },
2105
2218
  React.createElement(SectionTitle, { title: "Request" }),
2106
- securitySchemes.length > 0 && (React.createElement(VStack, { spacing: 3 }, securitySchemes.map((scheme, i) => (React.createElement(SecurityPanel, { key: i, scheme: scheme, includeKey: shouldIncludeKey(securitySchemes, scheme.type) }))))),
2219
+ React.createElement(SecuritySchemes$1, { schemes: securitySchemes }),
2107
2220
  pathParams.length > 0 && (React.createElement(VStack, { spacing: 5 },
2108
2221
  React.createElement(SectionSubtitle, { title: "Path Parameters" }),
2109
2222
  React.createElement(Parameters, { parameterType: "path", parameters: pathParams }))),
@@ -2124,6 +2237,15 @@ const SecurityPanel = ({ scheme, includeKey }) => {
2124
2237
  const [expandedState, setExpanded] = useAtom(schemeExpandedState);
2125
2238
  return (React.createElement(SubSectionPanel, { title: `Security: ${getReadableSecurityName(scheme, includeKey)}`, defaultIsOpen: !!expandedState[scheme.key], onChange: isOpen => setExpanded(Object.assign(Object.assign({}, expandedState), { [scheme.key]: isOpen })) },
2126
2239
  React.createElement(MarkdownViewer, { style: { fontSize: 12 }, markdown: `${scheme.description || ''}\n\n` + getDefaultDescription(scheme) })));
2240
+ };
2241
+ const SecuritySchemes$1 = ({ schemes }) => {
2242
+ const { nodeHasChanged } = useOptionsCtx();
2243
+ if (!schemes.length) {
2244
+ return null;
2245
+ }
2246
+ return (React.createElement(VStack, { spacing: 3 }, schemes.map((scheme, i) => (React.createElement(Box, { pos: "relative", key: i },
2247
+ React.createElement(SecurityPanel, { scheme: scheme, includeKey: shouldIncludeKey(schemes, scheme.type) }),
2248
+ React.createElement(NodeAnnotation, { change: nodeHasChanged === null || nodeHasChanged === void 0 ? void 0 : nodeHasChanged({ nodeId: scheme.id }) }))))));
2127
2249
  };
2128
2250
 
2129
2251
  const Responses = ({ responses: unsortedResponses, onStatusCodeChange, onMediaTypeChange }) => {
@@ -2146,13 +2268,17 @@ const Response = ({ response, onMediaTypeChange }) => {
2146
2268
  const { contents = [], headers = [], description } = response;
2147
2269
  const [chosenContent, setChosenContent] = React.useState(0);
2148
2270
  const refResolver = useInlineRefResolver();
2271
+ const { nodeHasChanged } = useOptionsCtx();
2149
2272
  const responseContent = contents[chosenContent];
2150
2273
  const schema = responseContent === null || responseContent === void 0 ? void 0 : responseContent.schema;
2151
2274
  React.useEffect(() => {
2152
2275
  responseContent && onMediaTypeChange(responseContent.mediaType);
2153
2276
  }, [responseContent]);
2277
+ const descriptionChanged = nodeHasChanged === null || nodeHasChanged === void 0 ? void 0 : nodeHasChanged({ nodeId: response.id, attr: 'description' });
2154
2278
  return (React.createElement(VStack, { spacing: 8, pt: 8 },
2155
- description && React.createElement(MarkdownViewer, { markdown: description }),
2279
+ description && (React.createElement(Box, { pos: "relative" },
2280
+ React.createElement(MarkdownViewer, { markdown: description }),
2281
+ React.createElement(NodeAnnotation, { change: descriptionChanged }))),
2156
2282
  headers.length > 0 && (React.createElement(VStack, { spacing: 5 },
2157
2283
  React.createElement(SectionSubtitle, { title: "Headers", id: "response-headers" }),
2158
2284
  React.createElement(Parameters, { parameterType: "header", parameters: headers }))),
@@ -2160,7 +2286,7 @@ const Response = ({ response, onMediaTypeChange }) => {
2160
2286
  React.createElement(SectionSubtitle, { title: "Body", id: "response-body" },
2161
2287
  React.createElement(Flex, { flex: 1, justify: "end" },
2162
2288
  React.createElement(Select, { "aria-label": "Response Body Content Type", value: String(chosenContent), onChange: (value) => setChosenContent(parseInt(String(value), 10)), options: contents.map((content, index) => ({ label: content.mediaType, value: index })), size: "sm" }))),
2163
- schema && (React.createElement(JsonSchemaViewer, { schema: getOriginalObject(schema), resolveRef: refResolver, viewMode: "read", parentCrumbs: ['responses', response.code], renderRootTreeLines: true }))))));
2289
+ schema && (React.createElement(JsonSchemaViewer, { schema: getOriginalObject(schema), resolveRef: refResolver, viewMode: "read", parentCrumbs: ['responses', response.code], renderRootTreeLines: true, nodeHasChanged: nodeHasChanged }))))));
2164
2290
  };
2165
2291
  Response.displayName = 'HttpOperation.Response';
2166
2292
  const codeToIntentVal = (code) => {
@@ -2178,6 +2304,7 @@ const codeToIntentVal = (code) => {
2178
2304
  };
2179
2305
 
2180
2306
  const HttpOperationComponent = React.memo(({ className, data: unresolvedData, layoutOptions, tryItCredentialsPolicy, tryItCorsProxy }) => {
2307
+ const { nodeHasChanged } = useOptionsCtx();
2181
2308
  const data = useResolvedObject(unresolvedData);
2182
2309
  const mocking = React.useContext(MockingContext);
2183
2310
  const isDeprecated = !!data.deprecated;
@@ -2187,15 +2314,12 @@ const HttpOperationComponent = React.memo(({ className, data: unresolvedData, la
2187
2314
  const [requestBodyIndex, setTextRequestBodyIndex] = React.useState(0);
2188
2315
  const prettyName = (data.summary || data.iid || '').trim();
2189
2316
  const hasBadges = isDeprecated || isInternal;
2190
- const header = (!(layoutOptions === null || layoutOptions === void 0 ? void 0 : layoutOptions.noHeading) || hasBadges) && (React.createElement(VStack, { spacing: 5 },
2191
- React.createElement(HStack, { spacing: 5 },
2192
- !(layoutOptions === null || layoutOptions === void 0 ? void 0 : layoutOptions.noHeading) && prettyName ? (React.createElement(Heading, { size: 1, fontWeight: "semibold" }, prettyName)) : null,
2193
- React.createElement(HStack, { spacing: 2 },
2194
- isDeprecated && React.createElement(DeprecatedBadge, null),
2195
- isInternal && React.createElement(InternalBadge, { isHttpService: true }))),
2196
- React.createElement(MethodPath, { method: data.method, path: data.path })));
2317
+ const header = (React.createElement(OperationHeader, { id: data.id, method: data.method, path: data.path, noHeading: layoutOptions === null || layoutOptions === void 0 ? void 0 : layoutOptions.noHeading, hasBadges: hasBadges, name: prettyName, isDeprecated: isDeprecated, isInternal: isInternal }));
2318
+ const descriptionChanged = nodeHasChanged === null || nodeHasChanged === void 0 ? void 0 : nodeHasChanged({ nodeId: data.id, attr: 'description' });
2197
2319
  const description = (React.createElement(VStack, { spacing: 10 },
2198
- data.description && React.createElement(MarkdownViewer, { className: "HttpOperation__Description", markdown: data.description }),
2320
+ data.description && (React.createElement(Box, { pos: "relative" },
2321
+ React.createElement(MarkdownViewer, { className: "HttpOperation__Description", markdown: data.description }),
2322
+ React.createElement(NodeAnnotation, { change: descriptionChanged }))),
2199
2323
  React.createElement(Request, { onChange: setTextRequestBodyIndex, operation: data }),
2200
2324
  data.responses && (React.createElement(Responses, { responses: data.responses, onMediaTypeChange: setResponseMediaType, onStatusCodeChange: setResponseStatusCode }))));
2201
2325
  const tryItPanel = !(layoutOptions === null || layoutOptions === void 0 ? void 0 : layoutOptions.hideTryItPanel) && (React.createElement(TryItWithRequestSamples, { httpOperation: data, responseMediaType: responseMediaType, responseStatusCode: responseStatusCode, requestBodyIndex: requestBodyIndex, hideTryIt: layoutOptions === null || layoutOptions === void 0 ? void 0 : layoutOptions.hideTryIt, tryItCredentialsPolicy: tryItCredentialsPolicy, mockUrl: mocking.hideMocking ? undefined : mocking.mockUrl, corsProxy: tryItCorsProxy }));
@@ -2217,12 +2341,34 @@ function MethodPath({ method, path }) {
2217
2341
  function MethodPathInner({ method, path, chosenServerUrl }) {
2218
2342
  const isDark = useThemeIsDark();
2219
2343
  const fullUrl = `${chosenServerUrl}${path}`;
2220
- const pathElem = (React.createElement(Flex, { overflowX: "hidden" },
2221
- chosenServerUrl ? (React.createElement(Box, { dir: "rtl", color: "muted", fontSize: "lg", textOverflow: "truncate", overflowX: "hidden" }, chosenServerUrl)) : null,
2222
- React.createElement(Box, { fontSize: "lg", fontWeight: "semibold", flex: 1 }, path)));
2344
+ const { leading, trailing } = useChosenServerUrl(chosenServerUrl);
2345
+ const pathElem = (React.createElement(Flex, { overflowX: "hidden", fontSize: "lg", userSelect: "all" },
2346
+ React.createElement(Box, { dir: "rtl", color: "muted", textOverflow: "truncate", overflowX: "hidden" },
2347
+ leading,
2348
+ trailing !== null && (React.createElement(Box, { as: "span", dir: "ltr", style: { unicodeBidi: 'bidi-override' } }, trailing))),
2349
+ React.createElement(Box, { fontWeight: "semibold", flex: 1 }, path)));
2223
2350
  return (React.createElement(HStack, { spacing: 3, pl: 2.5, pr: 4, py: 2, bg: "canvas-50", rounded: "lg", fontFamily: "mono", display: "inline-flex", maxW: "full", title: fullUrl },
2224
2351
  React.createElement(Box, { py: 1, px: 2.5, rounded: "lg", bg: !isDark ? HttpMethodColors[method] : 'canvas-100', color: !isDark ? 'on-primary' : 'body', fontSize: "lg", fontWeight: "semibold", textTransform: "uppercase" }, method),
2225
2352
  pathElem));
2353
+ }
2354
+ function OperationHeader({ id, noHeading, hasBadges, name, isDeprecated, isInternal, method, path, }) {
2355
+ const { nodeHasChanged } = useOptionsCtx();
2356
+ if (noHeading && !hasBadges) {
2357
+ return null;
2358
+ }
2359
+ const lineOneChanged = nodeHasChanged === null || nodeHasChanged === void 0 ? void 0 : nodeHasChanged({ nodeId: id, attr: ['iid', 'summary', 'deprecated', 'internal'] });
2360
+ const lineTwoChanged = nodeHasChanged === null || nodeHasChanged === void 0 ? void 0 : nodeHasChanged({ nodeId: id, attr: ['method', 'path'] });
2361
+ return (React.createElement(VStack, { spacing: 5 },
2362
+ React.createElement(Box, { pos: "relative" },
2363
+ React.createElement(HStack, { spacing: 5 },
2364
+ !noHeading && name ? (React.createElement(Heading, { size: 1, fontWeight: "semibold" }, name)) : null,
2365
+ React.createElement(HStack, { spacing: 2 },
2366
+ isDeprecated && React.createElement(DeprecatedBadge, null),
2367
+ isInternal && React.createElement(InternalBadge, { isHttpService: true }))),
2368
+ React.createElement(NodeAnnotation, { change: lineOneChanged })),
2369
+ React.createElement(Box, { pos: "relative" },
2370
+ React.createElement(MethodPath, { method: method, path: path }),
2371
+ React.createElement(NodeAnnotation, { change: lineTwoChanged }))));
2226
2372
  }
2227
2373
 
2228
2374
  const PoweredByLink = ({ source, pathname, packageType, layout = 'sidebar' }) => {
@@ -2233,7 +2379,9 @@ const PoweredByLink = ({ source, pathname, packageType, layout = 'sidebar' }) =>
2233
2379
  React.createElement("strong", null, "Stoplight"))));
2234
2380
  };
2235
2381
 
2236
- const AdditionalInfo = ({ termsOfService, contact, license }) => {
2382
+ const AdditionalInfo = ({ id, termsOfService, contact, license }) => {
2383
+ const { nodeHasChanged } = useOptionsCtx();
2384
+ const hasChanged = nodeHasChanged === null || nodeHasChanged === void 0 ? void 0 : nodeHasChanged({ nodeId: id, attr: ['termsOfService', 'contact', 'license'] });
2237
2385
  const contactLink = (contact === null || contact === void 0 ? void 0 : contact.name) && (contact === null || contact === void 0 ? void 0 : contact.url)
2238
2386
  ? `[Contact ${contact.name}](${contact.url})`
2239
2387
  : (contact === null || contact === void 0 ? void 0 : contact.email)
@@ -2242,12 +2390,13 @@ const AdditionalInfo = ({ termsOfService, contact, license }) => {
2242
2390
  const licenseUrl = (license === null || license === void 0 ? void 0 : license.url) || `https://spdx.org/licenses/${license === null || license === void 0 ? void 0 : license.identifier}.html`;
2243
2391
  const licenseLink = (license === null || license === void 0 ? void 0 : license.name) && licenseUrl ? `[${license.name} License](${licenseUrl})` : '';
2244
2392
  const tosLink = termsOfService ? `[Terms of Service](${termsOfService})` : '';
2245
- return contactLink || licenseLink || tosLink ? (React__default.createElement(Panel, { rounded: true, isCollapsible: false },
2393
+ return contactLink || licenseLink || tosLink ? (React__default.createElement(Panel, { rounded: true, isCollapsible: false, pos: "relative" },
2246
2394
  React__default.createElement(Panel.Titlebar, { bg: "canvas-300" },
2247
2395
  React__default.createElement("span", { role: "heading" }, "Additional Information")),
2248
2396
  React__default.createElement(Panel.Content, { p: 0 },
2249
2397
  React__default.createElement(Panel.Content, null,
2250
- React__default.createElement(MarkdownViewer, { style: { fontSize: 12 }, markdown: `${contactLink}\n \n${licenseLink}\n \n ${tosLink}` }))))) : null;
2398
+ React__default.createElement(MarkdownViewer, { style: { fontSize: 12 }, markdown: `${contactLink}\n \n${licenseLink}\n \n ${tosLink}` }))),
2399
+ React__default.createElement(NodeAnnotation, { change: hasChanged }))) : null;
2251
2400
  };
2252
2401
 
2253
2402
  const ExportButton = ({ original, bundled }) => {
@@ -2269,11 +2418,14 @@ const SecuritySchemes = ({ schemes, defaultScheme, defaultCollapsed = false, })
2269
2418
  React__default.createElement(Panel.Content, { p: 0 }, sortBy(schemes, 'type').map((scheme, i) => (React__default.createElement(SecurityScheme, { key: i, scheme: scheme, defaultIsOpen: defaultScheme ? scheme.key === defaultScheme : i === 0, isCollapsible: schemes.length > 1, showSchemeKey: shouldIncludeKey(schemes, scheme.type) }))))));
2270
2419
  };
2271
2420
  const SecurityScheme = ({ scheme, defaultIsOpen, isCollapsible, showSchemeKey }) => {
2272
- return (React__default.createElement(Panel, { defaultIsOpen: defaultIsOpen, isCollapsible: isCollapsible },
2421
+ const { nodeHasChanged } = useOptionsCtx();
2422
+ const hasChanged = nodeHasChanged === null || nodeHasChanged === void 0 ? void 0 : nodeHasChanged({ nodeId: scheme.id });
2423
+ return (React__default.createElement(Panel, { defaultIsOpen: defaultIsOpen, isCollapsible: isCollapsible, pos: "relative" },
2273
2424
  React__default.createElement(Panel.Titlebar, null,
2274
2425
  React__default.createElement(Box, { as: "span", role: "heading" }, getReadableSecurityName(scheme, showSchemeKey))),
2275
2426
  React__default.createElement(Panel.Content, null,
2276
- React__default.createElement(MarkdownViewer, { style: { fontSize: 12 }, markdown: `${scheme.description || ''}\n\n` + getDefaultDescription(scheme) }))));
2427
+ React__default.createElement(MarkdownViewer, { style: { fontSize: 12 }, markdown: `${scheme.description || ''}\n\n` + getDefaultDescription(scheme) })),
2428
+ React__default.createElement(NodeAnnotation, { change: hasChanged })));
2277
2429
  };
2278
2430
 
2279
2431
  const ServerInfo = ({ servers, mockUrl }) => {
@@ -2287,13 +2439,14 @@ const ServerInfo = ({ servers, mockUrl }) => {
2287
2439
  return (React.createElement(InvertTheme, null,
2288
2440
  React.createElement(Panel, { rounded: true, isCollapsible: false, className: "BaseURLContent", w: "full" },
2289
2441
  React.createElement(Panel.Titlebar, { whitespace: "nowrap" }, "API Base URL"),
2290
- React.createElement(Box, { overflowX: "auto" },
2291
- React.createElement(Panel.Content, { w: "full", className: "sl-flex sl-flex-col" },
2292
- React.createElement(VStack, { spacing: 1, divider: true }, serversToDisplay.map((server, index) => (React.createElement(ServerUrl, Object.assign({}, server, { key: index }))))))))));
2442
+ React.createElement(Panel.Content, { w: "full", className: "sl-flex sl-flex-col" },
2443
+ React.createElement(VStack, { spacing: 1, divider: true }, serversToDisplay.map((server, index) => (React.createElement(ServerUrl, Object.assign({}, server, { key: index })))))))));
2293
2444
  };
2294
- const ServerUrl = ({ description, url, marginBottom = true }) => {
2445
+ const ServerUrl = ({ id, description, url }) => {
2446
+ const { nodeHasChanged } = useOptionsCtx();
2295
2447
  const { onCopy, hasCopied } = useClipboard(url);
2296
- return (React.createElement(Box, { whitespace: "nowrap" },
2448
+ const hasChanged = nodeHasChanged === null || nodeHasChanged === void 0 ? void 0 : nodeHasChanged({ nodeId: id });
2449
+ return (React.createElement(Box, { whitespace: "nowrap", pos: "relative" },
2297
2450
  React.createElement(Text, { pr: 2, fontWeight: "bold" },
2298
2451
  description,
2299
2452
  ":"),
@@ -2303,26 +2456,37 @@ const ServerUrl = ({ description, url, marginBottom = true }) => {
2303
2456
  React.createElement(Icon, { className: "sl-ml-1", icon: ['fas', 'copy'] }))),
2304
2457
  hasCopied && (React.createElement(Box, { p: 1 },
2305
2458
  "Copied Server URL ",
2306
- React.createElement(Icon, { className: "sl-ml-1", icon: ['fas', 'check'] }))))));
2459
+ React.createElement(Icon, { className: "sl-ml-1", icon: ['fas', 'check'] })))),
2460
+ React.createElement(NodeAnnotation, { change: hasChanged, additionalLeftOffset: 16 })));
2307
2461
  };
2308
2462
 
2309
- const HttpServiceComponent = React.memo(({ data, location = {}, layoutOptions, exportProps }) => {
2463
+ const HttpServiceComponent = React.memo(({ data: unresolvedData, location = {}, layoutOptions, exportProps }) => {
2310
2464
  var _a, _b, _c, _d;
2465
+ const { nodeHasChanged } = useOptionsCtx();
2466
+ const data = useResolvedObject(unresolvedData);
2311
2467
  const { search, pathname } = location;
2312
2468
  const mocking = React.useContext(MockingContext);
2313
2469
  const query = new URLSearchParams(search);
2470
+ const nameChanged = nodeHasChanged === null || nodeHasChanged === void 0 ? void 0 : nodeHasChanged({ nodeId: data.id, attr: 'name' });
2471
+ const versionChanged = nodeHasChanged === null || nodeHasChanged === void 0 ? void 0 : nodeHasChanged({ nodeId: data.id, attr: 'version' });
2472
+ const descriptionChanged = nodeHasChanged === null || nodeHasChanged === void 0 ? void 0 : nodeHasChanged({ nodeId: data.id, attr: 'description' });
2314
2473
  return (React.createElement(Box, { mb: 10 },
2315
2474
  data.name && !(layoutOptions === null || layoutOptions === void 0 ? void 0 : layoutOptions.noHeading) && (React.createElement(Flex, { justifyContent: "between", alignItems: "center" },
2316
- React.createElement(Heading, { size: 1, mb: 4, fontWeight: "semibold" }, data.name),
2475
+ React.createElement(Box, { pos: "relative" },
2476
+ React.createElement(Heading, { size: 1, mb: 4, fontWeight: "semibold" }, data.name),
2477
+ React.createElement(NodeAnnotation, { change: nameChanged })),
2317
2478
  exportProps && !(layoutOptions === null || layoutOptions === void 0 ? void 0 : layoutOptions.hideExport) && React.createElement(ExportButton, Object.assign({}, exportProps)))),
2318
- data.version && (React.createElement(Box, { mb: 5 },
2319
- React.createElement(VersionBadge, { value: data.version }))),
2479
+ data.version && (React.createElement(Box, { mb: 5, pos: "relative" },
2480
+ React.createElement(VersionBadge, { value: data.version }),
2481
+ React.createElement(NodeAnnotation, { change: versionChanged }))),
2320
2482
  pathname && (layoutOptions === null || layoutOptions === void 0 ? void 0 : layoutOptions.showPoweredByLink) && (React.createElement(PoweredByLink, { source: (_a = data.name) !== null && _a !== void 0 ? _a : 'no-title', pathname: pathname, packageType: "elements", layout: "stacked" })),
2321
2483
  React.createElement(VStack, { spacing: 6 },
2322
2484
  React.createElement(ServerInfo, { servers: (_b = data.servers) !== null && _b !== void 0 ? _b : [], mockUrl: mocking.mockUrl }),
2323
- React.createElement(Box, null, ((_c = data.securitySchemes) === null || _c === void 0 ? void 0 : _c.length) && (React.createElement(SecuritySchemes, { schemes: data.securitySchemes, defaultScheme: query.get('security') || undefined }))),
2324
- React.createElement(Box, null, (((_d = data.contact) === null || _d === void 0 ? void 0 : _d.email) || data.license || data.termsOfService) && (React.createElement(AdditionalInfo, { contact: data.contact, license: data.license, termsOfService: data.termsOfService })))),
2325
- data.description && React.createElement(MarkdownViewer, { className: "sl-my-5", markdown: data.description })));
2485
+ React.createElement(Box, null, ((_c = data.securitySchemes) === null || _c === void 0 ? void 0 : _c.length) ? (React.createElement(SecuritySchemes, { schemes: data.securitySchemes, defaultScheme: query.get('security') || undefined })) : null),
2486
+ React.createElement(Box, null, (((_d = data.contact) === null || _d === void 0 ? void 0 : _d.email) || data.license || data.termsOfService) && (React.createElement(AdditionalInfo, { id: data.id, contact: data.contact, license: data.license, termsOfService: data.termsOfService })))),
2487
+ data.description && (React.createElement(Box, { pos: "relative" },
2488
+ React.createElement(MarkdownViewer, { className: "sl-my-5", markdown: data.description }),
2489
+ React.createElement(NodeAnnotation, { change: descriptionChanged })))));
2326
2490
  });
2327
2491
  HttpServiceComponent.displayName = 'HttpService.Component';
2328
2492
  const HttpService = withErrorBoundary(HttpServiceComponent, { recoverableProps: ['data'] });
@@ -2344,23 +2508,31 @@ function useIsCompact(layoutOptions) {
2344
2508
  }
2345
2509
 
2346
2510
  const ModelComponent = ({ data: unresolvedData, className, nodeTitle, layoutOptions, exportProps, }) => {
2347
- var _a;
2511
+ var _a, _b;
2348
2512
  const resolveRef = useInlineRefResolver();
2349
2513
  const data = useResolvedObject(unresolvedData);
2514
+ const { nodeHasChanged } = useOptionsCtx();
2350
2515
  const { ref: layoutRef, isCompact } = useIsCompact(layoutOptions);
2351
- const title = (_a = data.title) !== null && _a !== void 0 ? _a : nodeTitle;
2516
+ const nodeId = (_a = data === null || data === void 0 ? void 0 : data['x-stoplight']) === null || _a === void 0 ? void 0 : _a.id;
2517
+ const title = (_b = data.title) !== null && _b !== void 0 ? _b : nodeTitle;
2352
2518
  const isInternal = !!data['x-internal'];
2353
2519
  const shouldDisplayHeader = !(layoutOptions === null || layoutOptions === void 0 ? void 0 : layoutOptions.noHeading) && (title !== undefined || (exportProps && !(layoutOptions === null || layoutOptions === void 0 ? void 0 : layoutOptions.hideExport)));
2520
+ const titleChanged = nodeHasChanged === null || nodeHasChanged === void 0 ? void 0 : nodeHasChanged({ nodeId, attr: ['title', 'internal'] });
2354
2521
  const header = (shouldDisplayHeader || isInternal) && (React.createElement(Flex, { justifyContent: "between", alignItems: "center" },
2355
- React.createElement(HStack, { spacing: 5 },
2356
- title && (React.createElement(Heading, { size: 1, fontWeight: "semibold" }, title)),
2357
- React.createElement(HStack, { spacing: 2 }, isInternal && React.createElement(InternalBadge, null))),
2522
+ React.createElement(Box, { pos: "relative" },
2523
+ React.createElement(HStack, { spacing: 5 },
2524
+ title && (React.createElement(Heading, { size: 1, fontWeight: "semibold" }, title)),
2525
+ React.createElement(HStack, { spacing: 2 }, isInternal && React.createElement(InternalBadge, null))),
2526
+ React.createElement(NodeAnnotation, { change: titleChanged })),
2358
2527
  exportProps && !(layoutOptions === null || layoutOptions === void 0 ? void 0 : layoutOptions.hideExport) && React.createElement(ExportButton, Object.assign({}, exportProps))));
2359
2528
  const modelExamples = !(layoutOptions === null || layoutOptions === void 0 ? void 0 : layoutOptions.hideModelExamples) && React.createElement(ModelExamples, { data: data, isCollapsible: isCompact });
2529
+ const descriptionChanged = nodeHasChanged === null || nodeHasChanged === void 0 ? void 0 : nodeHasChanged({ nodeId, attr: 'description' });
2360
2530
  const description = (React.createElement(VStack, { spacing: 10 },
2361
- data.description && data.type === 'object' && React.createElement(MarkdownViewer, { role: "textbox", markdown: data.description }),
2531
+ data.description && data.type === 'object' && (React.createElement(Box, { pos: "relative" },
2532
+ React.createElement(MarkdownViewer, { role: "textbox", markdown: data.description }),
2533
+ React.createElement(NodeAnnotation, { change: descriptionChanged }))),
2362
2534
  isCompact && modelExamples,
2363
- React.createElement(JsonSchemaViewer, { resolveRef: resolveRef, schema: getOriginalObject(data) })));
2535
+ React.createElement(JsonSchemaViewer, { resolveRef: resolveRef, schema: getOriginalObject(data), nodeHasChanged: nodeHasChanged, skipTopLevelDescription: true })));
2364
2536
  return (React.createElement(TwoColumnLayout, { ref: layoutRef, className: cn('Model', className), header: header, left: description, right: !isCompact && modelExamples }));
2365
2537
  };
2366
2538
  const ModelExamples = React.memo(({ data, isCollapsible = false }) => {
@@ -2382,16 +2554,16 @@ const ModelExamples = React.memo(({ data, isCollapsible = false }) => {
2382
2554
  const Model = withErrorBoundary(ModelComponent, { recoverableProps: ['data'] });
2383
2555
 
2384
2556
  const Docs = React.memo((_a) => {
2385
- var { nodeType, nodeData, useNodeForRefResolving = false, refResolver } = _a, commonProps = __rest(_a, ["nodeType", "nodeData", "useNodeForRefResolving", "refResolver"]);
2557
+ var { nodeType, nodeData, useNodeForRefResolving = false, refResolver, nodeHasChanged } = _a, commonProps = __rest(_a, ["nodeType", "nodeData", "useNodeForRefResolving", "refResolver", "nodeHasChanged"]);
2386
2558
  const parsedNode = useParsedData(nodeType, nodeData);
2387
2559
  if (!parsedNode) {
2388
2560
  return null;
2389
2561
  }
2390
- const parsedDocs = React.createElement(ParsedDocs, Object.assign({ node: parsedNode }, commonProps));
2562
+ let elem = React.createElement(ParsedDocs, Object.assign({ node: parsedNode }, commonProps));
2391
2563
  if (useNodeForRefResolving) {
2392
- return (React.createElement(InlineRefResolverProvider, { document: parsedNode.data, resolver: refResolver }, parsedDocs));
2564
+ elem = (React.createElement(InlineRefResolverProvider, { document: parsedNode.data, resolver: refResolver }, elem));
2393
2565
  }
2394
- return parsedDocs;
2566
+ return React.createElement(ElementsOptionsProvider, { nodeHasChanged: nodeHasChanged }, elem);
2395
2567
  });
2396
2568
  const ParsedDocs = (_a) => {
2397
2569
  var { node } = _a, commonProps = __rest(_a, ["node"]);
@@ -2819,16 +2991,33 @@ const useRouter = (router, basePath, staticRouterPath) => {
2819
2991
  };
2820
2992
  };
2821
2993
 
2994
+ const components = {
2995
+ a: ReactRouterMarkdownLink,
2996
+ h2: (_a) => {
2997
+ var props = __rest(_a, ["color"]);
2998
+ return React.createElement(LinkHeading, Object.assign({ size: 2 }, props));
2999
+ },
3000
+ h3: (_a) => {
3001
+ var props = __rest(_a, ["color"]);
3002
+ return React.createElement(LinkHeading, Object.assign({ size: 3 }, props));
3003
+ },
3004
+ h4: (_a) => {
3005
+ var props = __rest(_a, ["color"]);
3006
+ return React.createElement(LinkHeading, Object.assign({ size: 4 }, props));
3007
+ },
3008
+ };
2822
3009
  function withRouter(WrappedComponent) {
2823
3010
  const WithRouter = (props) => {
2824
3011
  var _a, _b, _c;
2825
3012
  const basePath = (_a = props.basePath) !== null && _a !== void 0 ? _a : '/';
2826
3013
  const staticRouterPath = (_b = props.staticRouterPath) !== null && _b !== void 0 ? _b : '';
2827
- const { Router, routerProps } = useRouter((_c = props.router) !== null && _c !== void 0 ? _c : 'history', basePath, staticRouterPath);
2828
- return (React.createElement(Router, Object.assign({}, routerProps, { key: basePath }),
2829
- React.createElement(Route, { path: "/" },
2830
- React.createElement(MarkdownComponentsProvider, { value: { a: ReactRouterMarkdownLink } },
2831
- React.createElement(WrappedComponent, Object.assign({}, props))))));
3014
+ const routerType = (_c = props.router) !== null && _c !== void 0 ? _c : 'history';
3015
+ const { Router, routerProps } = useRouter(routerType, basePath, staticRouterPath);
3016
+ return (React.createElement(RouterTypeContext.Provider, { value: routerType },
3017
+ React.createElement(Router, Object.assign({}, routerProps, { key: basePath }),
3018
+ React.createElement(Route, { path: "/" },
3019
+ React.createElement(MarkdownComponentsProvider, { value: components },
3020
+ React.createElement(WrappedComponent, Object.assign({}, props)))))));
2832
3021
  };
2833
3022
  WithRouter.displayName = `WithRouter(${getDisplayName(WrappedComponent)})`;
2834
3023
  return WithRouter;