@stoplight/elements-core 7.6.5 → 7.7.1

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.js CHANGED
@@ -6,11 +6,11 @@ var tslib = require('tslib');
6
6
  var React = require('react');
7
7
  var json = require('@stoplight/json');
8
8
  var isArray = require('lodash/isArray.js');
9
- var isObject = require('lodash/isObject.js');
10
9
  var isPlainObject = require('lodash/isPlainObject.js');
11
10
  var types = require('@stoplight/types');
12
11
  var yaml = require('@stoplight/yaml');
13
12
  var mosaic = require('@stoplight/mosaic');
13
+ var isObject = require('lodash/isObject.js');
14
14
  var reactErrorBoundary = require('@stoplight/react-error-boundary');
15
15
  var markdownViewer = require('@stoplight/markdown-viewer');
16
16
  var cn = require('classnames');
@@ -39,9 +39,9 @@ var uniqBy = require('lodash/uniqBy.js');
39
39
  var formatXml = require('xml-formatter');
40
40
  var entries = require('lodash/entries.js');
41
41
  var keys = require('lodash/keys.js');
42
+ var reactRouterDom = require('react-router-dom');
42
43
  var jsonSchemaViewer = require('@stoplight/json-schema-viewer');
43
44
  var sortBy = require('lodash/sortBy.js');
44
- var reactRouterDom = require('react-router-dom');
45
45
  var reactRouterHashLink = require('react-router-hash-link');
46
46
  var reactQuery = require('react-query');
47
47
  var $RefParser = require('@stoplight/json-schema-ref-parser');
@@ -72,8 +72,8 @@ function _interopNamespace(e) {
72
72
  var React__namespace = /*#__PURE__*/_interopNamespace(React);
73
73
  var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
74
74
  var isArray__default = /*#__PURE__*/_interopDefaultLegacy(isArray);
75
- var isObject__default = /*#__PURE__*/_interopDefaultLegacy(isObject);
76
75
  var isPlainObject__default = /*#__PURE__*/_interopDefaultLegacy(isPlainObject);
76
+ var isObject__default = /*#__PURE__*/_interopDefaultLegacy(isObject);
77
77
  var cn__default = /*#__PURE__*/_interopDefaultLegacy(cn);
78
78
  var URI__default = /*#__PURE__*/_interopDefaultLegacy(URI);
79
79
  var HTTPSnippet__default = /*#__PURE__*/_interopDefaultLegacy(HTTPSnippet);
@@ -159,7 +159,7 @@ const isResolvedObjectProxy = (someObject) => {
159
159
  const getOriginalObject = (resolvedObject) => {
160
160
  return resolvedObject[originalObjectSymbol] || resolvedObject;
161
161
  };
162
- const isReference = (value) => isObject__default["default"](value) && typeof value['$ref'] === 'string';
162
+ const isReference = json.hasRef;
163
163
 
164
164
  const InlineRefResolverContext = React__namespace.createContext(undefined);
165
165
  InlineRefResolverContext.displayName = 'InlineRefResolverContext';
@@ -179,6 +179,15 @@ const useResolvedObject = (currentObject) => {
179
179
  return React__namespace.useMemo(() => createResolvedObject(currentObject, { contextObject: document, resolver }), [currentObject, document, resolver]);
180
180
  };
181
181
 
182
+ const DEFAULT_CONTEXT = {};
183
+ const ElementsOptionsContext = React__namespace.createContext(DEFAULT_CONTEXT);
184
+ const useOptionsCtx = () => {
185
+ return React__namespace.useContext(ElementsOptionsContext) || DEFAULT_CONTEXT;
186
+ };
187
+ function ElementsOptionsProvider({ children, nodeHasChanged }) {
188
+ return (React__namespace.createElement(ElementsOptionsContext.Provider, { value: Object.assign({}, DEFAULT_CONTEXT, { nodeHasChanged }) }, children));
189
+ }
190
+
182
191
  function isSMDASTRoot(maybeAst) {
183
192
  return isObject__default["default"](maybeAst) && maybeAst['type'] === 'root' && mosaic.isArray(maybeAst['children']);
184
193
  }
@@ -212,6 +221,7 @@ const parserMap = {
212
221
  [types.NodeType.TableOfContents]: parseUnknown,
213
222
  [types.NodeType.SpectralRuleset]: parseUnknown,
214
223
  [types.NodeType.Styleguide]: parseUnknown,
224
+ [types.NodeType.Image]: parseUnknown,
215
225
  [types.NodeType.Unknown]: parseUnknown,
216
226
  };
217
227
  function parseArticleData(rawData) {
@@ -325,6 +335,11 @@ var faEye = {
325
335
  iconName: 'eye',
326
336
  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"]
327
337
  };
338
+ var faImage = {
339
+ prefix: 'fas',
340
+ iconName: 'image',
341
+ 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"]
342
+ };
328
343
  var faServer = {
329
344
  prefix: 'fas',
330
345
  iconName: 'server',
@@ -342,6 +357,7 @@ const NodeTypeColors = {
342
357
  table_of_contents: '',
343
358
  spectral_ruleset: '',
344
359
  styleguide: '',
360
+ image: '',
345
361
  };
346
362
  const NodeTypePrettyName = {
347
363
  http_operation: 'Endpoint',
@@ -354,6 +370,7 @@ const NodeTypePrettyName = {
354
370
  table_of_contents: '',
355
371
  spectral_ruleset: '',
356
372
  styleguide: '',
373
+ image: '',
357
374
  };
358
375
  const NodeTypeIconDefs = {
359
376
  http_operation: faCrosshairs,
@@ -366,6 +383,7 @@ const NodeTypeIconDefs = {
366
383
  table_of_contents: faQuestionCircle,
367
384
  spectral_ruleset: faQuestionCircle,
368
385
  styleguide: faQuestionCircle,
386
+ image: faImage,
369
387
  };
370
388
  const HttpMethodColors = {
371
389
  get: 'success',
@@ -493,6 +511,7 @@ const getServersToDisplay = (originalServers, mockUrl) => {
493
511
  .filter(isValidServer);
494
512
  if (mockUrl) {
495
513
  servers.push({
514
+ id: 'mock',
496
515
  description: 'Mock Server',
497
516
  url: mockUrl,
498
517
  });
@@ -682,15 +701,12 @@ const requestSampleConfigs = {
682
701
  mosaicCodeViewerLanguage: 'php',
683
702
  httpSnippetLanguage: 'php',
684
703
  libraries: {
685
- 'pecl/http 1': {
686
- httpSnippetLibrary: 'http1',
687
- },
688
- 'pecl/http 2': {
689
- httpSnippetLibrary: 'http2',
690
- },
691
704
  cURL: {
692
705
  httpSnippetLibrary: 'curl',
693
706
  },
707
+ guzzle: {
708
+ httpSnippetLibrary: 'guzzle',
709
+ },
694
710
  },
695
711
  },
696
712
  Powershell: {
@@ -1053,9 +1069,12 @@ function parameterSupportsFileUpload(parameter) {
1053
1069
  (((_b = parameter.schema) === null || _b === void 0 ? void 0 : _b.contentEncoding) === 'base64' ||
1054
1070
  ((_c = parameter.schema) === null || _c === void 0 ? void 0 : _c.contentMediaType) === 'application/octet-stream'));
1055
1071
  }
1072
+ function stringifyValue(value) {
1073
+ return typeof value === 'object' ? JSON.stringify(value) : escapeQuotes(String(value));
1074
+ }
1056
1075
  function exampleValue(example) {
1057
1076
  const value = 'value' in example ? example.value : example.externalValue;
1058
- return escapeQuotes(String(value));
1077
+ return stringifyValue(value);
1059
1078
  }
1060
1079
  function escapeQuotes(value) {
1061
1080
  return value.replace(/"/g, '\\"');
@@ -1076,7 +1095,7 @@ const getValueForParameter = (parameter) => {
1076
1095
  var _a, _b, _c;
1077
1096
  const defaultValue = retrieveDefaultFromSchema(parameter);
1078
1097
  if (typeof defaultValue !== 'undefined') {
1079
- return { value: String(defaultValue), isDefault: true };
1098
+ return { value: stringifyValue(defaultValue), isDefault: true };
1080
1099
  }
1081
1100
  const examples = (_a = parameter.examples) !== null && _a !== void 0 ? _a : [];
1082
1101
  if (examples.length > 0) {
@@ -1084,7 +1103,7 @@ const getValueForParameter = (parameter) => {
1084
1103
  }
1085
1104
  const enums = (_c = (_b = parameter.schema) === null || _b === void 0 ? void 0 : _b.enum) !== null && _c !== void 0 ? _c : [];
1086
1105
  if (enums.length > 0) {
1087
- return { value: String(enums[0]) };
1106
+ return { value: stringifyValue(enums[0]) };
1088
1107
  }
1089
1108
  return { value: '' };
1090
1109
  };
@@ -1369,13 +1388,77 @@ const getServerUrl = ({ chosenServer, httpOperation, mockData, corsProxy, }) =>
1369
1388
  }
1370
1389
  return serverUrl;
1371
1390
  };
1391
+ const getQueryParams = ({ httpOperation, parameterValues, }) => {
1392
+ var _a;
1393
+ const query = (_a = httpOperation.request) === null || _a === void 0 ? void 0 : _a.query;
1394
+ if (!query)
1395
+ return [];
1396
+ return query.reduce((acc, param) => {
1397
+ var _a, _b, _c, _d, _e;
1398
+ const value = (_a = parameterValues[param.name]) !== null && _a !== void 0 ? _a : '';
1399
+ if (value.length === 0)
1400
+ return acc;
1401
+ const explode = (_b = param.explode) !== null && _b !== void 0 ? _b : true;
1402
+ if (((_c = param.schema) === null || _c === void 0 ? void 0 : _c.type) === 'object' && param.style === 'form' && value) {
1403
+ let nested;
1404
+ try {
1405
+ nested = JSON.parse(value);
1406
+ if (!(typeof nested === 'object' && nested !== null))
1407
+ throw Error();
1408
+ }
1409
+ catch (e) {
1410
+ throw new Error(`Cannot use param value "${value}". JSON object expected.`);
1411
+ }
1412
+ if (explode) {
1413
+ acc.push(...Object.entries(nested).map(([name, value]) => ({ name, value: value.toString() })));
1414
+ }
1415
+ else {
1416
+ acc.push({
1417
+ name: param.name,
1418
+ value: Object.entries(nested)
1419
+ .map(entry => entry.join(','))
1420
+ .join(','),
1421
+ });
1422
+ }
1423
+ }
1424
+ else if (((_d = param.schema) === null || _d === void 0 ? void 0 : _d.type) === 'array' && value) {
1425
+ let nested;
1426
+ try {
1427
+ nested = JSON.parse(value);
1428
+ if (!Array.isArray(nested))
1429
+ throw Error();
1430
+ }
1431
+ catch (e) {
1432
+ throw new Error(`Cannot use param value "${value}". JSON array expected.`);
1433
+ }
1434
+ if (explode) {
1435
+ acc.push(...nested.map(value => ({ name: param.name, value: value.toString() })));
1436
+ }
1437
+ else {
1438
+ const delimiter = {
1439
+ [types.HttpParamStyles.Form]: ',',
1440
+ [types.HttpParamStyles.SpaceDelimited]: ' ',
1441
+ [types.HttpParamStyles.PipeDelimited]: '|',
1442
+ };
1443
+ acc.push({
1444
+ name: param.name,
1445
+ value: nested.join((_e = delimiter[param.style]) !== null && _e !== void 0 ? _e : delimiter[types.HttpParamStyles.Form]),
1446
+ });
1447
+ }
1448
+ }
1449
+ else {
1450
+ acc.push({ name: param.name, value });
1451
+ }
1452
+ return acc;
1453
+ }, []);
1454
+ };
1372
1455
  function buildFetchRequest({ httpOperation, mediaTypeContent, bodyInput, parameterValues, mockData, auth, chosenServer, credentials = 'omit', corsProxy, }) {
1373
- var _a, _b, _c, _d, _e, _f;
1456
+ var _a, _b, _c;
1374
1457
  return tslib.__awaiter(this, void 0, void 0, function* () {
1375
1458
  const serverUrl = getServerUrl({ httpOperation, mockData, chosenServer, corsProxy });
1376
1459
  const shouldIncludeBody = ['PUT', 'POST', 'PATCH'].includes(httpOperation.method.toUpperCase());
1377
- 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 : [];
1378
- const rawHeaders = filterOutAuthorizationParams((_e = (_d = httpOperation.request) === null || _d === void 0 ? void 0 : _d.headers) !== null && _e !== void 0 ? _e : [], httpOperation.security)
1460
+ const queryParams = getQueryParams({ httpOperation, parameterValues });
1461
+ const rawHeaders = filterOutAuthorizationParams((_b = (_a = httpOperation.request) === null || _a === void 0 ? void 0 : _a.headers) !== null && _b !== void 0 ? _b : [], httpOperation.security)
1379
1462
  .map(header => { var _a; return ({ name: header.name, value: (_a = parameterValues[header.name]) !== null && _a !== void 0 ? _a : '' }); })
1380
1463
  .filter(({ value }) => value.length > 0);
1381
1464
  const [queryParamsWithAuth, headersWithAuth] = runAuthRequestEhancements(auth, queryParams, rawHeaders);
@@ -1384,7 +1467,7 @@ function buildFetchRequest({ httpOperation, mediaTypeContent, bodyInput, paramet
1384
1467
  urlObject.search = new URLSearchParams(queryParamsWithAuth.map(nameAndValueObjectToPair)).toString();
1385
1468
  const body = typeof bodyInput === 'object' ? yield createRequestBody(mediaTypeContent, bodyInput) : bodyInput;
1386
1469
  const headers = Object.assign(Object.assign(Object.assign({}, ((mediaTypeContent === null || mediaTypeContent === void 0 ? void 0 : mediaTypeContent.mediaType) !== 'multipart/form-data' && {
1387
- 'Content-Type': (_f = mediaTypeContent === null || mediaTypeContent === void 0 ? void 0 : mediaTypeContent.mediaType) !== null && _f !== void 0 ? _f : 'application/json',
1470
+ 'Content-Type': (_c = mediaTypeContent === null || mediaTypeContent === void 0 ? void 0 : mediaTypeContent.mediaType) !== null && _c !== void 0 ? _c : 'application/json',
1388
1471
  })), Object.fromEntries(headersWithAuth.map(nameAndValueObjectToPair))), mockData === null || mockData === void 0 ? void 0 : mockData.header);
1389
1472
  return [
1390
1473
  urlObject.href,
@@ -1444,13 +1527,13 @@ const runAuthRequestEhancements = (auth, queryParams, headers) => {
1444
1527
  return [newQueryParams, newHeaders];
1445
1528
  };
1446
1529
  function buildHarRequest({ httpOperation, bodyInput, parameterValues, mediaTypeContent, auth, mockData, chosenServer, corsProxy, }) {
1447
- var _a, _b, _c, _d, _e, _f, _g;
1530
+ var _a, _b, _c, _d;
1448
1531
  return tslib.__awaiter(this, void 0, void 0, function* () {
1449
1532
  const serverUrl = getServerUrl({ httpOperation, mockData, chosenServer, corsProxy });
1450
1533
  const mimeType = (_a = mediaTypeContent === null || mediaTypeContent === void 0 ? void 0 : mediaTypeContent.mediaType) !== null && _a !== void 0 ? _a : 'application/json';
1451
1534
  const shouldIncludeBody = ['PUT', 'POST', 'PATCH'].includes(httpOperation.method.toUpperCase());
1452
- 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 : [];
1453
- 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 : [];
1535
+ const queryParams = getQueryParams({ httpOperation, parameterValues });
1536
+ 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 : [];
1454
1537
  if (mockData === null || mockData === void 0 ? void 0 : mockData.header) {
1455
1538
  headerParams.push({ name: 'Prefer', value: mockData.header.Prefer });
1456
1539
  }
@@ -2059,9 +2142,28 @@ ${scopes.map(([key, value]) => `- \`${key}\` - ${value}`).join('\n')}`;
2059
2142
  return description;
2060
2143
  }
2061
2144
 
2145
+ const RouterTypeContext = React__namespace.createContext(null);
2146
+ const useRouterType = () => {
2147
+ return React__namespace.useContext(RouterTypeContext);
2148
+ };
2149
+
2150
+ const LinkHeading = React__namespace.memo(function LinkHeading(props) {
2151
+ const isUsingRouter = !!useRouterType();
2152
+ const Comp = isUsingRouter ? CustomLinkHeading : mosaic.LinkHeading;
2153
+ return React__namespace.createElement(Comp, Object.assign({}, props));
2154
+ });
2155
+ const CustomLinkHeading = React__namespace.memo(function LinkHeading(_a) {
2156
+ var { id: _id } = _a, props = tslib.__rest(_a, ["id"]);
2157
+ const { pathname } = reactRouterDom.useLocation();
2158
+ const routerKind = React__namespace.useContext(RouterTypeContext);
2159
+ const route = pathname.split('#')[0];
2160
+ const id = routerKind === 'hash' ? `${route}#${_id}` : _id;
2161
+ return React__namespace.createElement(mosaic.LinkHeading, Object.assign({ id: id }, props));
2162
+ });
2163
+
2062
2164
  const SectionTitle = ({ title, id, size = 2, children }) => {
2063
2165
  return (React__namespace.createElement(mosaic.HStack, { spacing: 6 },
2064
- React__namespace.createElement(mosaic.Box, { as: mosaic.LinkHeading, size: size, "aria-label": title, id: id || slugify(title) }, title),
2166
+ React__namespace.createElement(mosaic.Box, { as: LinkHeading, size: size, "aria-label": title, id: id || slugify(title) }, title),
2065
2167
  children));
2066
2168
  };
2067
2169
  const SectionSubtitle = props => {
@@ -2084,6 +2186,7 @@ const Body = ({ body, onChange }) => {
2084
2186
  var _a;
2085
2187
  const refResolver = useInlineRefResolver();
2086
2188
  const [chosenContent, setChosenContent] = React__namespace.useState(0);
2189
+ const { nodeHasChanged } = useOptionsCtx();
2087
2190
  React__namespace.useEffect(() => {
2088
2191
  onChange(chosenContent);
2089
2192
  }, [chosenContent]);
@@ -2091,11 +2194,14 @@ const Body = ({ body, onChange }) => {
2091
2194
  return null;
2092
2195
  const { contents = [], description } = body;
2093
2196
  const schema = (_a = contents[chosenContent]) === null || _a === void 0 ? void 0 : _a.schema;
2197
+ const descriptionChanged = nodeHasChanged === null || nodeHasChanged === void 0 ? void 0 : nodeHasChanged({ nodeId: body.id, attr: 'description' });
2094
2198
  return (React__namespace.createElement(mosaic.VStack, { spacing: 6 },
2095
2199
  React__namespace.createElement(SectionSubtitle, { title: "Body", id: "request-body" }, contents.length > 0 && (React__namespace.createElement(mosaic.Flex, { flex: 1, justify: "end" },
2096
2200
  React__namespace.createElement(mosaic.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" })))),
2097
- description && React__namespace.createElement(MarkdownViewer, { markdown: description }),
2098
- isJSONSchema(schema) && (React__namespace.createElement(jsonSchemaViewer.JsonSchemaViewer, { resolveRef: refResolver, schema: getOriginalObject(schema), viewMode: "write", renderRootTreeLines: true }))));
2201
+ description && (React__namespace.createElement(mosaic.Box, { pos: "relative" },
2202
+ React__namespace.createElement(MarkdownViewer, { markdown: description }),
2203
+ React__namespace.createElement(mosaic.NodeAnnotation, { change: descriptionChanged }))),
2204
+ isJSONSchema(schema) && (React__namespace.createElement(jsonSchemaViewer.JsonSchemaViewer, { resolveRef: refResolver, schema: getOriginalObject(schema), viewMode: "write", renderRootTreeLines: true, nodeHasChanged: nodeHasChanged }))));
2099
2205
  };
2100
2206
  Body.displayName = 'HttpOperation.Body';
2101
2207
 
@@ -2119,14 +2225,16 @@ const defaultStyle = {
2119
2225
  cookie: types.HttpParamStyles.Form,
2120
2226
  };
2121
2227
  const Parameters = ({ parameters, parameterType }) => {
2228
+ const { nodeHasChanged } = useOptionsCtx();
2229
+ const refResolver = useInlineRefResolver();
2122
2230
  const schema = React__namespace.useMemo(() => httpOperationParamsToSchema({ parameters, parameterType }), [parameters, parameterType]);
2123
2231
  if (!schema)
2124
2232
  return null;
2125
- return React__namespace.createElement(jsonSchemaViewer.JsonSchemaViewer, { schema: schema, disableCrumbs: true });
2233
+ return React__namespace.createElement(jsonSchemaViewer.JsonSchemaViewer, { resolveRef: refResolver, schema: schema, disableCrumbs: true, nodeHasChanged: nodeHasChanged });
2126
2234
  };
2127
2235
  Parameters.displayName = 'HttpOperation.Parameters';
2128
2236
  const httpOperationParamsToSchema = ({ parameters, parameterType }) => {
2129
- var _a;
2237
+ var _a, _b, _c;
2130
2238
  if (!parameters || !parameters.length)
2131
2239
  return null;
2132
2240
  const schema = {
@@ -2135,8 +2243,6 @@ const httpOperationParamsToSchema = ({ parameters, parameterType }) => {
2135
2243
  };
2136
2244
  const sortedParams = sortBy__default["default"](parameters, ['required', 'name']);
2137
2245
  for (const p of sortedParams) {
2138
- if (!p.schema)
2139
- continue;
2140
2246
  const { name, description, required, deprecated, examples, style } = p;
2141
2247
  const paramExamples = (examples === null || examples === void 0 ? void 0 : examples.map(example => {
2142
2248
  if (isNodeExample(example)) {
@@ -2146,10 +2252,10 @@ const httpOperationParamsToSchema = ({ parameters, parameterType }) => {
2146
2252
  })) || [];
2147
2253
  const schemaExamples = (_a = p.schema) === null || _a === void 0 ? void 0 : _a.examples;
2148
2254
  const schemaExamplesArray = Array.isArray(schemaExamples) ? schemaExamples : [];
2149
- const paramDescription = description || p.schema.description;
2255
+ const paramDescription = description || ((_b = p.schema) === null || _b === void 0 ? void 0 : _b.description);
2150
2256
  const paramDeprecated = deprecated || p.schema.deprecated;
2151
2257
  const paramStyle = style && defaultStyle[parameterType] !== style ? readableStyles[style] || style : undefined;
2152
- schema.properties[p.name] = Object.assign(Object.assign({}, p.schema), { description: paramDescription, examples: [...paramExamples, ...schemaExamplesArray], deprecated: paramDeprecated, style: paramStyle });
2258
+ 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 }) });
2153
2259
  if (required) {
2154
2260
  schema.required.push(name);
2155
2261
  }
@@ -2172,7 +2278,7 @@ const Request = ({ operation: { request, request: { path: pathParams = [], heade
2172
2278
  return null;
2173
2279
  return (React__namespace.createElement(mosaic.VStack, { spacing: 8 },
2174
2280
  React__namespace.createElement(SectionTitle, { title: "Request" }),
2175
- securitySchemes.length > 0 && (React__namespace.createElement(mosaic.VStack, { spacing: 3 }, securitySchemes.map((scheme, i) => (React__namespace.createElement(SecurityPanel, { key: i, scheme: scheme, includeKey: shouldIncludeKey(securitySchemes, scheme.type) }))))),
2281
+ React__namespace.createElement(SecuritySchemes$1, { schemes: securitySchemes }),
2176
2282
  pathParams.length > 0 && (React__namespace.createElement(mosaic.VStack, { spacing: 5 },
2177
2283
  React__namespace.createElement(SectionSubtitle, { title: "Path Parameters" }),
2178
2284
  React__namespace.createElement(Parameters, { parameterType: "path", parameters: pathParams }))),
@@ -2193,6 +2299,15 @@ const SecurityPanel = ({ scheme, includeKey }) => {
2193
2299
  const [expandedState, setExpanded] = jotai.useAtom(schemeExpandedState);
2194
2300
  return (React__namespace.createElement(SubSectionPanel, { title: `Security: ${getReadableSecurityName(scheme, includeKey)}`, defaultIsOpen: !!expandedState[scheme.key], onChange: isOpen => setExpanded(Object.assign(Object.assign({}, expandedState), { [scheme.key]: isOpen })) },
2195
2301
  React__namespace.createElement(MarkdownViewer, { style: { fontSize: 12 }, markdown: `${scheme.description || ''}\n\n` + getDefaultDescription(scheme) })));
2302
+ };
2303
+ const SecuritySchemes$1 = ({ schemes }) => {
2304
+ const { nodeHasChanged } = useOptionsCtx();
2305
+ if (!schemes.length) {
2306
+ return null;
2307
+ }
2308
+ return (React__namespace.createElement(mosaic.VStack, { spacing: 3 }, schemes.map((scheme, i) => (React__namespace.createElement(mosaic.Box, { pos: "relative", key: i },
2309
+ React__namespace.createElement(SecurityPanel, { scheme: scheme, includeKey: shouldIncludeKey(schemes, scheme.type) }),
2310
+ React__namespace.createElement(mosaic.NodeAnnotation, { change: nodeHasChanged === null || nodeHasChanged === void 0 ? void 0 : nodeHasChanged({ nodeId: scheme.id }) }))))));
2196
2311
  };
2197
2312
 
2198
2313
  const Responses = ({ responses: unsortedResponses, onStatusCodeChange, onMediaTypeChange }) => {
@@ -2215,13 +2330,17 @@ const Response = ({ response, onMediaTypeChange }) => {
2215
2330
  const { contents = [], headers = [], description } = response;
2216
2331
  const [chosenContent, setChosenContent] = React__namespace.useState(0);
2217
2332
  const refResolver = useInlineRefResolver();
2333
+ const { nodeHasChanged } = useOptionsCtx();
2218
2334
  const responseContent = contents[chosenContent];
2219
2335
  const schema = responseContent === null || responseContent === void 0 ? void 0 : responseContent.schema;
2220
2336
  React__namespace.useEffect(() => {
2221
2337
  responseContent && onMediaTypeChange(responseContent.mediaType);
2222
2338
  }, [responseContent]);
2339
+ const descriptionChanged = nodeHasChanged === null || nodeHasChanged === void 0 ? void 0 : nodeHasChanged({ nodeId: response.id, attr: 'description' });
2223
2340
  return (React__namespace.createElement(mosaic.VStack, { spacing: 8, pt: 8 },
2224
- description && React__namespace.createElement(MarkdownViewer, { markdown: description }),
2341
+ description && (React__namespace.createElement(mosaic.Box, { pos: "relative" },
2342
+ React__namespace.createElement(MarkdownViewer, { markdown: description }),
2343
+ React__namespace.createElement(mosaic.NodeAnnotation, { change: descriptionChanged }))),
2225
2344
  headers.length > 0 && (React__namespace.createElement(mosaic.VStack, { spacing: 5 },
2226
2345
  React__namespace.createElement(SectionSubtitle, { title: "Headers", id: "response-headers" }),
2227
2346
  React__namespace.createElement(Parameters, { parameterType: "header", parameters: headers }))),
@@ -2229,7 +2348,7 @@ const Response = ({ response, onMediaTypeChange }) => {
2229
2348
  React__namespace.createElement(SectionSubtitle, { title: "Body", id: "response-body" },
2230
2349
  React__namespace.createElement(mosaic.Flex, { flex: 1, justify: "end" },
2231
2350
  React__namespace.createElement(mosaic.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" }))),
2232
- schema && (React__namespace.createElement(jsonSchemaViewer.JsonSchemaViewer, { schema: getOriginalObject(schema), resolveRef: refResolver, viewMode: "read", parentCrumbs: ['responses', response.code], renderRootTreeLines: true }))))));
2351
+ schema && (React__namespace.createElement(jsonSchemaViewer.JsonSchemaViewer, { schema: getOriginalObject(schema), resolveRef: refResolver, viewMode: "read", parentCrumbs: ['responses', response.code], renderRootTreeLines: true, nodeHasChanged: nodeHasChanged }))))));
2233
2352
  };
2234
2353
  Response.displayName = 'HttpOperation.Response';
2235
2354
  const codeToIntentVal = (code) => {
@@ -2247,6 +2366,7 @@ const codeToIntentVal = (code) => {
2247
2366
  };
2248
2367
 
2249
2368
  const HttpOperationComponent = React__namespace.memo(({ className, data: unresolvedData, layoutOptions, tryItCredentialsPolicy, tryItCorsProxy }) => {
2369
+ const { nodeHasChanged } = useOptionsCtx();
2250
2370
  const data = useResolvedObject(unresolvedData);
2251
2371
  const mocking = React__namespace.useContext(MockingContext);
2252
2372
  const isDeprecated = !!data.deprecated;
@@ -2256,15 +2376,12 @@ const HttpOperationComponent = React__namespace.memo(({ className, data: unresol
2256
2376
  const [requestBodyIndex, setTextRequestBodyIndex] = React__namespace.useState(0);
2257
2377
  const prettyName = (data.summary || data.iid || '').trim();
2258
2378
  const hasBadges = isDeprecated || isInternal;
2259
- const header = (!(layoutOptions === null || layoutOptions === void 0 ? void 0 : layoutOptions.noHeading) || hasBadges) && (React__namespace.createElement(mosaic.VStack, { spacing: 5 },
2260
- React__namespace.createElement(mosaic.HStack, { spacing: 5 },
2261
- !(layoutOptions === null || layoutOptions === void 0 ? void 0 : layoutOptions.noHeading) && prettyName ? (React__namespace.createElement(mosaic.Heading, { size: 1, fontWeight: "semibold" }, prettyName)) : null,
2262
- React__namespace.createElement(mosaic.HStack, { spacing: 2 },
2263
- isDeprecated && React__namespace.createElement(DeprecatedBadge, null),
2264
- isInternal && React__namespace.createElement(InternalBadge, { isHttpService: true }))),
2265
- React__namespace.createElement(MethodPath, { method: data.method, path: data.path })));
2379
+ const header = (React__namespace.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 }));
2380
+ const descriptionChanged = nodeHasChanged === null || nodeHasChanged === void 0 ? void 0 : nodeHasChanged({ nodeId: data.id, attr: 'description' });
2266
2381
  const description = (React__namespace.createElement(mosaic.VStack, { spacing: 10 },
2267
- data.description && React__namespace.createElement(MarkdownViewer, { className: "HttpOperation__Description", markdown: data.description }),
2382
+ data.description && (React__namespace.createElement(mosaic.Box, { pos: "relative" },
2383
+ React__namespace.createElement(MarkdownViewer, { className: "HttpOperation__Description", markdown: data.description }),
2384
+ React__namespace.createElement(mosaic.NodeAnnotation, { change: descriptionChanged }))),
2268
2385
  React__namespace.createElement(Request, { onChange: setTextRequestBodyIndex, operation: data }),
2269
2386
  data.responses && (React__namespace.createElement(Responses, { responses: data.responses, onMediaTypeChange: setResponseMediaType, onStatusCodeChange: setResponseStatusCode }))));
2270
2387
  const tryItPanel = !(layoutOptions === null || layoutOptions === void 0 ? void 0 : layoutOptions.hideTryItPanel) && (React__namespace.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 }));
@@ -2295,6 +2412,25 @@ function MethodPathInner({ method, path, chosenServerUrl }) {
2295
2412
  return (React__namespace.createElement(mosaic.HStack, { spacing: 3, pl: 2.5, pr: 4, py: 2, bg: "canvas-50", rounded: "lg", fontFamily: "mono", display: "inline-flex", maxW: "full", title: fullUrl },
2296
2413
  React__namespace.createElement(mosaic.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),
2297
2414
  pathElem));
2415
+ }
2416
+ function OperationHeader({ id, noHeading, hasBadges, name, isDeprecated, isInternal, method, path, }) {
2417
+ const { nodeHasChanged } = useOptionsCtx();
2418
+ if (noHeading && !hasBadges) {
2419
+ return null;
2420
+ }
2421
+ const lineOneChanged = nodeHasChanged === null || nodeHasChanged === void 0 ? void 0 : nodeHasChanged({ nodeId: id, attr: ['iid', 'summary', 'deprecated', 'internal'] });
2422
+ const lineTwoChanged = nodeHasChanged === null || nodeHasChanged === void 0 ? void 0 : nodeHasChanged({ nodeId: id, attr: ['method', 'path'] });
2423
+ return (React__namespace.createElement(mosaic.VStack, { spacing: 5 },
2424
+ React__namespace.createElement(mosaic.Box, { pos: "relative" },
2425
+ React__namespace.createElement(mosaic.HStack, { spacing: 5 },
2426
+ !noHeading && name ? (React__namespace.createElement(mosaic.Heading, { size: 1, fontWeight: "semibold" }, name)) : null,
2427
+ React__namespace.createElement(mosaic.HStack, { spacing: 2 },
2428
+ isDeprecated && React__namespace.createElement(DeprecatedBadge, null),
2429
+ isInternal && React__namespace.createElement(InternalBadge, { isHttpService: true }))),
2430
+ React__namespace.createElement(mosaic.NodeAnnotation, { change: lineOneChanged })),
2431
+ React__namespace.createElement(mosaic.Box, { pos: "relative" },
2432
+ React__namespace.createElement(MethodPath, { method: method, path: path }),
2433
+ React__namespace.createElement(mosaic.NodeAnnotation, { change: lineTwoChanged }))));
2298
2434
  }
2299
2435
 
2300
2436
  const PoweredByLink = ({ source, pathname, packageType, layout = 'sidebar' }) => {
@@ -2305,7 +2441,9 @@ const PoweredByLink = ({ source, pathname, packageType, layout = 'sidebar' }) =>
2305
2441
  React__namespace.createElement("strong", null, "Stoplight"))));
2306
2442
  };
2307
2443
 
2308
- const AdditionalInfo = ({ termsOfService, contact, license }) => {
2444
+ const AdditionalInfo = ({ id, termsOfService, contact, license }) => {
2445
+ const { nodeHasChanged } = useOptionsCtx();
2446
+ const hasChanged = nodeHasChanged === null || nodeHasChanged === void 0 ? void 0 : nodeHasChanged({ nodeId: id, attr: ['termsOfService', 'contact', 'license'] });
2309
2447
  const contactLink = (contact === null || contact === void 0 ? void 0 : contact.name) && (contact === null || contact === void 0 ? void 0 : contact.url)
2310
2448
  ? `[Contact ${contact.name}](${contact.url})`
2311
2449
  : (contact === null || contact === void 0 ? void 0 : contact.email)
@@ -2314,12 +2452,13 @@ const AdditionalInfo = ({ termsOfService, contact, license }) => {
2314
2452
  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`;
2315
2453
  const licenseLink = (license === null || license === void 0 ? void 0 : license.name) && licenseUrl ? `[${license.name} License](${licenseUrl})` : '';
2316
2454
  const tosLink = termsOfService ? `[Terms of Service](${termsOfService})` : '';
2317
- return contactLink || licenseLink || tosLink ? (React__default["default"].createElement(mosaic.Panel, { rounded: true, isCollapsible: false },
2455
+ return contactLink || licenseLink || tosLink ? (React__default["default"].createElement(mosaic.Panel, { rounded: true, isCollapsible: false, pos: "relative" },
2318
2456
  React__default["default"].createElement(mosaic.Panel.Titlebar, { bg: "canvas-300" },
2319
2457
  React__default["default"].createElement("span", { role: "heading" }, "Additional Information")),
2320
2458
  React__default["default"].createElement(mosaic.Panel.Content, { p: 0 },
2321
2459
  React__default["default"].createElement(mosaic.Panel.Content, null,
2322
- React__default["default"].createElement(MarkdownViewer, { style: { fontSize: 12 }, markdown: `${contactLink}\n \n${licenseLink}\n \n ${tosLink}` }))))) : null;
2460
+ React__default["default"].createElement(MarkdownViewer, { style: { fontSize: 12 }, markdown: `${contactLink}\n \n${licenseLink}\n \n ${tosLink}` }))),
2461
+ React__default["default"].createElement(mosaic.NodeAnnotation, { change: hasChanged }))) : null;
2323
2462
  };
2324
2463
 
2325
2464
  const ExportButton = ({ original, bundled }) => {
@@ -2341,11 +2480,14 @@ const SecuritySchemes = ({ schemes, defaultScheme, defaultCollapsed = false, })
2341
2480
  React__default["default"].createElement(mosaic.Panel.Content, { p: 0 }, sortBy__default["default"](schemes, 'type').map((scheme, i) => (React__default["default"].createElement(SecurityScheme, { key: i, scheme: scheme, defaultIsOpen: defaultScheme ? scheme.key === defaultScheme : i === 0, isCollapsible: schemes.length > 1, showSchemeKey: shouldIncludeKey(schemes, scheme.type) }))))));
2342
2481
  };
2343
2482
  const SecurityScheme = ({ scheme, defaultIsOpen, isCollapsible, showSchemeKey }) => {
2344
- return (React__default["default"].createElement(mosaic.Panel, { defaultIsOpen: defaultIsOpen, isCollapsible: isCollapsible },
2483
+ const { nodeHasChanged } = useOptionsCtx();
2484
+ const hasChanged = nodeHasChanged === null || nodeHasChanged === void 0 ? void 0 : nodeHasChanged({ nodeId: scheme.id });
2485
+ return (React__default["default"].createElement(mosaic.Panel, { defaultIsOpen: defaultIsOpen, isCollapsible: isCollapsible, pos: "relative" },
2345
2486
  React__default["default"].createElement(mosaic.Panel.Titlebar, null,
2346
2487
  React__default["default"].createElement(mosaic.Box, { as: "span", role: "heading" }, getReadableSecurityName(scheme, showSchemeKey))),
2347
2488
  React__default["default"].createElement(mosaic.Panel.Content, null,
2348
- React__default["default"].createElement(MarkdownViewer, { style: { fontSize: 12 }, markdown: `${scheme.description || ''}\n\n` + getDefaultDescription(scheme) }))));
2489
+ React__default["default"].createElement(MarkdownViewer, { style: { fontSize: 12 }, markdown: `${scheme.description || ''}\n\n` + getDefaultDescription(scheme) })),
2490
+ React__default["default"].createElement(mosaic.NodeAnnotation, { change: hasChanged })));
2349
2491
  };
2350
2492
 
2351
2493
  const ServerInfo = ({ servers, mockUrl }) => {
@@ -2359,13 +2501,14 @@ const ServerInfo = ({ servers, mockUrl }) => {
2359
2501
  return (React__namespace.createElement(mosaic.InvertTheme, null,
2360
2502
  React__namespace.createElement(mosaic.Panel, { rounded: true, isCollapsible: false, className: "BaseURLContent", w: "full" },
2361
2503
  React__namespace.createElement(mosaic.Panel.Titlebar, { whitespace: "nowrap" }, "API Base URL"),
2362
- React__namespace.createElement(mosaic.Box, { overflowX: "auto" },
2363
- React__namespace.createElement(mosaic.Panel.Content, { w: "full", className: "sl-flex sl-flex-col" },
2364
- React__namespace.createElement(mosaic.VStack, { spacing: 1, divider: true }, serversToDisplay.map((server, index) => (React__namespace.createElement(ServerUrl, Object.assign({}, server, { key: index }))))))))));
2504
+ React__namespace.createElement(mosaic.Panel.Content, { w: "full", className: "sl-flex sl-flex-col" },
2505
+ React__namespace.createElement(mosaic.VStack, { spacing: 1, divider: true }, serversToDisplay.map((server, index) => (React__namespace.createElement(ServerUrl, Object.assign({}, server, { key: index })))))))));
2365
2506
  };
2366
- const ServerUrl = ({ description, url, marginBottom = true }) => {
2507
+ const ServerUrl = ({ id, description, url }) => {
2508
+ const { nodeHasChanged } = useOptionsCtx();
2367
2509
  const { onCopy, hasCopied } = mosaic.useClipboard(url);
2368
- return (React__namespace.createElement(mosaic.Box, { whitespace: "nowrap" },
2510
+ const hasChanged = nodeHasChanged === null || nodeHasChanged === void 0 ? void 0 : nodeHasChanged({ nodeId: id });
2511
+ return (React__namespace.createElement(mosaic.Box, { whitespace: "nowrap", pos: "relative" },
2369
2512
  React__namespace.createElement(mosaic.Text, { pr: 2, fontWeight: "bold" },
2370
2513
  description,
2371
2514
  ":"),
@@ -2375,26 +2518,37 @@ const ServerUrl = ({ description, url, marginBottom = true }) => {
2375
2518
  React__namespace.createElement(mosaic.Icon, { className: "sl-ml-1", icon: ['fas', 'copy'] }))),
2376
2519
  hasCopied && (React__namespace.createElement(mosaic.Box, { p: 1 },
2377
2520
  "Copied Server URL ",
2378
- React__namespace.createElement(mosaic.Icon, { className: "sl-ml-1", icon: ['fas', 'check'] }))))));
2521
+ React__namespace.createElement(mosaic.Icon, { className: "sl-ml-1", icon: ['fas', 'check'] })))),
2522
+ React__namespace.createElement(mosaic.NodeAnnotation, { change: hasChanged, additionalLeftOffset: 16 })));
2379
2523
  };
2380
2524
 
2381
- const HttpServiceComponent = React__namespace.memo(({ data, location = {}, layoutOptions, exportProps }) => {
2525
+ const HttpServiceComponent = React__namespace.memo(({ data: unresolvedData, location = {}, layoutOptions, exportProps }) => {
2382
2526
  var _a, _b, _c, _d;
2527
+ const { nodeHasChanged } = useOptionsCtx();
2528
+ const data = useResolvedObject(unresolvedData);
2383
2529
  const { search, pathname } = location;
2384
2530
  const mocking = React__namespace.useContext(MockingContext);
2385
2531
  const query = new URLSearchParams(search);
2532
+ const nameChanged = nodeHasChanged === null || nodeHasChanged === void 0 ? void 0 : nodeHasChanged({ nodeId: data.id, attr: 'name' });
2533
+ const versionChanged = nodeHasChanged === null || nodeHasChanged === void 0 ? void 0 : nodeHasChanged({ nodeId: data.id, attr: 'version' });
2534
+ const descriptionChanged = nodeHasChanged === null || nodeHasChanged === void 0 ? void 0 : nodeHasChanged({ nodeId: data.id, attr: 'description' });
2386
2535
  return (React__namespace.createElement(mosaic.Box, { mb: 10 },
2387
2536
  data.name && !(layoutOptions === null || layoutOptions === void 0 ? void 0 : layoutOptions.noHeading) && (React__namespace.createElement(mosaic.Flex, { justifyContent: "between", alignItems: "center" },
2388
- React__namespace.createElement(mosaic.Heading, { size: 1, mb: 4, fontWeight: "semibold" }, data.name),
2537
+ React__namespace.createElement(mosaic.Box, { pos: "relative" },
2538
+ React__namespace.createElement(mosaic.Heading, { size: 1, mb: 4, fontWeight: "semibold" }, data.name),
2539
+ React__namespace.createElement(mosaic.NodeAnnotation, { change: nameChanged })),
2389
2540
  exportProps && !(layoutOptions === null || layoutOptions === void 0 ? void 0 : layoutOptions.hideExport) && React__namespace.createElement(ExportButton, Object.assign({}, exportProps)))),
2390
- data.version && (React__namespace.createElement(mosaic.Box, { mb: 5 },
2391
- React__namespace.createElement(VersionBadge, { value: data.version }))),
2541
+ data.version && (React__namespace.createElement(mosaic.Box, { mb: 5, pos: "relative" },
2542
+ React__namespace.createElement(VersionBadge, { value: data.version }),
2543
+ React__namespace.createElement(mosaic.NodeAnnotation, { change: versionChanged }))),
2392
2544
  pathname && (layoutOptions === null || layoutOptions === void 0 ? void 0 : layoutOptions.showPoweredByLink) && (React__namespace.createElement(PoweredByLink, { source: (_a = data.name) !== null && _a !== void 0 ? _a : 'no-title', pathname: pathname, packageType: "elements", layout: "stacked" })),
2393
2545
  React__namespace.createElement(mosaic.VStack, { spacing: 6 },
2394
2546
  React__namespace.createElement(ServerInfo, { servers: (_b = data.servers) !== null && _b !== void 0 ? _b : [], mockUrl: mocking.mockUrl }),
2395
- React__namespace.createElement(mosaic.Box, null, ((_c = data.securitySchemes) === null || _c === void 0 ? void 0 : _c.length) && (React__namespace.createElement(SecuritySchemes, { schemes: data.securitySchemes, defaultScheme: query.get('security') || undefined }))),
2396
- React__namespace.createElement(mosaic.Box, null, (((_d = data.contact) === null || _d === void 0 ? void 0 : _d.email) || data.license || data.termsOfService) && (React__namespace.createElement(AdditionalInfo, { contact: data.contact, license: data.license, termsOfService: data.termsOfService })))),
2397
- data.description && React__namespace.createElement(MarkdownViewer, { className: "sl-my-5", markdown: data.description })));
2547
+ React__namespace.createElement(mosaic.Box, null, ((_c = data.securitySchemes) === null || _c === void 0 ? void 0 : _c.length) ? (React__namespace.createElement(SecuritySchemes, { schemes: data.securitySchemes, defaultScheme: query.get('security') || undefined })) : null),
2548
+ React__namespace.createElement(mosaic.Box, null, (((_d = data.contact) === null || _d === void 0 ? void 0 : _d.email) || data.license || data.termsOfService) && (React__namespace.createElement(AdditionalInfo, { id: data.id, contact: data.contact, license: data.license, termsOfService: data.termsOfService })))),
2549
+ data.description && (React__namespace.createElement(mosaic.Box, { pos: "relative" },
2550
+ React__namespace.createElement(MarkdownViewer, { className: "sl-my-5", markdown: data.description }),
2551
+ React__namespace.createElement(mosaic.NodeAnnotation, { change: descriptionChanged })))));
2398
2552
  });
2399
2553
  HttpServiceComponent.displayName = 'HttpService.Component';
2400
2554
  const HttpService = reactErrorBoundary.withErrorBoundary(HttpServiceComponent, { recoverableProps: ['data'] });
@@ -2416,23 +2570,31 @@ function useIsCompact(layoutOptions) {
2416
2570
  }
2417
2571
 
2418
2572
  const ModelComponent = ({ data: unresolvedData, className, nodeTitle, layoutOptions, exportProps, }) => {
2419
- var _a;
2573
+ var _a, _b;
2420
2574
  const resolveRef = useInlineRefResolver();
2421
2575
  const data = useResolvedObject(unresolvedData);
2576
+ const { nodeHasChanged } = useOptionsCtx();
2422
2577
  const { ref: layoutRef, isCompact } = useIsCompact(layoutOptions);
2423
- const title = (_a = data.title) !== null && _a !== void 0 ? _a : nodeTitle;
2578
+ const nodeId = (_a = data === null || data === void 0 ? void 0 : data['x-stoplight']) === null || _a === void 0 ? void 0 : _a.id;
2579
+ const title = (_b = data.title) !== null && _b !== void 0 ? _b : nodeTitle;
2424
2580
  const isInternal = !!data['x-internal'];
2425
2581
  const shouldDisplayHeader = !(layoutOptions === null || layoutOptions === void 0 ? void 0 : layoutOptions.noHeading) && (title !== undefined || (exportProps && !(layoutOptions === null || layoutOptions === void 0 ? void 0 : layoutOptions.hideExport)));
2582
+ const titleChanged = nodeHasChanged === null || nodeHasChanged === void 0 ? void 0 : nodeHasChanged({ nodeId, attr: ['title', 'internal'] });
2426
2583
  const header = (shouldDisplayHeader || isInternal) && (React__namespace.createElement(mosaic.Flex, { justifyContent: "between", alignItems: "center" },
2427
- React__namespace.createElement(mosaic.HStack, { spacing: 5 },
2428
- title && (React__namespace.createElement(mosaic.Heading, { size: 1, fontWeight: "semibold" }, title)),
2429
- React__namespace.createElement(mosaic.HStack, { spacing: 2 }, isInternal && React__namespace.createElement(InternalBadge, null))),
2584
+ React__namespace.createElement(mosaic.Box, { pos: "relative" },
2585
+ React__namespace.createElement(mosaic.HStack, { spacing: 5 },
2586
+ title && (React__namespace.createElement(mosaic.Heading, { size: 1, fontWeight: "semibold" }, title)),
2587
+ React__namespace.createElement(mosaic.HStack, { spacing: 2 }, isInternal && React__namespace.createElement(InternalBadge, null))),
2588
+ React__namespace.createElement(mosaic.NodeAnnotation, { change: titleChanged })),
2430
2589
  exportProps && !(layoutOptions === null || layoutOptions === void 0 ? void 0 : layoutOptions.hideExport) && React__namespace.createElement(ExportButton, Object.assign({}, exportProps))));
2431
2590
  const modelExamples = !(layoutOptions === null || layoutOptions === void 0 ? void 0 : layoutOptions.hideModelExamples) && React__namespace.createElement(ModelExamples, { data: data, isCollapsible: isCompact });
2591
+ const descriptionChanged = nodeHasChanged === null || nodeHasChanged === void 0 ? void 0 : nodeHasChanged({ nodeId, attr: 'description' });
2432
2592
  const description = (React__namespace.createElement(mosaic.VStack, { spacing: 10 },
2433
- data.description && data.type === 'object' && React__namespace.createElement(MarkdownViewer, { role: "textbox", markdown: data.description }),
2593
+ data.description && data.type === 'object' && (React__namespace.createElement(mosaic.Box, { pos: "relative" },
2594
+ React__namespace.createElement(MarkdownViewer, { role: "textbox", markdown: data.description }),
2595
+ React__namespace.createElement(mosaic.NodeAnnotation, { change: descriptionChanged }))),
2434
2596
  isCompact && modelExamples,
2435
- React__namespace.createElement(jsonSchemaViewer.JsonSchemaViewer, { resolveRef: resolveRef, schema: getOriginalObject(data) })));
2597
+ React__namespace.createElement(jsonSchemaViewer.JsonSchemaViewer, { resolveRef: resolveRef, schema: getOriginalObject(data), nodeHasChanged: nodeHasChanged, skipTopLevelDescription: true })));
2436
2598
  return (React__namespace.createElement(TwoColumnLayout, { ref: layoutRef, className: cn__default["default"]('Model', className), header: header, left: description, right: !isCompact && modelExamples }));
2437
2599
  };
2438
2600
  const ModelExamples = React__namespace.memo(({ data, isCollapsible = false }) => {
@@ -2454,16 +2616,16 @@ const ModelExamples = React__namespace.memo(({ data, isCollapsible = false }) =>
2454
2616
  const Model = reactErrorBoundary.withErrorBoundary(ModelComponent, { recoverableProps: ['data'] });
2455
2617
 
2456
2618
  const Docs = React__namespace.memo((_a) => {
2457
- var { nodeType, nodeData, useNodeForRefResolving = false, refResolver } = _a, commonProps = tslib.__rest(_a, ["nodeType", "nodeData", "useNodeForRefResolving", "refResolver"]);
2619
+ var { nodeType, nodeData, useNodeForRefResolving = false, refResolver, nodeHasChanged } = _a, commonProps = tslib.__rest(_a, ["nodeType", "nodeData", "useNodeForRefResolving", "refResolver", "nodeHasChanged"]);
2458
2620
  const parsedNode = useParsedData(nodeType, nodeData);
2459
2621
  if (!parsedNode) {
2460
2622
  return null;
2461
2623
  }
2462
- const parsedDocs = React__namespace.createElement(ParsedDocs, Object.assign({ node: parsedNode }, commonProps));
2624
+ let elem = React__namespace.createElement(ParsedDocs, Object.assign({ node: parsedNode }, commonProps));
2463
2625
  if (useNodeForRefResolving) {
2464
- return (React__namespace.createElement(InlineRefResolverProvider, { document: parsedNode.data, resolver: refResolver }, parsedDocs));
2626
+ elem = (React__namespace.createElement(InlineRefResolverProvider, { document: parsedNode.data, resolver: refResolver }, elem));
2465
2627
  }
2466
- return parsedDocs;
2628
+ return React__namespace.createElement(ElementsOptionsProvider, { nodeHasChanged: nodeHasChanged }, elem);
2467
2629
  });
2468
2630
  const ParsedDocs = (_a) => {
2469
2631
  var { node } = _a, commonProps = tslib.__rest(_a, ["node"]);
@@ -2891,16 +3053,33 @@ const useRouter = (router, basePath, staticRouterPath) => {
2891
3053
  };
2892
3054
  };
2893
3055
 
3056
+ const components = {
3057
+ a: ReactRouterMarkdownLink,
3058
+ h2: (_a) => {
3059
+ var props = tslib.__rest(_a, ["color"]);
3060
+ return React__namespace.createElement(LinkHeading, Object.assign({ size: 2 }, props));
3061
+ },
3062
+ h3: (_a) => {
3063
+ var props = tslib.__rest(_a, ["color"]);
3064
+ return React__namespace.createElement(LinkHeading, Object.assign({ size: 3 }, props));
3065
+ },
3066
+ h4: (_a) => {
3067
+ var props = tslib.__rest(_a, ["color"]);
3068
+ return React__namespace.createElement(LinkHeading, Object.assign({ size: 4 }, props));
3069
+ },
3070
+ };
2894
3071
  function withRouter(WrappedComponent) {
2895
3072
  const WithRouter = (props) => {
2896
3073
  var _a, _b, _c;
2897
3074
  const basePath = (_a = props.basePath) !== null && _a !== void 0 ? _a : '/';
2898
3075
  const staticRouterPath = (_b = props.staticRouterPath) !== null && _b !== void 0 ? _b : '';
2899
- const { Router, routerProps } = useRouter((_c = props.router) !== null && _c !== void 0 ? _c : 'history', basePath, staticRouterPath);
2900
- return (React__namespace.createElement(Router, Object.assign({}, routerProps, { key: basePath }),
2901
- React__namespace.createElement(reactRouterDom.Route, { path: "/" },
2902
- React__namespace.createElement(MarkdownComponentsProvider, { value: { a: ReactRouterMarkdownLink } },
2903
- React__namespace.createElement(WrappedComponent, Object.assign({}, props))))));
3076
+ const routerType = (_c = props.router) !== null && _c !== void 0 ? _c : 'history';
3077
+ const { Router, routerProps } = useRouter(routerType, basePath, staticRouterPath);
3078
+ return (React__namespace.createElement(RouterTypeContext.Provider, { value: routerType },
3079
+ React__namespace.createElement(Router, Object.assign({}, routerProps, { key: basePath }),
3080
+ React__namespace.createElement(reactRouterDom.Route, { path: "/" },
3081
+ React__namespace.createElement(MarkdownComponentsProvider, { value: components },
3082
+ React__namespace.createElement(WrappedComponent, Object.assign({}, props)))))));
2904
3083
  };
2905
3084
  WithRouter.displayName = `WithRouter(${getDisplayName(WrappedComponent)})`;
2906
3085
  return WithRouter;