@oneuptime/common 12.0.30 → 12.0.31

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.
Files changed (489) hide show
  1. package/Models/AnalyticsModels/SecurityEvent.ts +48 -16
  2. package/Models/AnalyticsModels/ThreatIntelIndicator.ts +10 -5
  3. package/Models/DatabaseModels/AlertSeverity.ts +44 -0
  4. package/Models/DatabaseModels/DetectionRule.ts +16 -5
  5. package/Models/DatabaseModels/GoogleSecOpsConnection.ts +14 -5
  6. package/Models/DatabaseModels/IncidentSeverity.ts +44 -0
  7. package/Models/DatabaseModels/Index.ts +2 -0
  8. package/Models/DatabaseModels/NetworkDevice.ts +113 -3
  9. package/Models/DatabaseModels/NetworkDeviceAutoImportRule.ts +88 -0
  10. package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +22 -0
  11. package/Models/DatabaseModels/NetworkDeviceOidTemplate.ts +499 -0
  12. package/Models/DatabaseModels/ThreatIntelFeed.ts +16 -5
  13. package/Server/API/GlobalConfigAPI.ts +362 -183
  14. package/Server/API/TelemetryAPI.ts +42 -4
  15. package/Server/EnvironmentConfig.ts +112 -0
  16. package/Server/Infrastructure/Postgres/SchemaMigrations/1790500000000-AddNetworkDeviceOidTemplate.ts +59 -0
  17. package/Server/Infrastructure/Postgres/SchemaMigrations/1790600000000-AddAutoImportRuleOidTemplate.ts +25 -0
  18. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +4 -0
  19. package/Server/Middleware/MultipartFormData.ts +118 -32
  20. package/Server/Services/AlertEpisodeLabelRuleEngineService.ts +9 -1
  21. package/Server/Services/AlertEpisodeOnCallRuleEngineService.ts +9 -1
  22. package/Server/Services/AlertEpisodeOwnerRuleEngineService.ts +9 -1
  23. package/Server/Services/AlertEpisodePrivacyRuleEngineService.ts +9 -1
  24. package/Server/Services/AlertGroupingEngineService.ts +9 -1
  25. package/Server/Services/AlertLabelRuleEngineService.ts +9 -1
  26. package/Server/Services/AlertOnCallRuleEngineService.ts +9 -1
  27. package/Server/Services/AlertOwnerRuleEngineService.ts +9 -1
  28. package/Server/Services/AlertPrivacyRuleEngineService.ts +9 -1
  29. package/Server/Services/AlertReminderRuleService.ts +9 -1
  30. package/Server/Services/AutoRemediationRuleEngineService.ts +9 -1
  31. package/Server/Services/CephClusterLabelRuleEngineService.ts +9 -1
  32. package/Server/Services/CephClusterOwnerRuleEngineService.ts +9 -1
  33. package/Server/Services/CloudResourceLabelRuleEngineService.ts +9 -1
  34. package/Server/Services/CloudResourceOwnerRuleEngineService.ts +9 -1
  35. package/Server/Services/DashboardLabelRuleEngineService.ts +9 -1
  36. package/Server/Services/DashboardOwnerRuleEngineService.ts +9 -1
  37. package/Server/Services/DockerHostLabelRuleEngineService.ts +9 -1
  38. package/Server/Services/DockerHostOwnerRuleEngineService.ts +9 -1
  39. package/Server/Services/DockerSwarmClusterLabelRuleEngineService.ts +9 -1
  40. package/Server/Services/DockerSwarmClusterOwnerRuleEngineService.ts +9 -1
  41. package/Server/Services/HostLabelRuleEngineService.ts +9 -1
  42. package/Server/Services/HostOwnerRuleEngineService.ts +9 -1
  43. package/Server/Services/IncidentEpisodeLabelRuleEngineService.ts +9 -1
  44. package/Server/Services/IncidentEpisodeOnCallRuleEngineService.ts +9 -1
  45. package/Server/Services/IncidentEpisodeOwnerRuleEngineService.ts +9 -1
  46. package/Server/Services/IncidentEpisodePrivacyRuleEngineService.ts +9 -1
  47. package/Server/Services/IncidentGroupingEngineService.ts +9 -1
  48. package/Server/Services/IncidentLabelRuleEngineService.ts +9 -1
  49. package/Server/Services/IncidentOnCallRuleEngineService.ts +9 -1
  50. package/Server/Services/IncidentOwnerRuleEngineService.ts +9 -1
  51. package/Server/Services/IncidentPrivacyRuleEngineService.ts +9 -1
  52. package/Server/Services/IncidentReminderRuleService.ts +9 -1
  53. package/Server/Services/IncidentSlaRuleService.ts +9 -1
  54. package/Server/Services/IncomingCallPolicyLabelRuleEngineService.ts +9 -1
  55. package/Server/Services/IncomingCallPolicyOwnerRuleEngineService.ts +9 -1
  56. package/Server/Services/Index.ts +2 -0
  57. package/Server/Services/IoTFleetLabelRuleEngineService.ts +9 -1
  58. package/Server/Services/IoTFleetOwnerRuleEngineService.ts +9 -1
  59. package/Server/Services/KubernetesClusterLabelRuleEngineService.ts +9 -1
  60. package/Server/Services/KubernetesClusterOwnerRuleEngineService.ts +9 -1
  61. package/Server/Services/KubernetesResourceService.ts +5 -1
  62. package/Server/Services/MonitorLabelRuleEngineService.ts +9 -1
  63. package/Server/Services/MonitorOwnerRuleEngineService.ts +9 -1
  64. package/Server/Services/NetworkDeviceAutoImportRuleEngineService.ts +35 -0
  65. package/Server/Services/NetworkDeviceAutoImportRuleService.ts +96 -0
  66. package/Server/Services/NetworkDeviceLabelRuleEngineService.ts +9 -1
  67. package/Server/Services/NetworkDeviceOidTemplateService.ts +201 -0
  68. package/Server/Services/NetworkDeviceOwnerRuleEngineService.ts +9 -1
  69. package/Server/Services/NetworkDeviceService.ts +209 -1
  70. package/Server/Services/OnCallDutyPolicyLabelRuleEngineService.ts +9 -1
  71. package/Server/Services/OnCallDutyPolicyOwnerRuleEngineService.ts +9 -1
  72. package/Server/Services/OnCallDutyPolicyScheduleLabelRuleEngineService.ts +9 -1
  73. package/Server/Services/OnCallDutyPolicyScheduleOwnerRuleEngineService.ts +9 -1
  74. package/Server/Services/PodmanHostLabelRuleEngineService.ts +9 -1
  75. package/Server/Services/PodmanHostOwnerRuleEngineService.ts +9 -1
  76. package/Server/Services/ProxmoxClusterLabelRuleEngineService.ts +9 -1
  77. package/Server/Services/ProxmoxClusterOwnerRuleEngineService.ts +9 -1
  78. package/Server/Services/RumApplicationLabelRuleEngineService.ts +9 -1
  79. package/Server/Services/RumApplicationOwnerRuleEngineService.ts +9 -1
  80. package/Server/Services/RunbookLabelRuleEngineService.ts +9 -1
  81. package/Server/Services/RunbookOwnerRuleEngineService.ts +9 -1
  82. package/Server/Services/RunbookRuleEngineService.ts +9 -1
  83. package/Server/Services/ScheduledMaintenanceLabelRuleEngineService.ts +9 -1
  84. package/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.ts +9 -1
  85. package/Server/Services/ScheduledMaintenanceReminderRuleService.ts +9 -1
  86. package/Server/Services/ServerlessFunctionLabelRuleEngineService.ts +9 -1
  87. package/Server/Services/ServerlessFunctionOwnerRuleEngineService.ts +9 -1
  88. package/Server/Services/ServiceLabelRuleEngineService.ts +9 -1
  89. package/Server/Services/ServiceOwnerRuleEngineService.ts +9 -1
  90. package/Server/Services/StatusPageLabelRuleEngineService.ts +9 -1
  91. package/Server/Services/StatusPageMonitorRuleEngineService.ts +7 -0
  92. package/Server/Services/StatusPageOwnerRuleEngineService.ts +9 -1
  93. package/Server/Services/TelemetrySourceMapService.ts +266 -23
  94. package/Server/Services/UserService.ts +27 -0
  95. package/Server/Services/WorkflowLabelRuleEngineService.ts +9 -1
  96. package/Server/Services/WorkflowOwnerRuleEngineService.ts +9 -1
  97. package/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.ts +186 -0
  98. package/Server/Utils/Monitor/CapturedMetricAttributeUtil.ts +245 -0
  99. package/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.ts +21 -2
  100. package/Server/Utils/Monitor/MonitorMetricUtil.ts +55 -21
  101. package/Server/Utils/Monitor/MonitorTemplateUtil.ts +32 -0
  102. package/Server/Utils/Monitor/NetworkDeviceMetricUtil.ts +15 -2
  103. package/Server/Utils/Monitor/NetworkDeviceWalkUtil.ts +18 -1
  104. package/Server/Utils/Monitor/NetworkInventoryUtil.ts +10 -0
  105. package/Server/Utils/Monitor/SeriesResourceLabels.ts +34 -0
  106. package/Server/Utils/Rules/RuleEngineRuleRead.ts +48 -0
  107. package/Server/Utils/Telemetry/ExceptionSanitizer.ts +14 -1
  108. package/Server/Utils/Telemetry/LogExceptionExtractor.ts +14 -2
  109. package/Server/Utils/Telemetry/SourceMapResolver.ts +16 -5
  110. package/Server/Utils/Telemetry/StackTraceParser.ts +399 -0
  111. package/Tests/App/Dashboard/EventOverlayHook.test.tsx +125 -0
  112. package/Tests/App/Dashboard/HeaderImageAssets.test.tsx +93 -0
  113. package/Tests/App/Dashboard/OnCallReadinessSurfaces.test.tsx +3 -3
  114. package/Tests/App/Dashboard/UserElementEmail.test.tsx +12 -4
  115. package/Tests/App/Dashboard/UserEmailCallSites.test.tsx +1 -1
  116. package/Tests/Models/DatabaseModels/DomainRoleTierCoverage.test.ts +14 -0
  117. package/Tests/Models/DatabaseModels/ModelRegistryInvariants.test.ts +469 -0
  118. package/Tests/Models/SecurityDomainAccessControl.test.ts +429 -0
  119. package/Tests/Server/API/GlobalConfigLicense.test.ts +657 -0
  120. package/Tests/Server/API/SecurityEventAttributesAPI.test.ts +84 -6
  121. package/Tests/Server/API/TelemetryResolveStackTraceAPI.test.ts +805 -0
  122. package/Tests/Server/Infrastructure/Postgres/AddOnCallCalendarFeedsMigration.test.ts +32 -7
  123. package/Tests/Server/Middleware/IdentityRateLimit.test.ts +1144 -0
  124. package/Tests/Server/Middleware/MultipartFormData.test.ts +618 -3
  125. package/Tests/Server/Services/MonitorLabelRuleEngineScale.test.ts +520 -0
  126. package/Tests/Server/Services/NetworkDeviceOidTemplateService.test.ts +332 -0
  127. package/Tests/Server/Services/NetworkDeviceOidTemplateWriteGuards.test.ts +409 -0
  128. package/Tests/Server/Services/RuleEngineRuleFetchLimit.test.ts +239 -0
  129. package/Tests/Server/Services/TelemetrySourceMapService.test.ts +1210 -2
  130. package/Tests/Server/Services/UserServiceSeatLimit.test.ts +182 -0
  131. package/Tests/Server/Types/AnalyticsDatabase/SecurityEventModelPermission.test.ts +255 -0
  132. package/Tests/Server/Types/Database/Permissions/ReadBlockPermission.test.ts +212 -0
  133. package/Tests/Server/Types/Database/Permissions/SecurityRoleAccess.test.ts +413 -0
  134. package/Tests/Server/Utils/CodeRepository.test.ts +689 -0
  135. package/Tests/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.test.ts +495 -0
  136. package/Tests/Server/Utils/ExceptionSanitizer.test.ts +77 -0
  137. package/Tests/Server/Utils/Monitor/CapturedMetricAttributeUtil.test.ts +284 -0
  138. package/Tests/Server/Utils/Monitor/MonitorCustomMetricAttributes.test.ts +503 -0
  139. package/Tests/Server/Utils/Monitor/MonitorTemplatePrototypePollution.test.ts +106 -0
  140. package/Tests/Server/Utils/Monitor/NetworkDeviceWalkLogWritePath.test.ts +33 -4
  141. package/Tests/Server/Utils/Monitor/NetworkDeviceWalkUtil.test.ts +14 -4
  142. package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +44 -0
  143. package/Tests/Server/Utils/OpenAPISpec.test.ts +536 -0
  144. package/Tests/Server/Utils/Rules/RuleEngineRuleRead.test.ts +115 -0
  145. package/Tests/Server/Utils/StackTraceParser.test.ts +610 -0
  146. package/Tests/Server/Utils/Telemetry/LogExceptionExtractor.test.ts +0 -0
  147. package/Tests/Server/Utils/Telemetry/SourceMapLimits.test.ts +656 -0
  148. package/Tests/Server/Utils/Telemetry/SourceMapResolver.test.ts +100 -0
  149. package/Tests/Types/Monitor/SnmpMonitor/SnmpOidListUtil.test.ts +454 -0
  150. package/Tests/Types/SecurityRolePermissions.test.ts +193 -0
  151. package/Tests/UI/Components/Charts/AnnotationLayout.test.ts +773 -0
  152. package/Tests/UI/Components/Charts/ChartAnnotationRail.test.tsx +789 -0
  153. package/Tests/UI/Components/Charts/ChartBucketIdentity.test.ts +254 -0
  154. package/Tests/UI/Components/Charts/TimeAnnotation.test.ts +471 -0
  155. package/Tests/UI/Components/EditionLabelLicenseRefresh.test.tsx +405 -0
  156. package/Tests/UI/Components/ErrorMessageRefreshControl.test.tsx +83 -0
  157. package/Tests/UI/Components/MarkdownConverters.test.ts +686 -0
  158. package/Tests/UI/Components/ModelTable/BaseModelTableDeleteAndEmptyStates.test.tsx +341 -0
  159. package/Tests/UI/Components/OrderedStatesList.test.tsx +5 -5
  160. package/Tests/UI/Components/PendingProjectInvitations.test.tsx +1 -1
  161. package/Tests/UI/Components/TableSortAndMobileColumns.test.tsx +195 -0
  162. package/Tests/UI/Components/XAxis.test.ts +270 -5
  163. package/Tests/UI/Components/XAxisDaylightSaving.test.ts +113 -0
  164. package/Tests/UI/Styles/ChartFocusRing.test.ts +153 -0
  165. package/Tests/UI/Styles/ChartFocusRingCoverage.test.tsx +377 -0
  166. package/Tests/UI/Styles/ThemeStylesheet.ts +162 -0
  167. package/Tests/Utils/EnterpriseLicenseSeats.test.ts +507 -0
  168. package/Tests/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.test.ts +951 -1
  169. package/Tests/Utils/NetworkDiscovery/DiscoveredHostUtil.test.ts +238 -0
  170. package/Tests/Utils/NetworkDiscovery/DiscoveryReverseDnsChain.test.ts +1056 -0
  171. package/Tests/Utils/NetworkDiscovery/ReverseDnsNameUtil.test.ts +882 -0
  172. package/Types/Date.ts +39 -0
  173. package/Types/Monitor/SnmpMonitor/SnmpOidListUtil.ts +333 -0
  174. package/Types/Permission.ts +96 -0
  175. package/Types/Rum/SessionReplay.ts +21 -0
  176. package/Types/Telemetry/SourceMap.ts +8 -0
  177. package/UI/Components/Charts/ChartLibrary/Annotations/AnnotationHoverCard.tsx +176 -0
  178. package/UI/Components/Charts/ChartLibrary/Annotations/AnnotationLayout.ts +745 -0
  179. package/UI/Components/Charts/ChartLibrary/Annotations/ChartAnnotationLayer.tsx +576 -0
  180. package/UI/Components/Charts/ChartLibrary/Annotations/UseChartAnnotations.tsx +204 -0
  181. package/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.tsx +491 -544
  182. package/UI/Components/Charts/ChartLibrary/BarChart/BarChart.tsx +324 -372
  183. package/UI/Components/Charts/ChartLibrary/LineChart/LineChart.tsx +487 -540
  184. package/UI/Components/Charts/ChartLibrary/Types/FormattedReferenceRegion.ts +7 -3
  185. package/UI/Components/Charts/ChartLibrary/Types/FormattedTimeReferenceLine.ts +14 -3
  186. package/UI/Components/Charts/Types/ChartEventKind.ts +13 -0
  187. package/UI/Components/Charts/Types/ReferenceRegionProps.ts +6 -0
  188. package/UI/Components/Charts/Types/TimeReferenceLineProps.ts +20 -3
  189. package/UI/Components/Charts/Utils/TimeAnnotation.ts +69 -35
  190. package/UI/Components/Charts/Utils/XAxis.ts +125 -18
  191. package/UI/Components/EditionLabel/EditionLabel.tsx +280 -26
  192. package/UI/Components/ErrorMessage/ErrorMessage.tsx +21 -10
  193. package/UI/Components/Feed/FeedItem.tsx +4 -5
  194. package/UI/Components/Header/HeaderIconDropdownButton.tsx +1 -2
  195. package/UI/Components/Header/UserProfile/UserProfile.tsx +1 -2
  196. package/UI/Components/Image/Image.tsx +20 -3
  197. package/UI/Components/Markdown.tsx/MarkdownConverters.ts +0 -0
  198. package/UI/Components/MemberRoleAssignment/MemberRoleAssignment.tsx +1 -2
  199. package/UI/Components/ModelTable/BaseModelTable.tsx +150 -24
  200. package/UI/Components/Table/TableHeader.tsx +64 -48
  201. package/UI/Components/Table/TableRow.tsx +13 -3
  202. package/UI/Styles/Theme.css +38 -0
  203. package/Utils/EnterpriseLicense/EnterpriseLicenseSeats.ts +271 -0
  204. package/Utils/NetworkDiscovery/AutoImportRuleMatcher.ts +6 -0
  205. package/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.ts +141 -10
  206. package/Utils/NetworkDiscovery/DiscoveredHostUtil.ts +55 -3
  207. package/Utils/NetworkDiscovery/ReverseDnsNameUtil.ts +151 -0
  208. package/Utils/Rules/RuleEngineLimits.ts +32 -0
  209. package/build/dist/Models/AnalyticsModels/SecurityEvent.js +48 -16
  210. package/build/dist/Models/AnalyticsModels/SecurityEvent.js.map +1 -1
  211. package/build/dist/Models/AnalyticsModels/ThreatIntelIndicator.js +10 -5
  212. package/build/dist/Models/AnalyticsModels/ThreatIntelIndicator.js.map +1 -1
  213. package/build/dist/Models/DatabaseModels/AlertSeverity.js +46 -1
  214. package/build/dist/Models/DatabaseModels/AlertSeverity.js.map +1 -1
  215. package/build/dist/Models/DatabaseModels/DetectionRule.js +16 -5
  216. package/build/dist/Models/DatabaseModels/DetectionRule.js.map +1 -1
  217. package/build/dist/Models/DatabaseModels/GoogleSecOpsConnection.js +14 -5
  218. package/build/dist/Models/DatabaseModels/GoogleSecOpsConnection.js.map +1 -1
  219. package/build/dist/Models/DatabaseModels/IncidentSeverity.js +46 -1
  220. package/build/dist/Models/DatabaseModels/IncidentSeverity.js.map +1 -1
  221. package/build/dist/Models/DatabaseModels/Index.js +2 -0
  222. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  223. package/build/dist/Models/DatabaseModels/NetworkDevice.js +115 -3
  224. package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
  225. package/build/dist/Models/DatabaseModels/NetworkDeviceAutoImportRule.js +88 -0
  226. package/build/dist/Models/DatabaseModels/NetworkDeviceAutoImportRule.js.map +1 -1
  227. package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
  228. package/build/dist/Models/DatabaseModels/NetworkDeviceOidTemplate.js +519 -0
  229. package/build/dist/Models/DatabaseModels/NetworkDeviceOidTemplate.js.map +1 -0
  230. package/build/dist/Models/DatabaseModels/ThreatIntelFeed.js +16 -5
  231. package/build/dist/Models/DatabaseModels/ThreatIntelFeed.js.map +1 -1
  232. package/build/dist/Server/API/GlobalConfigAPI.js +293 -176
  233. package/build/dist/Server/API/GlobalConfigAPI.js.map +1 -1
  234. package/build/dist/Server/API/TelemetryAPI.js +31 -3
  235. package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
  236. package/build/dist/Server/EnvironmentConfig.js +83 -0
  237. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  238. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790500000000-AddNetworkDeviceOidTemplate.js +26 -0
  239. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790500000000-AddNetworkDeviceOidTemplate.js.map +1 -0
  240. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790600000000-AddAutoImportRuleOidTemplate.js +14 -0
  241. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790600000000-AddAutoImportRuleOidTemplate.js.map +1 -0
  242. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +4 -0
  243. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  244. package/build/dist/Server/Middleware/MultipartFormData.js +93 -28
  245. package/build/dist/Server/Middleware/MultipartFormData.js.map +1 -1
  246. package/build/dist/Server/Services/AlertEpisodeLabelRuleEngineService.js +8 -1
  247. package/build/dist/Server/Services/AlertEpisodeLabelRuleEngineService.js.map +1 -1
  248. package/build/dist/Server/Services/AlertEpisodeOnCallRuleEngineService.js +8 -1
  249. package/build/dist/Server/Services/AlertEpisodeOnCallRuleEngineService.js.map +1 -1
  250. package/build/dist/Server/Services/AlertEpisodeOwnerRuleEngineService.js +8 -1
  251. package/build/dist/Server/Services/AlertEpisodeOwnerRuleEngineService.js.map +1 -1
  252. package/build/dist/Server/Services/AlertEpisodePrivacyRuleEngineService.js +8 -1
  253. package/build/dist/Server/Services/AlertEpisodePrivacyRuleEngineService.js.map +1 -1
  254. package/build/dist/Server/Services/AlertGroupingEngineService.js +8 -1
  255. package/build/dist/Server/Services/AlertGroupingEngineService.js.map +1 -1
  256. package/build/dist/Server/Services/AlertLabelRuleEngineService.js +8 -1
  257. package/build/dist/Server/Services/AlertLabelRuleEngineService.js.map +1 -1
  258. package/build/dist/Server/Services/AlertOnCallRuleEngineService.js +8 -1
  259. package/build/dist/Server/Services/AlertOnCallRuleEngineService.js.map +1 -1
  260. package/build/dist/Server/Services/AlertOwnerRuleEngineService.js +8 -1
  261. package/build/dist/Server/Services/AlertOwnerRuleEngineService.js.map +1 -1
  262. package/build/dist/Server/Services/AlertPrivacyRuleEngineService.js +8 -1
  263. package/build/dist/Server/Services/AlertPrivacyRuleEngineService.js.map +1 -1
  264. package/build/dist/Server/Services/AlertReminderRuleService.js +8 -1
  265. package/build/dist/Server/Services/AlertReminderRuleService.js.map +1 -1
  266. package/build/dist/Server/Services/AutoRemediationRuleEngineService.js +8 -1
  267. package/build/dist/Server/Services/AutoRemediationRuleEngineService.js.map +1 -1
  268. package/build/dist/Server/Services/CephClusterLabelRuleEngineService.js +8 -1
  269. package/build/dist/Server/Services/CephClusterLabelRuleEngineService.js.map +1 -1
  270. package/build/dist/Server/Services/CephClusterOwnerRuleEngineService.js +8 -1
  271. package/build/dist/Server/Services/CephClusterOwnerRuleEngineService.js.map +1 -1
  272. package/build/dist/Server/Services/CloudResourceLabelRuleEngineService.js +8 -1
  273. package/build/dist/Server/Services/CloudResourceLabelRuleEngineService.js.map +1 -1
  274. package/build/dist/Server/Services/CloudResourceOwnerRuleEngineService.js +8 -1
  275. package/build/dist/Server/Services/CloudResourceOwnerRuleEngineService.js.map +1 -1
  276. package/build/dist/Server/Services/DashboardLabelRuleEngineService.js +8 -1
  277. package/build/dist/Server/Services/DashboardLabelRuleEngineService.js.map +1 -1
  278. package/build/dist/Server/Services/DashboardOwnerRuleEngineService.js +8 -1
  279. package/build/dist/Server/Services/DashboardOwnerRuleEngineService.js.map +1 -1
  280. package/build/dist/Server/Services/DockerHostLabelRuleEngineService.js +8 -1
  281. package/build/dist/Server/Services/DockerHostLabelRuleEngineService.js.map +1 -1
  282. package/build/dist/Server/Services/DockerHostOwnerRuleEngineService.js +8 -1
  283. package/build/dist/Server/Services/DockerHostOwnerRuleEngineService.js.map +1 -1
  284. package/build/dist/Server/Services/DockerSwarmClusterLabelRuleEngineService.js +8 -1
  285. package/build/dist/Server/Services/DockerSwarmClusterLabelRuleEngineService.js.map +1 -1
  286. package/build/dist/Server/Services/DockerSwarmClusterOwnerRuleEngineService.js +8 -1
  287. package/build/dist/Server/Services/DockerSwarmClusterOwnerRuleEngineService.js.map +1 -1
  288. package/build/dist/Server/Services/HostLabelRuleEngineService.js +8 -1
  289. package/build/dist/Server/Services/HostLabelRuleEngineService.js.map +1 -1
  290. package/build/dist/Server/Services/HostOwnerRuleEngineService.js +8 -1
  291. package/build/dist/Server/Services/HostOwnerRuleEngineService.js.map +1 -1
  292. package/build/dist/Server/Services/IncidentEpisodeLabelRuleEngineService.js +8 -1
  293. package/build/dist/Server/Services/IncidentEpisodeLabelRuleEngineService.js.map +1 -1
  294. package/build/dist/Server/Services/IncidentEpisodeOnCallRuleEngineService.js +8 -1
  295. package/build/dist/Server/Services/IncidentEpisodeOnCallRuleEngineService.js.map +1 -1
  296. package/build/dist/Server/Services/IncidentEpisodeOwnerRuleEngineService.js +8 -1
  297. package/build/dist/Server/Services/IncidentEpisodeOwnerRuleEngineService.js.map +1 -1
  298. package/build/dist/Server/Services/IncidentEpisodePrivacyRuleEngineService.js +8 -1
  299. package/build/dist/Server/Services/IncidentEpisodePrivacyRuleEngineService.js.map +1 -1
  300. package/build/dist/Server/Services/IncidentGroupingEngineService.js +8 -1
  301. package/build/dist/Server/Services/IncidentGroupingEngineService.js.map +1 -1
  302. package/build/dist/Server/Services/IncidentLabelRuleEngineService.js +8 -1
  303. package/build/dist/Server/Services/IncidentLabelRuleEngineService.js.map +1 -1
  304. package/build/dist/Server/Services/IncidentOnCallRuleEngineService.js +8 -1
  305. package/build/dist/Server/Services/IncidentOnCallRuleEngineService.js.map +1 -1
  306. package/build/dist/Server/Services/IncidentOwnerRuleEngineService.js +8 -1
  307. package/build/dist/Server/Services/IncidentOwnerRuleEngineService.js.map +1 -1
  308. package/build/dist/Server/Services/IncidentPrivacyRuleEngineService.js +8 -1
  309. package/build/dist/Server/Services/IncidentPrivacyRuleEngineService.js.map +1 -1
  310. package/build/dist/Server/Services/IncidentReminderRuleService.js +8 -1
  311. package/build/dist/Server/Services/IncidentReminderRuleService.js.map +1 -1
  312. package/build/dist/Server/Services/IncidentSlaRuleService.js +8 -1
  313. package/build/dist/Server/Services/IncidentSlaRuleService.js.map +1 -1
  314. package/build/dist/Server/Services/IncomingCallPolicyLabelRuleEngineService.js +8 -1
  315. package/build/dist/Server/Services/IncomingCallPolicyLabelRuleEngineService.js.map +1 -1
  316. package/build/dist/Server/Services/IncomingCallPolicyOwnerRuleEngineService.js +8 -1
  317. package/build/dist/Server/Services/IncomingCallPolicyOwnerRuleEngineService.js.map +1 -1
  318. package/build/dist/Server/Services/Index.js +2 -0
  319. package/build/dist/Server/Services/Index.js.map +1 -1
  320. package/build/dist/Server/Services/IoTFleetLabelRuleEngineService.js +8 -1
  321. package/build/dist/Server/Services/IoTFleetLabelRuleEngineService.js.map +1 -1
  322. package/build/dist/Server/Services/IoTFleetOwnerRuleEngineService.js +8 -1
  323. package/build/dist/Server/Services/IoTFleetOwnerRuleEngineService.js.map +1 -1
  324. package/build/dist/Server/Services/KubernetesClusterLabelRuleEngineService.js +8 -1
  325. package/build/dist/Server/Services/KubernetesClusterLabelRuleEngineService.js.map +1 -1
  326. package/build/dist/Server/Services/KubernetesClusterOwnerRuleEngineService.js +8 -1
  327. package/build/dist/Server/Services/KubernetesClusterOwnerRuleEngineService.js.map +1 -1
  328. package/build/dist/Server/Services/KubernetesResourceService.js +5 -1
  329. package/build/dist/Server/Services/KubernetesResourceService.js.map +1 -1
  330. package/build/dist/Server/Services/MonitorLabelRuleEngineService.js +8 -1
  331. package/build/dist/Server/Services/MonitorLabelRuleEngineService.js.map +1 -1
  332. package/build/dist/Server/Services/MonitorOwnerRuleEngineService.js +8 -1
  333. package/build/dist/Server/Services/MonitorOwnerRuleEngineService.js.map +1 -1
  334. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js +30 -21
  335. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js.map +1 -1
  336. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js +64 -0
  337. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js.map +1 -1
  338. package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js +8 -1
  339. package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js.map +1 -1
  340. package/build/dist/Server/Services/NetworkDeviceOidTemplateService.js +180 -0
  341. package/build/dist/Server/Services/NetworkDeviceOidTemplateService.js.map +1 -0
  342. package/build/dist/Server/Services/NetworkDeviceOwnerRuleEngineService.js +8 -1
  343. package/build/dist/Server/Services/NetworkDeviceOwnerRuleEngineService.js.map +1 -1
  344. package/build/dist/Server/Services/NetworkDeviceService.js +154 -1
  345. package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
  346. package/build/dist/Server/Services/OnCallDutyPolicyLabelRuleEngineService.js +8 -1
  347. package/build/dist/Server/Services/OnCallDutyPolicyLabelRuleEngineService.js.map +1 -1
  348. package/build/dist/Server/Services/OnCallDutyPolicyOwnerRuleEngineService.js +8 -1
  349. package/build/dist/Server/Services/OnCallDutyPolicyOwnerRuleEngineService.js.map +1 -1
  350. package/build/dist/Server/Services/OnCallDutyPolicyScheduleLabelRuleEngineService.js +8 -1
  351. package/build/dist/Server/Services/OnCallDutyPolicyScheduleLabelRuleEngineService.js.map +1 -1
  352. package/build/dist/Server/Services/OnCallDutyPolicyScheduleOwnerRuleEngineService.js +8 -1
  353. package/build/dist/Server/Services/OnCallDutyPolicyScheduleOwnerRuleEngineService.js.map +1 -1
  354. package/build/dist/Server/Services/PodmanHostLabelRuleEngineService.js +8 -1
  355. package/build/dist/Server/Services/PodmanHostLabelRuleEngineService.js.map +1 -1
  356. package/build/dist/Server/Services/PodmanHostOwnerRuleEngineService.js +8 -1
  357. package/build/dist/Server/Services/PodmanHostOwnerRuleEngineService.js.map +1 -1
  358. package/build/dist/Server/Services/ProxmoxClusterLabelRuleEngineService.js +8 -1
  359. package/build/dist/Server/Services/ProxmoxClusterLabelRuleEngineService.js.map +1 -1
  360. package/build/dist/Server/Services/ProxmoxClusterOwnerRuleEngineService.js +8 -1
  361. package/build/dist/Server/Services/ProxmoxClusterOwnerRuleEngineService.js.map +1 -1
  362. package/build/dist/Server/Services/RumApplicationLabelRuleEngineService.js +8 -1
  363. package/build/dist/Server/Services/RumApplicationLabelRuleEngineService.js.map +1 -1
  364. package/build/dist/Server/Services/RumApplicationOwnerRuleEngineService.js +8 -1
  365. package/build/dist/Server/Services/RumApplicationOwnerRuleEngineService.js.map +1 -1
  366. package/build/dist/Server/Services/RunbookLabelRuleEngineService.js +8 -1
  367. package/build/dist/Server/Services/RunbookLabelRuleEngineService.js.map +1 -1
  368. package/build/dist/Server/Services/RunbookOwnerRuleEngineService.js +8 -1
  369. package/build/dist/Server/Services/RunbookOwnerRuleEngineService.js.map +1 -1
  370. package/build/dist/Server/Services/RunbookRuleEngineService.js +8 -1
  371. package/build/dist/Server/Services/RunbookRuleEngineService.js.map +1 -1
  372. package/build/dist/Server/Services/ScheduledMaintenanceLabelRuleEngineService.js +8 -1
  373. package/build/dist/Server/Services/ScheduledMaintenanceLabelRuleEngineService.js.map +1 -1
  374. package/build/dist/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.js +8 -1
  375. package/build/dist/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.js.map +1 -1
  376. package/build/dist/Server/Services/ScheduledMaintenanceReminderRuleService.js +8 -1
  377. package/build/dist/Server/Services/ScheduledMaintenanceReminderRuleService.js.map +1 -1
  378. package/build/dist/Server/Services/ServerlessFunctionLabelRuleEngineService.js +8 -1
  379. package/build/dist/Server/Services/ServerlessFunctionLabelRuleEngineService.js.map +1 -1
  380. package/build/dist/Server/Services/ServerlessFunctionOwnerRuleEngineService.js +8 -1
  381. package/build/dist/Server/Services/ServerlessFunctionOwnerRuleEngineService.js.map +1 -1
  382. package/build/dist/Server/Services/ServiceLabelRuleEngineService.js +8 -1
  383. package/build/dist/Server/Services/ServiceLabelRuleEngineService.js.map +1 -1
  384. package/build/dist/Server/Services/ServiceOwnerRuleEngineService.js +8 -1
  385. package/build/dist/Server/Services/ServiceOwnerRuleEngineService.js.map +1 -1
  386. package/build/dist/Server/Services/StatusPageLabelRuleEngineService.js +8 -1
  387. package/build/dist/Server/Services/StatusPageLabelRuleEngineService.js.map +1 -1
  388. package/build/dist/Server/Services/StatusPageMonitorRuleEngineService.js +6 -0
  389. package/build/dist/Server/Services/StatusPageMonitorRuleEngineService.js.map +1 -1
  390. package/build/dist/Server/Services/StatusPageOwnerRuleEngineService.js +8 -1
  391. package/build/dist/Server/Services/StatusPageOwnerRuleEngineService.js.map +1 -1
  392. package/build/dist/Server/Services/TelemetrySourceMapService.js +213 -19
  393. package/build/dist/Server/Services/TelemetrySourceMapService.js.map +1 -1
  394. package/build/dist/Server/Services/UserService.js +25 -0
  395. package/build/dist/Server/Services/UserService.js.map +1 -1
  396. package/build/dist/Server/Services/WorkflowLabelRuleEngineService.js +8 -1
  397. package/build/dist/Server/Services/WorkflowLabelRuleEngineService.js.map +1 -1
  398. package/build/dist/Server/Services/WorkflowOwnerRuleEngineService.js +8 -1
  399. package/build/dist/Server/Services/WorkflowOwnerRuleEngineService.js.map +1 -1
  400. package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js +145 -0
  401. package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js.map +1 -0
  402. package/build/dist/Server/Utils/Monitor/CapturedMetricAttributeUtil.js +201 -0
  403. package/build/dist/Server/Utils/Monitor/CapturedMetricAttributeUtil.js.map +1 -0
  404. package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js +19 -2
  405. package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js.map +1 -1
  406. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +42 -23
  407. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
  408. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +29 -0
  409. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
  410. package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js +11 -2
  411. package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js.map +1 -1
  412. package/build/dist/Server/Utils/Monitor/NetworkDeviceWalkUtil.js +16 -1
  413. package/build/dist/Server/Utils/Monitor/NetworkDeviceWalkUtil.js.map +1 -1
  414. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +10 -0
  415. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -1
  416. package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js +33 -0
  417. package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js.map +1 -1
  418. package/build/dist/Server/Utils/Rules/RuleEngineRuleRead.js +37 -0
  419. package/build/dist/Server/Utils/Rules/RuleEngineRuleRead.js.map +1 -0
  420. package/build/dist/Server/Utils/Telemetry/ExceptionSanitizer.js +12 -1
  421. package/build/dist/Server/Utils/Telemetry/ExceptionSanitizer.js.map +1 -1
  422. package/build/dist/Server/Utils/Telemetry/LogExceptionExtractor.js +14 -2
  423. package/build/dist/Server/Utils/Telemetry/LogExceptionExtractor.js.map +1 -1
  424. package/build/dist/Server/Utils/Telemetry/SourceMapResolver.js +15 -5
  425. package/build/dist/Server/Utils/Telemetry/SourceMapResolver.js.map +1 -1
  426. package/build/dist/Server/Utils/Telemetry/StackTraceParser.js +307 -0
  427. package/build/dist/Server/Utils/Telemetry/StackTraceParser.js.map +1 -1
  428. package/build/dist/Types/Date.js +27 -0
  429. package/build/dist/Types/Date.js.map +1 -1
  430. package/build/dist/Types/Monitor/SnmpMonitor/SnmpOidListUtil.js +253 -0
  431. package/build/dist/Types/Monitor/SnmpMonitor/SnmpOidListUtil.js.map +1 -0
  432. package/build/dist/Types/Permission.js +86 -0
  433. package/build/dist/Types/Permission.js.map +1 -1
  434. package/build/dist/Types/Rum/SessionReplay.js +19 -0
  435. package/build/dist/Types/Rum/SessionReplay.js.map +1 -1
  436. package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/AnnotationHoverCard.js +83 -0
  437. package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/AnnotationHoverCard.js.map +1 -0
  438. package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/AnnotationLayout.js +531 -0
  439. package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/AnnotationLayout.js.map +1 -0
  440. package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/ChartAnnotationLayer.js +264 -0
  441. package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/ChartAnnotationLayer.js.map +1 -0
  442. package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/UseChartAnnotations.js +122 -0
  443. package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/UseChartAnnotations.js.map +1 -0
  444. package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js +213 -233
  445. package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js.map +1 -1
  446. package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js +139 -152
  447. package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js.map +1 -1
  448. package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js +212 -232
  449. package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js.map +1 -1
  450. package/build/dist/UI/Components/Charts/Types/ChartEventKind.js +14 -0
  451. package/build/dist/UI/Components/Charts/Types/ChartEventKind.js.map +1 -0
  452. package/build/dist/UI/Components/Charts/Utils/TimeAnnotation.js +57 -28
  453. package/build/dist/UI/Components/Charts/Utils/TimeAnnotation.js.map +1 -1
  454. package/build/dist/UI/Components/Charts/Utils/XAxis.js +103 -17
  455. package/build/dist/UI/Components/Charts/Utils/XAxis.js.map +1 -1
  456. package/build/dist/UI/Components/EditionLabel/EditionLabel.js +198 -23
  457. package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
  458. package/build/dist/UI/Components/ErrorMessage/ErrorMessage.js +15 -5
  459. package/build/dist/UI/Components/ErrorMessage/ErrorMessage.js.map +1 -1
  460. package/build/dist/UI/Components/Feed/FeedItem.js +4 -5
  461. package/build/dist/UI/Components/Feed/FeedItem.js.map +1 -1
  462. package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js +1 -2
  463. package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js.map +1 -1
  464. package/build/dist/UI/Components/Header/UserProfile/UserProfile.js.map +1 -1
  465. package/build/dist/UI/Components/Image/Image.js +6 -1
  466. package/build/dist/UI/Components/Image/Image.js.map +1 -1
  467. package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js +0 -0
  468. package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js.map +1 -1
  469. package/build/dist/UI/Components/MemberRoleAssignment/MemberRoleAssignment.js +1 -2
  470. package/build/dist/UI/Components/MemberRoleAssignment/MemberRoleAssignment.js.map +1 -1
  471. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +104 -23
  472. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  473. package/build/dist/UI/Components/Table/TableHeader.js +20 -22
  474. package/build/dist/UI/Components/Table/TableHeader.js.map +1 -1
  475. package/build/dist/UI/Components/Table/TableRow.js +13 -4
  476. package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
  477. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js +153 -0
  478. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js.map +1 -0
  479. package/build/dist/Utils/NetworkDiscovery/AutoImportRuleMatcher.js.map +1 -1
  480. package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js +127 -7
  481. package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js.map +1 -1
  482. package/build/dist/Utils/NetworkDiscovery/DiscoveredHostUtil.js +50 -3
  483. package/build/dist/Utils/NetworkDiscovery/DiscoveredHostUtil.js.map +1 -1
  484. package/build/dist/Utils/NetworkDiscovery/ReverseDnsNameUtil.js +132 -0
  485. package/build/dist/Utils/NetworkDiscovery/ReverseDnsNameUtil.js.map +1 -0
  486. package/build/dist/Utils/Rules/RuleEngineLimits.js +31 -0
  487. package/build/dist/Utils/Rules/RuleEngineLimits.js.map +1 -0
  488. package/jest.config.json +1 -0
  489. package/package.json +2 -2
@@ -0,0 +1,686 @@
1
+ import { describe, expect, it } from "@jest/globals";
2
+ import {
3
+ htmlToMarkdown,
4
+ markdownToHtml,
5
+ } from "../../../UI/Components/Markdown.tsx/MarkdownConverters";
6
+
7
+ /*
8
+ * The markdown <-> HTML pair behind the WYSIWYG editor.
9
+ *
10
+ * Two things make this worth testing properly rather than spot-checking.
11
+ *
12
+ * The first is that the two directions are used in a loop: the editor renders
13
+ * markdown to HTML into a contenteditable, the user types, and the result is
14
+ * serialized back. A construct that survives one direction but not the other
15
+ * silently rewrites a document every time somebody opens it, so the
16
+ * round-trip block below is the point of this file rather than an extra.
17
+ *
18
+ * The second is that the HTML produced here is injected into the page. It is
19
+ * passed through DOMPurify by the caller, but the converter must not be the
20
+ * thing relying on that: text taken from the document has to arrive escaped.
21
+ */
22
+
23
+ describe("markdownToHtml", () => {
24
+ describe("empty input", () => {
25
+ it("returns an empty string for an empty document", () => {
26
+ expect(markdownToHtml("")).toBe("");
27
+ });
28
+ });
29
+
30
+ describe("headings", () => {
31
+ it("renders each of the six levels", () => {
32
+ for (let level: number = 1; level <= 6; level++) {
33
+ expect(markdownToHtml(`${"#".repeat(level)} Title`)).toBe(
34
+ `<h${level}>Title</h${level}>`,
35
+ );
36
+ }
37
+ });
38
+
39
+ it("does not treat a seventh hash level as a heading", () => {
40
+ expect(markdownToHtml("####### Title")).not.toContain("<h7>");
41
+ });
42
+
43
+ it("requires a space after the hashes", () => {
44
+ expect(markdownToHtml("#NotAHeading")).toBe("<p>#NotAHeading</p>");
45
+ });
46
+
47
+ it("drops the closing hashes of a closed ATX heading", () => {
48
+ expect(markdownToHtml("## Title ##")).toBe("<h2>Title</h2>");
49
+ });
50
+
51
+ it("renders inline markup inside a heading", () => {
52
+ expect(markdownToHtml("# A **bold** title")).toBe(
53
+ "<h1>A <strong>bold</strong> title</h1>",
54
+ );
55
+ });
56
+ });
57
+
58
+ describe("inline formatting", () => {
59
+ it("renders bold with asterisks and with underscores", () => {
60
+ expect(markdownToHtml("**a**")).toBe("<p><strong>a</strong></p>");
61
+ expect(markdownToHtml("__a__")).toBe("<p><strong>a</strong></p>");
62
+ });
63
+
64
+ it("renders italic with a single asterisk and a single underscore", () => {
65
+ expect(markdownToHtml("*a*")).toBe("<p><em>a</em></p>");
66
+ expect(markdownToHtml("_a_")).toBe("<p><em>a</em></p>");
67
+ });
68
+
69
+ /*
70
+ * Bold has to run before italic, or `**a**` is consumed as an empty
71
+ * emphasis wrapping a stray asterisk.
72
+ */
73
+ it("does not let italic eat the inner half of a bold span", () => {
74
+ expect(markdownToHtml("**bold**")).toBe("<p><strong>bold</strong></p>");
75
+ });
76
+
77
+ it("nests italic inside bold", () => {
78
+ expect(markdownToHtml("**a *b* c**")).toBe(
79
+ "<p><strong>a <em>b</em> c</strong></p>",
80
+ );
81
+ });
82
+
83
+ it("renders strikethrough", () => {
84
+ expect(markdownToHtml("~~gone~~")).toBe("<p><s>gone</s></p>");
85
+ });
86
+
87
+ it("renders inline code", () => {
88
+ expect(markdownToHtml("`x`")).toBe("<p><code>x</code></p>");
89
+ });
90
+
91
+ /*
92
+ * Inline code is literal. Running the inline pass over its contents would
93
+ * turn a documented markdown snippet into rendered markup.
94
+ */
95
+ it("does not parse markdown inside inline code", () => {
96
+ expect(markdownToHtml("`**not bold**`")).toBe(
97
+ "<p><code>**not bold**</code></p>",
98
+ );
99
+ });
100
+
101
+ it("escapes HTML inside inline code", () => {
102
+ expect(markdownToHtml("`<script>`")).toBe(
103
+ "<p><code>&lt;script&gt;</code></p>",
104
+ );
105
+ });
106
+
107
+ it("keeps the small allowlist of inline tags a user may type", () => {
108
+ expect(markdownToHtml("a <u>b</u> c")).toBe("<p>a <u>b</u> c</p>");
109
+ expect(markdownToHtml("x<sub>1</sub>")).toBe("<p>x<sub>1</sub></p>");
110
+ expect(markdownToHtml("press <kbd>K</kbd>")).toBe(
111
+ "<p>press <kbd>K</kbd></p>",
112
+ );
113
+ });
114
+ });
115
+
116
+ describe("escaping", () => {
117
+ /*
118
+ * The output is injected into the page. DOMPurify runs after this, but
119
+ * the converter must not be what makes the difference.
120
+ */
121
+ it("escapes a script tag in plain text", () => {
122
+ const html: string = markdownToHtml("<script>alert(1)</script>");
123
+
124
+ expect(html).not.toContain("<script>");
125
+ expect(html).toContain("&lt;script&gt;");
126
+ });
127
+
128
+ it("escapes an img onerror payload in plain text", () => {
129
+ const html: string = markdownToHtml('<img src=x onerror="alert(1)">');
130
+
131
+ expect(html).not.toContain("<img src=x");
132
+ expect(html).toContain("&lt;img");
133
+ });
134
+
135
+ it("escapes a quote in a link title attribute", () => {
136
+ const html: string = markdownToHtml('[a](http://e.com "t\\"x")');
137
+
138
+ expect(html).not.toContain('title="t""');
139
+ });
140
+
141
+ it("escapes an ampersand in link text", () => {
142
+ expect(markdownToHtml("a & b")).toBe("<p>a &amp; b</p>");
143
+ });
144
+
145
+ it("escapes HTML inside a fenced code block", () => {
146
+ expect(markdownToHtml("```\n<b>hi</b>\n```")).toBe(
147
+ "<pre><code>&lt;b&gt;hi&lt;/b&gt;</code></pre>",
148
+ );
149
+ });
150
+ });
151
+
152
+ describe("links and images", () => {
153
+ it("renders a link", () => {
154
+ expect(markdownToHtml("[label](http://example.com)")).toBe(
155
+ '<p><a href="http://example.com">label</a></p>',
156
+ );
157
+ });
158
+
159
+ it("renders a link title", () => {
160
+ expect(markdownToHtml('[label](http://example.com "hi")')).toBe(
161
+ '<p><a href="http://example.com" title="hi">label</a></p>',
162
+ );
163
+ });
164
+
165
+ it("renders inline markup inside a link label", () => {
166
+ expect(markdownToHtml("[**bold**](http://example.com)")).toBe(
167
+ '<p><a href="http://example.com"><strong>bold</strong></a></p>',
168
+ );
169
+ });
170
+
171
+ it("renders an image", () => {
172
+ expect(markdownToHtml("![alt](http://example.com/a.png)")).toBe(
173
+ '<p><img alt="alt" src="http://example.com/a.png"></p>',
174
+ );
175
+ });
176
+
177
+ /* An image is a link with a bang, so the image rule must run first. */
178
+ it("does not render an image as a link", () => {
179
+ expect(markdownToHtml("![alt](http://example.com/a.png)")).not.toContain(
180
+ "<a ",
181
+ );
182
+ });
183
+
184
+ it("renders an image with an empty alt", () => {
185
+ expect(markdownToHtml("![](http://example.com/a.png)")).toBe(
186
+ '<p><img alt="" src="http://example.com/a.png"></p>',
187
+ );
188
+ });
189
+ });
190
+
191
+ describe("code blocks", () => {
192
+ it("renders a fenced block with no language", () => {
193
+ expect(markdownToHtml("```\nx = 1\n```")).toBe(
194
+ "<pre><code>x = 1</code></pre>",
195
+ );
196
+ });
197
+
198
+ it("carries the language onto the code element", () => {
199
+ expect(markdownToHtml("```ts\nx = 1\n```")).toBe(
200
+ '<pre><code class="language-ts">x = 1</code></pre>',
201
+ );
202
+ });
203
+
204
+ it("keeps blank lines inside a fenced block", () => {
205
+ expect(markdownToHtml("```\na\n\nb\n```")).toBe(
206
+ "<pre><code>a\n\nb</code></pre>",
207
+ );
208
+ });
209
+
210
+ it("closes an unterminated fence at the end of the document", () => {
211
+ expect(markdownToHtml("```\na")).toBe("<pre><code>a</code></pre>");
212
+ });
213
+
214
+ /* A fence must end the paragraph above it rather than joining it. */
215
+ it("ends the paragraph above a fence", () => {
216
+ expect(markdownToHtml("text\n```\na\n```")).toBe(
217
+ "<p>text</p><pre><code>a</code></pre>",
218
+ );
219
+ });
220
+ });
221
+
222
+ describe("lists", () => {
223
+ it("renders an unordered list", () => {
224
+ expect(markdownToHtml("- a\n- b")).toBe("<ul><li>a</li><li>b</li></ul>");
225
+ });
226
+
227
+ it("accepts every unordered bullet character", () => {
228
+ expect(markdownToHtml("* a")).toBe("<ul><li>a</li></ul>");
229
+ expect(markdownToHtml("+ a")).toBe("<ul><li>a</li></ul>");
230
+ });
231
+
232
+ it("renders an ordered list", () => {
233
+ expect(markdownToHtml("1. a\n2. b")).toBe(
234
+ "<ol><li>a</li><li>b</li></ol>",
235
+ );
236
+ });
237
+
238
+ /*
239
+ * Switching marker kind starts a new list. Without that break an ordered
240
+ * item would be swallowed into the unordered list above it.
241
+ */
242
+ it("starts a new list when the marker kind changes", () => {
243
+ expect(markdownToHtml("- a\n1. b")).toBe(
244
+ "<ul><li>a</li></ul><ol><li>b</li></ol>",
245
+ );
246
+ });
247
+
248
+ it("renders a task list", () => {
249
+ const html: string = markdownToHtml("- [ ] a\n- [x] b");
250
+
251
+ expect(html).toContain('<ul class="task-list">');
252
+ expect(html).toContain('<li class="task-list-item">');
253
+ expect(html).toContain("checked");
254
+ });
255
+
256
+ it("accepts an upper-case task marker", () => {
257
+ expect(markdownToHtml("- [X] a")).toContain("checked");
258
+ });
259
+
260
+ /* WCAG 4.1.2: the disabled checkbox needs an accessible name. */
261
+ it("gives a task checkbox an accessible name from its label", () => {
262
+ expect(markdownToHtml("- [ ] Deploy the thing")).toContain(
263
+ 'aria-label="Deploy the thing"',
264
+ );
265
+ });
266
+
267
+ it("falls back to a generic accessible name for an empty task", () => {
268
+ expect(markdownToHtml("- [ ] ")).not.toContain('aria-label=""');
269
+ });
270
+
271
+ it("renders inline markup inside a list item", () => {
272
+ expect(markdownToHtml("- a **b**")).toBe(
273
+ "<ul><li>a <strong>b</strong></li></ul>",
274
+ );
275
+ });
276
+ });
277
+
278
+ describe("blockquotes", () => {
279
+ it("renders a single quoted line", () => {
280
+ expect(markdownToHtml("> hi")).toBe("<blockquote><p>hi</p></blockquote>");
281
+ });
282
+
283
+ it("joins contiguous quoted lines into one quote", () => {
284
+ expect(markdownToHtml("> a\n> b")).toBe(
285
+ "<blockquote><p>a<br>b</p></blockquote>",
286
+ );
287
+ });
288
+
289
+ it("ends a quote at the first unquoted line", () => {
290
+ expect(markdownToHtml("> a\nb")).toBe(
291
+ "<blockquote><p>a</p></blockquote><p>b</p>",
292
+ );
293
+ });
294
+ });
295
+
296
+ describe("horizontal rules", () => {
297
+ it("accepts each rule spelling", () => {
298
+ expect(markdownToHtml("---")).toBe("<hr>");
299
+ expect(markdownToHtml("***")).toBe("<hr>");
300
+ expect(markdownToHtml("___")).toBe("<hr>");
301
+ });
302
+ });
303
+
304
+ describe("tables", () => {
305
+ it("renders a GFM table", () => {
306
+ expect(markdownToHtml("| a | b |\n| --- | --- |\n| 1 | 2 |")).toBe(
307
+ "<table><thead><tr><th>a</th><th>b</th></tr></thead>" +
308
+ "<tbody><tr><td>1</td><td>2</td></tr></tbody></table>",
309
+ );
310
+ });
311
+
312
+ it("accepts an alignment row", () => {
313
+ expect(markdownToHtml("| a | b |\n| :-- | --: |\n| 1 | 2 |")).toContain(
314
+ "<table>",
315
+ );
316
+ });
317
+
318
+ /*
319
+ * A pipe in a paragraph is not a table. Without the separator check the
320
+ * next line would be eaten as a header row.
321
+ */
322
+ it("does not treat a bare pipe line as a table", () => {
323
+ expect(markdownToHtml("a | b\nplain text")).toBe(
324
+ "<p>a | b<br>plain text</p>",
325
+ );
326
+ });
327
+
328
+ it("pads a short row out to the header width", () => {
329
+ expect(markdownToHtml("| a | b |\n| --- | --- |\n| 1 |")).toContain(
330
+ "<td>1</td><td></td>",
331
+ );
332
+ });
333
+
334
+ it("renders inline markup inside a cell", () => {
335
+ expect(
336
+ markdownToHtml("| a | b |\n| --- | --- |\n| **c** | d |"),
337
+ ).toContain("<td><strong>c</strong></td>");
338
+ });
339
+
340
+ /*
341
+ * Regression. `tableToMarkdown` happily emits a one column table, so the
342
+ * editor's render/serialize loop feeds one straight back in. While the
343
+ * delimiter row needed two or more columns to match, that table came back
344
+ * as a paragraph and the document lost its table on every reopen.
345
+ */
346
+ it("recognises a one column table", () => {
347
+ expect(markdownToHtml("| a |\n| --- |\n| 1 |")).toBe(
348
+ "<table><thead><tr><th>a</th></tr></thead>" +
349
+ "<tbody><tr><td>1</td></tr></tbody></table>",
350
+ );
351
+ });
352
+
353
+ /*
354
+ * The other side of that change. Relaxing the delimiter row to allow a
355
+ * single column also lets a bare `---` match the pattern, so a rule under
356
+ * a line containing a pipe must still be a rule.
357
+ */
358
+ it("still treats a bare rule under a piped line as a rule", () => {
359
+ expect(markdownToHtml("a | b\n---")).toBe("<p>a | b</p><hr>");
360
+ });
361
+ });
362
+
363
+ describe("paragraphs", () => {
364
+ it("joins wrapped lines with a break", () => {
365
+ expect(markdownToHtml("a\nb")).toBe("<p>a<br>b</p>");
366
+ });
367
+
368
+ it("splits paragraphs on a blank line", () => {
369
+ expect(markdownToHtml("a\n\nb")).toBe("<p>a</p><p>b</p>");
370
+ });
371
+
372
+ it("normalizes CRLF line endings", () => {
373
+ expect(markdownToHtml("a\r\n\r\nb")).toBe("<p>a</p><p>b</p>");
374
+ });
375
+
376
+ it("normalizes a lone CR", () => {
377
+ expect(markdownToHtml("a\rb")).toBe("<p>a<br>b</p>");
378
+ });
379
+ });
380
+ });
381
+
382
+ describe("htmlToMarkdown", () => {
383
+ describe("empty input", () => {
384
+ it("returns an empty string for empty HTML", () => {
385
+ expect(htmlToMarkdown("")).toBe("");
386
+ });
387
+ });
388
+
389
+ describe("blocks", () => {
390
+ it("serializes each heading level", () => {
391
+ for (let level: number = 1; level <= 6; level++) {
392
+ expect(htmlToMarkdown(`<h${level}>T</h${level}>`)).toBe(
393
+ `${"#".repeat(level)} T`,
394
+ );
395
+ }
396
+ });
397
+
398
+ it("serializes a paragraph", () => {
399
+ expect(htmlToMarkdown("<p>a</p>")).toBe("a");
400
+ });
401
+
402
+ it("serializes a horizontal rule", () => {
403
+ expect(htmlToMarkdown("<hr>")).toBe("---");
404
+ });
405
+
406
+ it("turns a break into a newline", () => {
407
+ expect(htmlToMarkdown("<p>a<br>b</p>")).toBe("a\nb");
408
+ });
409
+
410
+ it("serializes a blockquote with a marker on every line", () => {
411
+ expect(htmlToMarkdown("<blockquote><p>a<br>b</p></blockquote>")).toBe(
412
+ "> a\n> b",
413
+ );
414
+ });
415
+
416
+ it("collapses runs of blank lines", () => {
417
+ expect(htmlToMarkdown("<p>a</p><p>b</p>")).toBe("a\n\nb");
418
+ });
419
+ });
420
+
421
+ describe("inline", () => {
422
+ it("serializes both spellings of bold", () => {
423
+ expect(htmlToMarkdown("<p><strong>a</strong></p>")).toBe("**a**");
424
+ expect(htmlToMarkdown("<p><b>a</b></p>")).toBe("**a**");
425
+ });
426
+
427
+ it("serializes both spellings of italic", () => {
428
+ expect(htmlToMarkdown("<p><em>a</em></p>")).toBe("*a*");
429
+ expect(htmlToMarkdown("<p><i>a</i></p>")).toBe("*a*");
430
+ });
431
+
432
+ it("serializes every spelling of strikethrough", () => {
433
+ expect(htmlToMarkdown("<p><s>a</s></p>")).toBe("~~a~~");
434
+ expect(htmlToMarkdown("<p><del>a</del></p>")).toBe("~~a~~");
435
+ expect(htmlToMarkdown("<p><strike>a</strike></p>")).toBe("~~a~~");
436
+ });
437
+
438
+ /* Underline has no markdown spelling, so it stays as a tag. */
439
+ it("keeps underline as an HTML tag", () => {
440
+ expect(htmlToMarkdown("<p><u>a</u></p>")).toBe("<u>a</u>");
441
+ });
442
+
443
+ it("keeps sub, sup and kbd as HTML tags", () => {
444
+ expect(htmlToMarkdown("<p><sub>a</sub></p>")).toBe("<sub>a</sub>");
445
+ expect(htmlToMarkdown("<p><sup>a</sup></p>")).toBe("<sup>a</sup>");
446
+ expect(htmlToMarkdown("<p><kbd>a</kbd></p>")).toBe("<kbd>a</kbd>");
447
+ });
448
+
449
+ it("serializes inline code", () => {
450
+ expect(htmlToMarkdown("<p><code>a</code></p>")).toBe("`a`");
451
+ });
452
+
453
+ it("serializes a link", () => {
454
+ expect(htmlToMarkdown('<p><a href="http://e.com">a</a></p>')).toBe(
455
+ "[a](http://e.com)",
456
+ );
457
+ });
458
+
459
+ it("falls back to the href when a link has no text", () => {
460
+ expect(htmlToMarkdown('<p><a href="http://e.com"></a></p>')).toBe(
461
+ "[http://e.com](http://e.com)",
462
+ );
463
+ });
464
+
465
+ it("drops the link syntax when there is no href", () => {
466
+ expect(htmlToMarkdown("<p><a>a</a></p>")).toBe("a");
467
+ });
468
+
469
+ it("serializes an image", () => {
470
+ expect(htmlToMarkdown('<p><img alt="a" src="b.png"></p>')).toBe(
471
+ "![a](b.png)",
472
+ );
473
+ });
474
+
475
+ it("serializes an image title", () => {
476
+ expect(htmlToMarkdown('<p><img alt="a" src="b.png" title="t"></p>')).toBe(
477
+ '![a](b.png "t")',
478
+ );
479
+ });
480
+ });
481
+
482
+ describe("code blocks", () => {
483
+ it("serializes a pre/code pair", () => {
484
+ expect(htmlToMarkdown("<pre><code>x = 1</code></pre>")).toBe(
485
+ "```\nx = 1\n```",
486
+ );
487
+ });
488
+
489
+ it("recovers the language from the code class", () => {
490
+ expect(
491
+ htmlToMarkdown('<pre><code class="language-ts">x</code></pre>'),
492
+ ).toBe("```ts\nx\n```");
493
+ });
494
+
495
+ /* The text is already literal; re-escaping it would corrupt the source. */
496
+ it("does not escape the contents of a code block", () => {
497
+ expect(htmlToMarkdown("<pre><code>a &lt; b</code></pre>")).toBe(
498
+ "```\na < b\n```",
499
+ );
500
+ });
501
+ });
502
+
503
+ describe("lists", () => {
504
+ it("serializes an unordered list", () => {
505
+ expect(htmlToMarkdown("<ul><li>a</li><li>b</li></ul>")).toBe("- a\n- b");
506
+ });
507
+
508
+ it("numbers an ordered list from one regardless of the source numbers", () => {
509
+ expect(htmlToMarkdown("<ol><li>a</li><li>b</li><li>c</li></ol>")).toBe(
510
+ "1. a\n2. b\n3. c",
511
+ );
512
+ });
513
+
514
+ it("serializes a task list back to its markers", () => {
515
+ expect(
516
+ htmlToMarkdown(
517
+ '<ul class="task-list">' +
518
+ '<li class="task-list-item"><input type="checkbox" disabled> a</li>' +
519
+ '<li class="task-list-item"><input type="checkbox" disabled checked> b</li>' +
520
+ "</ul>",
521
+ ),
522
+ ).toBe("- [ ] a\n- [x] b");
523
+ });
524
+
525
+ it("drops a bare checkbox that is not inside a list item", () => {
526
+ const md: string = htmlToMarkdown('<p><input type="checkbox"> a</p>');
527
+
528
+ expect(md).not.toContain("[ ]");
529
+ expect(md.trim()).toBe("a");
530
+ });
531
+
532
+ it("ignores a non-li child of a list", () => {
533
+ expect(htmlToMarkdown("<ul><span>x</span><li>a</li></ul>")).toBe("- a");
534
+ });
535
+
536
+ /* A continuation line has to be indented or it leaves the item. */
537
+ it("indents a continuation line so it stays inside its item", () => {
538
+ expect(htmlToMarkdown("<ul><li>a<br>b</li></ul>")).toBe("- a\n b");
539
+ });
540
+ });
541
+
542
+ describe("tables", () => {
543
+ it("serializes a table to a padded GFM table", () => {
544
+ expect(
545
+ htmlToMarkdown(
546
+ "<table><thead><tr><th>a</th><th>b</th></tr></thead>" +
547
+ "<tbody><tr><td>1</td><td>2</td></tr></tbody></table>",
548
+ ),
549
+ ).toBe("| a | b |\n| --- | --- |\n| 1 | 2 |");
550
+ });
551
+
552
+ it("widens a column to its longest cell", () => {
553
+ const md: string = htmlToMarkdown(
554
+ "<table><tr><th>a</th></tr><tr><td>longer</td></tr></table>",
555
+ );
556
+
557
+ expect(md).toContain("| a |");
558
+ expect(md).toContain("| longer |");
559
+ });
560
+
561
+ /* An unescaped pipe in a cell would split it into two columns. */
562
+ it("escapes a pipe inside a cell", () => {
563
+ expect(htmlToMarkdown("<table><tr><th>a|b</th></tr></table>")).toContain(
564
+ "a\\|b",
565
+ );
566
+ });
567
+
568
+ it("flattens a newline inside a cell", () => {
569
+ expect(
570
+ htmlToMarkdown("<table><tr><th>a<br>b</th></tr></table>"),
571
+ ).toContain("| a b |");
572
+ });
573
+
574
+ it("returns nothing for a table with no rows", () => {
575
+ expect(htmlToMarkdown("<table></table>")).toBe("");
576
+ });
577
+ });
578
+
579
+ describe("unknown elements", () => {
580
+ it("keeps the text of an element it does not know", () => {
581
+ expect(htmlToMarkdown("<p><span>a</span></p>")).toBe("a");
582
+ });
583
+
584
+ it("keeps the text of a div", () => {
585
+ expect(htmlToMarkdown("<div>a</div>")).toBe("a");
586
+ });
587
+
588
+ it("drops a comment node", () => {
589
+ expect(htmlToMarkdown("<p>a<!-- note --></p>")).toBe("a");
590
+ });
591
+ });
592
+ });
593
+
594
+ /*
595
+ * The property that actually matters. The editor renders markdown into a
596
+ * contenteditable and serializes it back on every change, so anything that
597
+ * does not survive the loop is a document the editor silently rewrites.
598
+ */
599
+ describe("markdown round trip", () => {
600
+ const cases: Array<{ name: string; markdown: string }> = [
601
+ { name: "a heading", markdown: "# Title" },
602
+ { name: "a deep heading", markdown: "###### Title" },
603
+ { name: "a paragraph", markdown: "Just some text." },
604
+ { name: "bold", markdown: "**bold**" },
605
+ { name: "italic", markdown: "*italic*" },
606
+ { name: "strikethrough", markdown: "~~gone~~" },
607
+ { name: "inline code", markdown: "`code`" },
608
+ { name: "underline", markdown: "<u>under</u>" },
609
+ { name: "a link", markdown: "[label](http://example.com)" },
610
+ { name: "an image", markdown: "![alt](http://example.com/a.png)" },
611
+ { name: "a rule", markdown: "---" },
612
+ { name: "an unordered list", markdown: "- a\n- b" },
613
+ { name: "an ordered list", markdown: "1. a\n2. b" },
614
+ { name: "a task list", markdown: "- [ ] a\n- [x] b" },
615
+ { name: "a blockquote", markdown: "> quoted" },
616
+ { name: "a fenced block", markdown: "```\nx = 1\n```" },
617
+ { name: "a fenced block with a language", markdown: "```ts\nx = 1\n```" },
618
+ { name: "two paragraphs", markdown: "one\n\ntwo" },
619
+ { name: "mixed inline markup", markdown: "a **b** and *c* and `d`" },
620
+ ];
621
+
622
+ for (const testCase of cases) {
623
+ it(`preserves ${testCase.name}`, () => {
624
+ const once: string = htmlToMarkdown(markdownToHtml(testCase.markdown));
625
+
626
+ expect(once).toBe(testCase.markdown);
627
+ });
628
+ }
629
+
630
+ /*
631
+ * Tables are padded on the way back, so they do not round trip
632
+ * character-for-character. What must hold is that the SECOND pass is a
633
+ * no-op -- otherwise the document grows every time it is opened.
634
+ */
635
+ it("preserves a one column table across the loop", () => {
636
+ const first: string = htmlToMarkdown(
637
+ markdownToHtml("| a |\n| --- |\n| 1 |"),
638
+ );
639
+
640
+ expect(markdownToHtml(first)).toContain("<table>");
641
+ expect(htmlToMarkdown(markdownToHtml(first))).toBe(first);
642
+ });
643
+
644
+ it("reaches a fixed point for a table after one pass", () => {
645
+ const first: string = htmlToMarkdown(
646
+ markdownToHtml("| a | b |\n| --- | --- |\n| 1 | 2 |"),
647
+ );
648
+ const second: string = htmlToMarkdown(markdownToHtml(first));
649
+
650
+ expect(second).toBe(first);
651
+ });
652
+
653
+ it("reaches a fixed point for a mixed document after one pass", () => {
654
+ const source: string = [
655
+ "# Title",
656
+ "",
657
+ "Some **bold** text with a [link](http://example.com).",
658
+ "",
659
+ "- one",
660
+ "- two",
661
+ "",
662
+ "> a quote",
663
+ "",
664
+ "```ts",
665
+ "const x: number = 1;",
666
+ "```",
667
+ ].join("\n");
668
+
669
+ const first: string = htmlToMarkdown(markdownToHtml(source));
670
+ const second: string = htmlToMarkdown(markdownToHtml(first));
671
+
672
+ expect(second).toBe(first);
673
+ });
674
+
675
+ /*
676
+ * The loop must not be able to promote text into markup. A user who typed
677
+ * a literal angle bracket must still have one after a save and a reopen.
678
+ */
679
+ it("does not turn escaped text into live markup across a round trip", () => {
680
+ const html: string = markdownToHtml(
681
+ htmlToMarkdown(markdownToHtml("<script>alert(1)</script>")),
682
+ );
683
+
684
+ expect(html).not.toContain("<script>");
685
+ });
686
+ });