@capillarytech/creatives-library 8.0.263 → 8.0.265

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 (280) hide show
  1. package/assets/Android.png +0 -0
  2. package/assets/iOS.png +0 -0
  3. package/constants/unified.js +1 -3
  4. package/initialReducer.js +0 -2
  5. package/package.json +1 -1
  6. package/services/api.js +0 -15
  7. package/services/tests/api.test.js +0 -34
  8. package/tests/integration/TemplateCreation/TemplateCreation.integration.test.js +35 -17
  9. package/tests/integration/TemplateCreation/api-response.js +1 -31
  10. package/tests/integration/TemplateCreation/msw-handler.js +0 -2
  11. package/utils/common.js +0 -11
  12. package/utils/commonUtils.js +5 -28
  13. package/utils/tests/commonUtil.test.js +0 -224
  14. package/utils/tests/transformerUtils.test.js +0 -297
  15. package/utils/transformTemplateConfig.js +10 -0
  16. package/utils/transformerUtils.js +0 -40
  17. package/v2Components/CapDeviceContent/index.js +56 -61
  18. package/v2Components/CapImageUpload/constants.js +0 -2
  19. package/v2Components/CapImageUpload/index.js +16 -65
  20. package/v2Components/CapImageUpload/index.scss +1 -4
  21. package/v2Components/CapImageUpload/messages.js +1 -5
  22. package/v2Components/CapTagList/index.js +1 -6
  23. package/v2Components/CapTagListWithInput/index.js +1 -5
  24. package/v2Components/CapTagListWithInput/messages.js +1 -1
  25. package/v2Components/CapWhatsappCTA/tests/index.test.js +0 -5
  26. package/v2Components/ErrorInfoNote/index.js +72 -402
  27. package/v2Components/ErrorInfoNote/messages.js +6 -32
  28. package/v2Components/ErrorInfoNote/style.scss +6 -278
  29. package/v2Components/FormBuilder/tests/index.test.js +4 -13
  30. package/v2Components/HtmlEditor/HTMLEditor.js +99 -418
  31. package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +133 -1882
  32. package/v2Components/HtmlEditor/__tests__/index.lazy.test.js +16 -27
  33. package/v2Components/HtmlEditor/_htmlEditor.scss +45 -108
  34. package/v2Components/HtmlEditor/_index.lazy.scss +1 -0
  35. package/v2Components/HtmlEditor/components/CodeEditorPane/_codeEditorPane.scss +102 -23
  36. package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +140 -148
  37. package/v2Components/HtmlEditor/components/DeviceToggle/_deviceToggle.scss +1 -2
  38. package/v2Components/HtmlEditor/components/DeviceToggle/index.js +3 -3
  39. package/v2Components/HtmlEditor/components/EditorToolbar/_editorToolbar.scss +1 -9
  40. package/v2Components/HtmlEditor/components/EditorToolbar/index.js +6 -31
  41. package/v2Components/HtmlEditor/components/FullscreenModal/_fullscreenModal.scss +0 -22
  42. package/v2Components/HtmlEditor/components/InAppPreviewPane/DeviceFrame.js +7 -4
  43. package/v2Components/HtmlEditor/components/InAppPreviewPane/__tests__/DeviceFrame.test.js +45 -35
  44. package/v2Components/HtmlEditor/components/InAppPreviewPane/_inAppPreviewPane.scss +3 -1
  45. package/v2Components/HtmlEditor/components/InAppPreviewPane/constants.js +33 -33
  46. package/v2Components/HtmlEditor/components/InAppPreviewPane/index.js +6 -7
  47. package/v2Components/HtmlEditor/components/PreviewPane/_previewPane.scss +10 -7
  48. package/v2Components/HtmlEditor/components/PreviewPane/index.js +43 -22
  49. package/v2Components/HtmlEditor/components/SplitContainer/_splitContainer.scss +1 -1
  50. package/v2Components/HtmlEditor/components/ValidationErrorDisplay/__tests__/index.test.js +152 -0
  51. package/v2Components/HtmlEditor/components/ValidationErrorDisplay/_validationErrorDisplay.scss +0 -18
  52. package/v2Components/HtmlEditor/components/ValidationErrorDisplay/index.js +31 -36
  53. package/v2Components/HtmlEditor/components/ValidationPanel/_validationPanel.scss +34 -46
  54. package/v2Components/HtmlEditor/components/ValidationPanel/index.js +46 -52
  55. package/v2Components/HtmlEditor/constants.js +20 -45
  56. package/v2Components/HtmlEditor/hooks/__tests__/useInAppContent.test.js +16 -373
  57. package/v2Components/HtmlEditor/hooks/__tests__/useValidation.test.js +16 -351
  58. package/v2Components/HtmlEditor/hooks/useEditorContent.js +2 -5
  59. package/v2Components/HtmlEditor/hooks/useInAppContent.js +146 -88
  60. package/v2Components/HtmlEditor/hooks/useValidation.js +56 -213
  61. package/v2Components/HtmlEditor/index.js +1 -1
  62. package/v2Components/HtmlEditor/messages.js +94 -102
  63. package/v2Components/HtmlEditor/utils/__tests__/htmlValidator.enhanced.test.js +45 -214
  64. package/v2Components/HtmlEditor/utils/__tests__/validationAdapter.test.js +0 -134
  65. package/v2Components/HtmlEditor/utils/contentSanitizer.js +41 -40
  66. package/v2Components/HtmlEditor/utils/htmlValidator.js +72 -71
  67. package/v2Components/HtmlEditor/utils/liquidTemplateSupport.js +124 -158
  68. package/v2Components/HtmlEditor/utils/properSyntaxHighlighting.js +25 -23
  69. package/v2Components/HtmlEditor/utils/validationAdapter.js +41 -66
  70. package/v2Components/MobilePushPreviewV2/index.js +7 -33
  71. package/v2Components/TemplatePreview/_templatePreview.scss +24 -55
  72. package/v2Components/TemplatePreview/index.js +32 -47
  73. package/v2Components/TemplatePreview/messages.js +0 -4
  74. package/v2Components/TestAndPreviewSlidebox/_testAndPreviewSlidebox.scss +0 -1
  75. package/v2Containers/App/constants.js +0 -5
  76. package/v2Containers/BeeEditor/index.js +90 -172
  77. package/v2Containers/CreativesContainer/SlideBoxContent.js +53 -184
  78. package/v2Containers/CreativesContainer/SlideBoxFooter.js +13 -163
  79. package/v2Containers/CreativesContainer/SlideBoxHeader.js +1 -3
  80. package/v2Containers/CreativesContainer/constants.js +0 -4
  81. package/v2Containers/CreativesContainer/index.js +46 -408
  82. package/v2Containers/CreativesContainer/messages.js +0 -12
  83. package/v2Containers/CreativesContainer/tests/SlideBoxContent.test.js +0 -210
  84. package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +2 -11
  85. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +50 -342
  86. package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +0 -103
  87. package/v2Containers/Email/actions.js +0 -7
  88. package/v2Containers/Email/constants.js +1 -5
  89. package/v2Containers/Email/index.js +36 -237
  90. package/v2Containers/Email/messages.js +0 -32
  91. package/v2Containers/Email/reducer.js +1 -12
  92. package/v2Containers/Email/sagas.js +7 -61
  93. package/v2Containers/Email/tests/__snapshots__/reducer.test.js.snap +0 -2
  94. package/v2Containers/Email/tests/reducer.test.js +0 -46
  95. package/v2Containers/Email/tests/sagas.test.js +29 -320
  96. package/v2Containers/EmailWrapper/components/EmailWrapperView.js +21 -211
  97. package/v2Containers/EmailWrapper/components/HTMLEditorTesting.js +74 -40
  98. package/v2Containers/EmailWrapper/components/__tests__/HTMLEditorTesting.test.js +67 -2
  99. package/v2Containers/EmailWrapper/constants.js +0 -2
  100. package/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +77 -629
  101. package/v2Containers/EmailWrapper/index.js +23 -103
  102. package/v2Containers/EmailWrapper/messages.js +1 -65
  103. package/v2Containers/EmailWrapper/tests/EmailWrapperView.test.js +214 -0
  104. package/v2Containers/EmailWrapper/tests/useEmailWrapper.test.js +77 -594
  105. package/v2Containers/InApp/actions.js +0 -7
  106. package/v2Containers/InApp/constants.js +4 -20
  107. package/v2Containers/InApp/index.js +359 -802
  108. package/v2Containers/InApp/index.scss +3 -4
  109. package/v2Containers/InApp/messages.js +3 -7
  110. package/v2Containers/InApp/reducer.js +3 -21
  111. package/v2Containers/InApp/sagas.js +9 -29
  112. package/v2Containers/InApp/selectors.js +5 -25
  113. package/v2Containers/InApp/tests/index.test.js +50 -154
  114. package/v2Containers/InApp/tests/reducer.test.js +0 -34
  115. package/v2Containers/InApp/tests/sagas.test.js +9 -61
  116. package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/content.test.js.snap +0 -3
  117. package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/index.test.js.snap +0 -2
  118. package/v2Containers/Line/Container/Wrapper/tests/__snapshots__/index.test.js.snap +0 -2
  119. package/v2Containers/Line/Container/tests/__snapshots__/index.test.js.snap +0 -9
  120. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +0 -12
  121. package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +0 -4
  122. package/v2Containers/TagList/index.js +19 -62
  123. package/v2Containers/Templates/ChannelTypeIllustration.js +1 -13
  124. package/v2Containers/Templates/_templates.scss +1 -265
  125. package/v2Containers/Templates/actions.js +1 -2
  126. package/v2Containers/Templates/constants.js +0 -1
  127. package/v2Containers/Templates/index.js +38 -363
  128. package/v2Containers/Templates/messages.js +0 -28
  129. package/v2Containers/Templates/reducer.js +0 -2
  130. package/v2Containers/Templates/tests/index.test.js +0 -10
  131. package/v2Containers/TemplatesV2/TemplatesV2.style.js +2 -4
  132. package/v2Containers/TemplatesV2/index.js +7 -15
  133. package/v2Containers/TemplatesV2/messages.js +0 -4
  134. package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +0 -34
  135. package/utils/imageUrlUpload.js +0 -141
  136. package/v2Components/CapImageUrlUpload/constants.js +0 -26
  137. package/v2Components/CapImageUrlUpload/index.js +0 -365
  138. package/v2Components/CapImageUrlUpload/index.scss +0 -35
  139. package/v2Components/CapImageUrlUpload/messages.js +0 -47
  140. package/v2Components/ErrorInfoNote/constants.js +0 -1
  141. package/v2Components/HtmlEditor/__tests__/HTMLEditor.apiErrors.test.js +0 -870
  142. package/v2Components/HtmlEditor/components/ValidationPanel/constants.js +0 -6
  143. package/v2Components/HtmlEditor/components/ValidationTabs/_validationTabs.scss +0 -281
  144. package/v2Components/HtmlEditor/components/ValidationTabs/index.js +0 -295
  145. package/v2Components/HtmlEditor/components/ValidationTabs/messages.js +0 -51
  146. package/v2Components/HtmlEditor/utils/validationConstants.js +0 -38
  147. package/v2Components/MobilePushPreviewV2/constants.js +0 -6
  148. package/v2Containers/BeePopupEditor/_beePopupEditor.scss +0 -14
  149. package/v2Containers/BeePopupEditor/constants.js +0 -10
  150. package/v2Containers/BeePopupEditor/index.js +0 -194
  151. package/v2Containers/BeePopupEditor/tests/index.test.js +0 -627
  152. package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +0 -1246
  153. package/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +0 -2472
  154. package/v2Containers/EmailWrapper/components/__tests__/EmailWrapperView.test.js +0 -520
  155. package/v2Containers/EmailWrapper/tests/useEmailWrapper.edgeCases.test.js +0 -956
  156. package/v2Containers/InApp/__tests__/InAppHTMLEditor.test.js +0 -376
  157. package/v2Containers/InApp/__tests__/sagas.test.js +0 -363
  158. package/v2Containers/InApp/tests/selectors.test.js +0 -612
  159. package/v2Containers/InAppWrapper/components/InAppWrapperView.js +0 -151
  160. package/v2Containers/InAppWrapper/components/__tests__/InAppWrapperView.test.js +0 -267
  161. package/v2Containers/InAppWrapper/components/inAppWrapperView.scss +0 -23
  162. package/v2Containers/InAppWrapper/constants.js +0 -16
  163. package/v2Containers/InAppWrapper/hooks/__tests__/useInAppWrapper.test.js +0 -473
  164. package/v2Containers/InAppWrapper/hooks/useInAppWrapper.js +0 -198
  165. package/v2Containers/InAppWrapper/index.js +0 -148
  166. package/v2Containers/InAppWrapper/messages.js +0 -49
  167. package/v2Containers/InappAdvance/index.js +0 -1099
  168. package/v2Containers/InappAdvance/index.scss +0 -10
  169. package/v2Containers/InappAdvance/tests/index.test.js +0 -448
  170. package/v2Containers/WebPush/Create/components/BrandIconSection.js +0 -108
  171. package/v2Containers/WebPush/Create/components/ButtonForm.js +0 -172
  172. package/v2Containers/WebPush/Create/components/ButtonItem.js +0 -101
  173. package/v2Containers/WebPush/Create/components/ButtonList.js +0 -145
  174. package/v2Containers/WebPush/Create/components/ButtonsLinksSection.js +0 -164
  175. package/v2Containers/WebPush/Create/components/ButtonsLinksSection.test.js +0 -463
  176. package/v2Containers/WebPush/Create/components/FormActions.js +0 -54
  177. package/v2Containers/WebPush/Create/components/FormActions.test.js +0 -163
  178. package/v2Containers/WebPush/Create/components/MediaSection.js +0 -142
  179. package/v2Containers/WebPush/Create/components/MediaSection.test.js +0 -341
  180. package/v2Containers/WebPush/Create/components/MessageSection.js +0 -103
  181. package/v2Containers/WebPush/Create/components/MessageSection.test.js +0 -268
  182. package/v2Containers/WebPush/Create/components/NotificationTitleSection.js +0 -87
  183. package/v2Containers/WebPush/Create/components/NotificationTitleSection.test.js +0 -210
  184. package/v2Containers/WebPush/Create/components/TemplateNameSection.js +0 -54
  185. package/v2Containers/WebPush/Create/components/TemplateNameSection.test.js +0 -143
  186. package/v2Containers/WebPush/Create/components/__snapshots__/ButtonsLinksSection.test.js.snap +0 -86
  187. package/v2Containers/WebPush/Create/components/__snapshots__/FormActions.test.js.snap +0 -16
  188. package/v2Containers/WebPush/Create/components/__snapshots__/MediaSection.test.js.snap +0 -41
  189. package/v2Containers/WebPush/Create/components/__snapshots__/MessageSection.test.js.snap +0 -54
  190. package/v2Containers/WebPush/Create/components/__snapshots__/NotificationTitleSection.test.js.snap +0 -37
  191. package/v2Containers/WebPush/Create/components/__snapshots__/TemplateNameSection.test.js.snap +0 -21
  192. package/v2Containers/WebPush/Create/components/_buttons.scss +0 -246
  193. package/v2Containers/WebPush/Create/components/tests/ButtonForm.test.js +0 -554
  194. package/v2Containers/WebPush/Create/components/tests/ButtonItem.test.js +0 -607
  195. package/v2Containers/WebPush/Create/components/tests/ButtonList.test.js +0 -633
  196. package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonForm.test.js.snap +0 -666
  197. package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonItem.test.js.snap +0 -74
  198. package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonList.test.js.snap +0 -78
  199. package/v2Containers/WebPush/Create/hooks/useButtonManagement.js +0 -138
  200. package/v2Containers/WebPush/Create/hooks/useButtonManagement.test.js +0 -406
  201. package/v2Containers/WebPush/Create/hooks/useCharacterCount.js +0 -30
  202. package/v2Containers/WebPush/Create/hooks/useCharacterCount.test.js +0 -151
  203. package/v2Containers/WebPush/Create/hooks/useImageUpload.js +0 -104
  204. package/v2Containers/WebPush/Create/hooks/useImageUpload.test.js +0 -538
  205. package/v2Containers/WebPush/Create/hooks/useTagManagement.js +0 -122
  206. package/v2Containers/WebPush/Create/hooks/useTagManagement.test.js +0 -633
  207. package/v2Containers/WebPush/Create/index.js +0 -1148
  208. package/v2Containers/WebPush/Create/index.scss +0 -134
  209. package/v2Containers/WebPush/Create/messages.js +0 -211
  210. package/v2Containers/WebPush/Create/preview/DevicePreviewContent.js +0 -228
  211. package/v2Containers/WebPush/Create/preview/NotificationContainer.js +0 -294
  212. package/v2Containers/WebPush/Create/preview/PreviewContent.js +0 -90
  213. package/v2Containers/WebPush/Create/preview/PreviewControls.js +0 -305
  214. package/v2Containers/WebPush/Create/preview/PreviewDisclaimer.js +0 -25
  215. package/v2Containers/WebPush/Create/preview/WebPushPreview.js +0 -155
  216. package/v2Containers/WebPush/Create/preview/assets/Light.svg +0 -53
  217. package/v2Containers/WebPush/Create/preview/assets/Top.svg +0 -5
  218. package/v2Containers/WebPush/Create/preview/assets/android-arrow-down.svg +0 -9
  219. package/v2Containers/WebPush/Create/preview/assets/android-arrow-up.svg +0 -9
  220. package/v2Containers/WebPush/Create/preview/assets/chrome-icon.png +0 -0
  221. package/v2Containers/WebPush/Create/preview/assets/edge-icon.png +0 -0
  222. package/v2Containers/WebPush/Create/preview/assets/firefox-icon.svg +0 -106
  223. package/v2Containers/WebPush/Create/preview/assets/iOS.svg +0 -26
  224. package/v2Containers/WebPush/Create/preview/assets/macos-arrow-down-icon.svg +0 -9
  225. package/v2Containers/WebPush/Create/preview/assets/macos-triple-dot-icon.svg +0 -9
  226. package/v2Containers/WebPush/Create/preview/assets/opera-icon.svg +0 -18
  227. package/v2Containers/WebPush/Create/preview/assets/safari-icon.svg +0 -29
  228. package/v2Containers/WebPush/Create/preview/assets/windows-close-icon.svg +0 -9
  229. package/v2Containers/WebPush/Create/preview/assets/windows-triple-dot-icon.svg +0 -9
  230. package/v2Containers/WebPush/Create/preview/components/AndroidMobileChromeHeader.js +0 -51
  231. package/v2Containers/WebPush/Create/preview/components/AndroidMobileExpanded.js +0 -145
  232. package/v2Containers/WebPush/Create/preview/components/IOSHeader.js +0 -45
  233. package/v2Containers/WebPush/Create/preview/components/NotificationExpandedContent.js +0 -68
  234. package/v2Containers/WebPush/Create/preview/components/NotificationHeader.js +0 -61
  235. package/v2Containers/WebPush/Create/preview/components/WindowsChromeExpanded.js +0 -99
  236. package/v2Containers/WebPush/Create/preview/components/tests/AndroidMobileExpanded.test.js +0 -733
  237. package/v2Containers/WebPush/Create/preview/components/tests/WindowsChromeExpanded.test.js +0 -571
  238. package/v2Containers/WebPush/Create/preview/components/tests/__snapshots__/AndroidMobileExpanded.test.js.snap +0 -85
  239. package/v2Containers/WebPush/Create/preview/components/tests/__snapshots__/WindowsChromeExpanded.test.js.snap +0 -81
  240. package/v2Containers/WebPush/Create/preview/config/notificationMappings.js +0 -50
  241. package/v2Containers/WebPush/Create/preview/constants.js +0 -637
  242. package/v2Containers/WebPush/Create/preview/notification-container.scss +0 -79
  243. package/v2Containers/WebPush/Create/preview/preview.scss +0 -358
  244. package/v2Containers/WebPush/Create/preview/styles/_android-mobile-chrome.scss +0 -370
  245. package/v2Containers/WebPush/Create/preview/styles/_android-mobile-edge.scss +0 -12
  246. package/v2Containers/WebPush/Create/preview/styles/_android-mobile-firefox.scss +0 -12
  247. package/v2Containers/WebPush/Create/preview/styles/_android-mobile-opera.scss +0 -12
  248. package/v2Containers/WebPush/Create/preview/styles/_android-tablet-chrome.scss +0 -47
  249. package/v2Containers/WebPush/Create/preview/styles/_android-tablet-edge.scss +0 -11
  250. package/v2Containers/WebPush/Create/preview/styles/_android-tablet-firefox.scss +0 -11
  251. package/v2Containers/WebPush/Create/preview/styles/_android-tablet-opera.scss +0 -11
  252. package/v2Containers/WebPush/Create/preview/styles/_base.scss +0 -207
  253. package/v2Containers/WebPush/Create/preview/styles/_ios.scss +0 -153
  254. package/v2Containers/WebPush/Create/preview/styles/_ipados.scss +0 -107
  255. package/v2Containers/WebPush/Create/preview/styles/_macos-chrome.scss +0 -101
  256. package/v2Containers/WebPush/Create/preview/styles/_windows-chrome.scss +0 -229
  257. package/v2Containers/WebPush/Create/preview/tests/DevicePreviewContent.test.js +0 -909
  258. package/v2Containers/WebPush/Create/preview/tests/NotificationContainer.test.js +0 -1081
  259. package/v2Containers/WebPush/Create/preview/tests/PreviewControls.test.js +0 -723
  260. package/v2Containers/WebPush/Create/preview/tests/WebPushPreview.test.js +0 -1327
  261. package/v2Containers/WebPush/Create/preview/tests/__snapshots__/DevicePreviewContent.test.js.snap +0 -131
  262. package/v2Containers/WebPush/Create/preview/tests/__snapshots__/NotificationContainer.test.js.snap +0 -112
  263. package/v2Containers/WebPush/Create/preview/tests/__snapshots__/PreviewControls.test.js.snap +0 -144
  264. package/v2Containers/WebPush/Create/preview/tests/__snapshots__/WebPushPreview.test.js.snap +0 -129
  265. package/v2Containers/WebPush/Create/utils/payloadBuilder.js +0 -96
  266. package/v2Containers/WebPush/Create/utils/payloadBuilder.test.js +0 -396
  267. package/v2Containers/WebPush/Create/utils/previewUtils.js +0 -89
  268. package/v2Containers/WebPush/Create/utils/urlValidation.js +0 -115
  269. package/v2Containers/WebPush/Create/utils/urlValidation.test.js +0 -449
  270. package/v2Containers/WebPush/Create/utils/validation.js +0 -75
  271. package/v2Containers/WebPush/Create/utils/validation.test.js +0 -283
  272. package/v2Containers/WebPush/actions.js +0 -60
  273. package/v2Containers/WebPush/constants.js +0 -132
  274. package/v2Containers/WebPush/index.js +0 -2
  275. package/v2Containers/WebPush/reducer.js +0 -104
  276. package/v2Containers/WebPush/sagas.js +0 -119
  277. package/v2Containers/WebPush/selectors.js +0 -65
  278. package/v2Containers/WebPush/tests/reducer.test.js +0 -863
  279. package/v2Containers/WebPush/tests/sagas.test.js +0 -566
  280. package/v2Containers/WebPush/tests/selectors.test.js +0 -960
@@ -24,7 +24,7 @@ const defaultMessageFormatter = (messageKey, values = {}) => {
24
24
  'sanitizer.productionValidHtml': 'Provide valid HTML content before deploying to production',
25
25
  'sanitizer.productionSanitized': 'Content has been sanitized for security - review changes before deploying',
26
26
  'sanitizer.productionInlineCss': 'Consider inlining CSS for better email client compatibility',
27
- 'sanitizer.productionLargeContent': `Content is large (${values.size || 'unknown'} characters) - consider optimizing for mobile performance`,
27
+ 'sanitizer.productionLargeContent': `Content is large (${values.size || 'unknown'} characters) - consider optimizing for mobile performance`
28
28
  };
29
29
 
30
30
  return fallbackMessages[messageKey] || messageKey;
@@ -33,17 +33,17 @@ const defaultMessageFormatter = (messageKey, values = {}) => {
33
33
  // Constants for better maintainability
34
34
  const SANITIZER_VARIANTS = {
35
35
  EMAIL: 'email',
36
- INAPP: 'inapp',
36
+ INAPP: 'inapp'
37
37
  };
38
38
 
39
39
  const SECURITY_LEVELS = {
40
40
  STANDARD: 'standard',
41
- STRICT: 'strict',
41
+ STRICT: 'strict'
42
42
  };
43
43
 
44
44
  const CONTENT_LIMITS = {
45
45
  LARGE_CONTENT_SIZE: 50000,
46
- MIN_CONTENT_LENGTH: 0,
46
+ MIN_CONTENT_LENGTH: 0
47
47
  };
48
48
 
49
49
  const DANGEROUS_PROTOCOLS = ['javascript:', 'data:', 'vbscript:'];
@@ -51,7 +51,7 @@ const DANGEROUS_PROTOCOLS = ['javascript:', 'data:', 'vbscript:'];
51
51
  const EVENT_HANDLERS = [
52
52
  'onclick', 'onload', 'onerror', 'onmouseover', 'onmouseout',
53
53
  'onmousedown', 'onmouseup', 'onkeydown', 'onkeyup', 'onkeypress',
54
- 'onfocus', 'onblur', 'onchange', 'onsubmit', 'onreset',
54
+ 'onfocus', 'onblur', 'onchange', 'onsubmit', 'onreset'
55
55
  ];
56
56
 
57
57
  // Email-specific sanitization config
@@ -62,18 +62,18 @@ const EMAIL_CONFIG = {
62
62
  'a', 'img', 'table', 'tr', 'td', 'th', 'thead', 'tbody', 'tfoot',
63
63
  'ul', 'ol', 'li', 'strong', 'b', 'em', 'i', 'u', 'center',
64
64
  'font', 'small', 'big', 'sup', 'sub', 'pre', 'code',
65
- 'blockquote', 'cite', 'abbr', 'acronym', 'address',
65
+ 'blockquote', 'cite', 'abbr', 'acronym', 'address'
66
66
  ],
67
67
  ALLOWED_ATTR: [
68
68
  'src', 'alt', 'title', 'href', 'target', 'rel',
69
69
  'width', 'height', 'style', 'class', 'id',
70
70
  'align', 'valign', 'bgcolor', 'color', 'border',
71
71
  'cellpadding', 'cellspacing', 'colspan', 'rowspan',
72
- 'type', 'charset', 'content', 'name', 'http-equiv',
72
+ 'type', 'charset', 'content', 'name', 'http-equiv'
73
73
  ],
74
74
  FORBID_TAGS: ['script', 'iframe', 'object', 'embed', 'applet', 'form', 'input'],
75
75
  FORBID_ATTR: ['onclick', 'onload', 'onerror', 'onmouseover'],
76
- ALLOW_DATA_ATTR: false,
76
+ ALLOW_DATA_ATTR: false
77
77
  };
78
78
 
79
79
  // InApp-specific sanitization config
@@ -83,29 +83,29 @@ const INAPP_CONFIG = {
83
83
  'div', 'span', 'p', 'br', 'hr', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
84
84
  'a', 'img', 'button', 'ul', 'ol', 'li', 'strong', 'b', 'em', 'i', 'u',
85
85
  'small', 'big', 'sup', 'sub', 'pre', 'code', 'blockquote', 'cite',
86
- 'video', 'audio', 'source', 'canvas', // Mobile-friendly multimedia
86
+ 'video', 'audio', 'source', 'canvas' // Mobile-friendly multimedia
87
87
  ],
88
88
  ALLOWED_ATTR: [
89
89
  'src', 'alt', 'title', 'href', 'target', 'rel',
90
90
  'width', 'height', 'style', 'class', 'id',
91
91
  'type', 'controls', 'autoplay', 'loop', 'muted',
92
- 'poster', 'preload',
92
+ 'poster', 'preload'
93
93
  ],
94
94
  FORBID_TAGS: ['script', 'iframe', 'object', 'embed', 'applet', 'form', 'input'],
95
95
  FORBID_ATTR: ['onclick', 'onload', 'onerror', 'onmouseover'],
96
- ALLOW_DATA_ATTR: true,
96
+ ALLOW_DATA_ATTR: true
97
97
  };
98
98
 
99
99
  // Strict sanitization config for production
100
100
  const STRICT_CONFIG = {
101
101
  ALLOWED_TAGS: [
102
102
  'div', 'span', 'p', 'br', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
103
- 'a', 'img', 'strong', 'b', 'em', 'i', 'u', 'ul', 'ol', 'li',
103
+ 'a', 'img', 'strong', 'b', 'em', 'i', 'u', 'ul', 'ol', 'li'
104
104
  ],
105
105
  ALLOWED_ATTR: ['src', 'alt', 'title', 'href', 'style', 'class'],
106
106
  FORBID_TAGS: ['script', 'iframe', 'object', 'embed', 'applet', 'form', 'input', 'style'],
107
107
  FORBID_ATTR: ['onclick', 'onload', 'onerror', 'onmouseover'],
108
- ALLOW_DATA_ATTR: false,
108
+ ALLOW_DATA_ATTR: false
109
109
  };
110
110
 
111
111
  /**
@@ -126,9 +126,8 @@ export const sanitizeHTML = (html, variant = SANITIZER_VARIANTS.EMAIL, level = S
126
126
  warnings: html === null || html === undefined ? [] : [{
127
127
  type: 'warning',
128
128
  message: formatMessage('sanitizer.invalidInput'),
129
- source: 'sanitizer',
130
- rule: 'sanitizer.invalidInput', // Rule Group #1 – blocking error for UI gating
131
- }],
129
+ source: 'sanitizer'
130
+ }]
132
131
  };
133
132
  }
134
133
 
@@ -138,7 +137,7 @@ export const sanitizeHTML = (html, variant = SANITIZER_VARIANTS.EMAIL, level = S
138
137
  sanitized: '',
139
138
  isClean: true,
140
139
  removedElements: [],
141
- warnings: [],
140
+ warnings: []
142
141
  };
143
142
  }
144
143
 
@@ -160,7 +159,7 @@ export const sanitizeHTML = (html, variant = SANITIZER_VARIANTS.EMAIL, level = S
160
159
  sanitized: '',
161
160
  isClean: true,
162
161
  removedElements: [],
163
- warnings: [],
162
+ warnings: []
164
163
  };
165
164
 
166
165
  try {
@@ -189,8 +188,8 @@ export const sanitizeHTML = (html, variant = SANITIZER_VARIANTS.EMAIL, level = S
189
188
  CUSTOM_ELEMENT_HANDLING: {
190
189
  tagNameCheck: null,
191
190
  attributeNameCheck: null,
192
- allowCustomizedBuiltInElements: false,
193
- },
191
+ allowCustomizedBuiltInElements: false
192
+ }
194
193
  };
195
194
 
196
195
  // Sanitize the content directly
@@ -203,12 +202,12 @@ export const sanitizeHTML = (html, variant = SANITIZER_VARIANTS.EMAIL, level = S
203
202
 
204
203
  // Add variant-specific warnings (check original HTML before sanitization)
205
204
  addVariantWarnings(html, variant, result, formatMessage);
205
+
206
206
  } catch (error) {
207
207
  result.warnings.push({
208
208
  type: 'error',
209
209
  message: formatMessage('sanitizer.sanitizationFailed', { error: error.message }),
210
- source: 'sanitizer',
211
- rule: 'sanitizer.sanitizationFailed', // Rule Group #1 – blocking error for UI gating
210
+ source: 'sanitizer'
212
211
  });
213
212
  result.sanitized = ''; // Return empty content if sanitization fails
214
213
  result.isClean = false;
@@ -230,30 +229,30 @@ const addVariantWarnings = (html, variant, result, formatMessage = defaultMessag
230
229
  if (variant === SANITIZER_VARIANTS.EMAIL) {
231
230
  // Check for potentially problematic email elements
232
231
  const emailProblematicElements = ['<video', '<audio', '<canvas'];
233
- if (emailProblematicElements.some((element) => html.includes(element))) {
232
+ if (emailProblematicElements.some(element => html.includes(element))) {
234
233
  result.warnings.push({
235
234
  type: 'warning',
236
235
  message: formatMessage('sanitizer.emailMultimediaNotSupported'),
237
- source: 'email-compatibility',
236
+ source: 'email-compatibility'
238
237
  });
239
238
  }
240
239
 
241
240
  const problematicStyles = ['position: fixed', 'position: sticky', 'position:fixed', 'position:sticky'];
242
- if (problematicStyles.some((style) => html.includes(style))) {
241
+ if (problematicStyles.some(style => html.includes(style))) {
243
242
  result.warnings.push({
244
243
  type: 'warning',
245
244
  message: formatMessage('sanitizer.emailPositioningNotSupported'),
246
- source: 'email-compatibility',
245
+ source: 'email-compatibility'
247
246
  });
248
247
  }
249
248
 
250
249
  // Check for CSS Grid/Flexbox which may have limited email support
251
250
  const modernCssFeatures = ['display: grid', 'display: flex', 'display:grid', 'display:flex'];
252
- if (modernCssFeatures.some((feature) => html.includes(feature))) {
251
+ if (modernCssFeatures.some(feature => html.includes(feature))) {
253
252
  result.warnings.push({
254
253
  type: 'info',
255
254
  message: formatMessage('sanitizer.emailModernCssLimited'),
256
- source: 'email-compatibility',
255
+ source: 'email-compatibility'
257
256
  });
258
257
  }
259
258
  } else if (variant === SANITIZER_VARIANTS.INAPP) {
@@ -262,7 +261,7 @@ const addVariantWarnings = (html, variant, result, formatMessage = defaultMessag
262
261
  result.warnings.push({
263
262
  type: 'info',
264
263
  message: formatMessage('sanitizer.mobileTablesNotFriendly'),
265
- source: 'mobile-optimization',
264
+ source: 'mobile-optimization'
266
265
  });
267
266
  }
268
267
 
@@ -271,7 +270,7 @@ const addVariantWarnings = (html, variant, result, formatMessage = defaultMessag
271
270
  result.warnings.push({
272
271
  type: 'info',
273
272
  message: formatMessage('sanitizer.mobileRelativeFontSizes'),
274
- source: 'mobile-optimization',
273
+ source: 'mobile-optimization'
275
274
  });
276
275
  }
277
276
 
@@ -280,7 +279,7 @@ const addVariantWarnings = (html, variant, result, formatMessage = defaultMessag
280
279
  result.warnings.push({
281
280
  type: 'info',
282
281
  message: formatMessage('sanitizer.mobileFixedWidthsProblematic'),
283
- source: 'mobile-optimization',
282
+ source: 'mobile-optimization'
284
283
  });
285
284
  }
286
285
  }
@@ -303,9 +302,9 @@ export const prepareForProduction = (html, variant = SANITIZER_VARIANTS.EMAIL, f
303
302
  warnings: [{
304
303
  type: 'error',
305
304
  message: formatMessage('sanitizer.invalidInputNonEmpty'),
306
- source: 'production-validator',
305
+ source: 'production-validator'
307
306
  }],
308
- recommendations: [formatMessage('sanitizer.productionValidHtml')],
307
+ recommendations: [formatMessage('sanitizer.productionValidHtml')]
309
308
  };
310
309
  }
311
310
 
@@ -317,7 +316,7 @@ export const prepareForProduction = (html, variant = SANITIZER_VARIANTS.EMAIL, f
317
316
  isProductionReady: sanitizeResult.isClean,
318
317
  securityIssues: sanitizeResult.removedElements,
319
318
  warnings: sanitizeResult.warnings,
320
- recommendations: [],
319
+ recommendations: []
321
320
  };
322
321
 
323
322
  // Add production readiness recommendations
@@ -356,7 +355,9 @@ export const isContentSafe = (html) => {
356
355
  if (!html || typeof html !== 'string') return true;
357
356
 
358
357
  // Create dynamic patterns from constants
359
- const protocolPatterns = DANGEROUS_PROTOCOLS.map((protocol) => new RegExp(protocol.replace(':', '\\:'), 'gi'));
358
+ const protocolPatterns = DANGEROUS_PROTOCOLS.map(protocol =>
359
+ new RegExp(protocol.replace(':', '\\:'), 'gi')
360
+ );
360
361
 
361
362
  const eventHandlerPattern = new RegExp(EVENT_HANDLERS.join('|'), 'gi');
362
363
 
@@ -368,10 +369,10 @@ export const isContentSafe = (html) => {
368
369
  /<object/gi,
369
370
  /<embed/gi,
370
371
  /<applet/gi,
371
- /<form/gi,
372
+ /<form/gi
372
373
  ];
373
374
 
374
- return !dangerousPatterns.some((pattern) => pattern.test(html));
375
+ return !dangerousPatterns.some(pattern => pattern.test(html));
375
376
  };
376
377
 
377
378
  /**
@@ -394,7 +395,7 @@ export const findUnsafeContent = (html) => {
394
395
  'Iframe': /<iframe[^>]*>/gi,
395
396
  'Object/Embed': /<(object|embed)[^>]*>/gi,
396
397
  'Applet': /<applet[^>]*>/gi,
397
- 'Form': /<form[^>]*>/gi,
398
+ 'Form': /<form[^>]*>/gi
398
399
  };
399
400
 
400
401
  Object.entries(patterns).forEach(([name, pattern]) => {
@@ -405,7 +406,7 @@ export const findUnsafeContent = (html) => {
405
406
  type: name,
406
407
  content: match[0],
407
408
  position: match.index,
408
- length: match[0].length,
409
+ length: match[0].length
409
410
  });
410
411
 
411
412
  // Prevent infinite loop for global patterns
@@ -428,5 +429,5 @@ export default {
428
429
  // Include constants in default export for convenience
429
430
  VARIANTS: SANITIZER_VARIANTS,
430
431
  SECURITY_LEVELS,
431
- CONTENT_LIMITS,
432
+ CONTENT_LIMITS
432
433
  };
@@ -20,7 +20,7 @@ const defaultMessageFormatter = (messageKey, values = {}) => {
20
20
  'validator.largeImageDetected': 'Large image dimensions detected - consider mobile optimization',
21
21
  'validator.unclosedCssRule': 'Unclosed CSS rule detected',
22
22
  'validator.emptyCssRule': 'Empty CSS rule detected',
23
- 'validator.cssValidationFailed': `CSS validation failed: ${values.error || 'Unknown error'}`,
23
+ 'validator.cssValidationFailed': `CSS validation failed: ${values.error || 'Unknown error'}`
24
24
  };
25
25
 
26
26
  return fallbackMessages[messageKey] || messageKey;
@@ -49,7 +49,7 @@ const HTML_RULES = {
49
49
  'space-tab-mixed-disabled': 'space',
50
50
  'id-class-ad-disabled': false,
51
51
  'href-abs-or-rel': false,
52
- 'attr-unsafe-chars': true,
52
+ 'attr-unsafe-chars': true
53
53
  };
54
54
 
55
55
  // Additional custom validation rules
@@ -66,7 +66,7 @@ const CUSTOM_VALIDATIONS = {
66
66
 
67
67
  // InApp-specific validations
68
68
  MOBILE_INCOMPATIBLE: /<(object|embed|applet)\b/gi,
69
- LARGE_IMAGES: /width\s*:\s*[5-9]\d{2,}px|height\s*:\s*[5-9]\d{2,}px/gi,
69
+ LARGE_IMAGES: /width\s*:\s*[5-9]\d{2,}px|height\s*:\s*[5-9]\d{2,}px/gi
70
70
  };
71
71
 
72
72
  /**
@@ -82,7 +82,7 @@ export const validateHTML = (html, variant = 'email', formatMessage = defaultMes
82
82
  isValid: true,
83
83
  errors: [],
84
84
  warnings: [],
85
- info: [],
85
+ info: []
86
86
  };
87
87
  }
88
88
 
@@ -90,7 +90,7 @@ export const validateHTML = (html, variant = 'email', formatMessage = defaultMes
90
90
  isValid: true,
91
91
  errors: [],
92
92
  warnings: [],
93
- info: [],
93
+ info: []
94
94
  };
95
95
 
96
96
  try {
@@ -98,7 +98,7 @@ export const validateHTML = (html, variant = 'email', formatMessage = defaultMes
98
98
  const htmlHintResults = HTMLHint.verify(html, HTML_RULES);
99
99
 
100
100
  // Process HTMLHint results
101
- htmlHintResults.forEach((issue) => {
101
+ htmlHintResults.forEach(issue => {
102
102
  const error = {
103
103
  type: issue.type,
104
104
  message: issue.message,
@@ -106,64 +106,66 @@ export const validateHTML = (html, variant = 'email', formatMessage = defaultMes
106
106
  column: issue.col,
107
107
  rule: issue.rule.id,
108
108
  severity: getSeverityLevel(issue.type, issue.rule.id),
109
- source: 'htmlhint',
109
+ source: 'htmlhint'
110
110
  };
111
111
 
112
- if (error.severity === 'warning') {
112
+ if (error.severity === 'error') {
113
+ results.errors.push(error);
114
+ results.isValid = false;
115
+ } else if (error.severity === 'warning') {
113
116
  results.warnings.push(error);
114
- } else if (error.severity === 'info') {
115
- results.info.push(error);
116
117
  } else {
117
- results.warnings.push(error);
118
+ results.info.push(error);
118
119
  }
119
120
  });
121
+
122
+ // Run custom validations
123
+ runCustomValidations(html, variant, results, formatMessage);
124
+
125
+ // Run Liquid template validation
126
+ runLiquidValidation(html, variant, results, formatMessage);
127
+
120
128
  } catch (error) {
121
- // HTMLHint failed, but we still want to run custom validations and Liquid validation
122
- results.warnings.push({
123
- type: 'warning',
129
+ results.errors.push({
130
+ type: 'error',
124
131
  message: formatMessage('validator.validationFailed', { error: error.message }),
125
132
  line: 1,
126
133
  column: 1,
127
134
  rule: 'validation-error',
128
- severity: 'warning',
129
- source: 'validator',
135
+ severity: 'error',
136
+ source: 'validator'
130
137
  });
138
+ results.isValid = false;
131
139
  }
132
140
 
133
- // Always run custom validations and Liquid validation, even if HTMLHint failed
134
- // This ensures unsafe protocol detection and other critical validations still run
135
- runCustomValidations(html, variant, results, formatMessage);
136
- runLiquidValidation(html, variant, results, formatMessage);
137
-
138
141
  return results;
139
142
  };
140
143
 
141
144
  /**
142
- * Determines severity level based on error type and rule.
143
- * ONLY Rule Group #1 (Input & Sanitization) is blocking; that is handled in
144
- * contentSanitizer/useValidation. All HTML/CSS/Liquid/security rules here are
145
- * WARNING only for backward compatibility with CKEditor legacy templates.
145
+ * Determines severity level based on error type and rule
146
146
  */
147
147
  const getSeverityLevel = (type, ruleId) => {
148
- const warningRules = [
148
+ const errorRules = [
149
149
  'tag-pair',
150
150
  'attr-no-duplication',
151
151
  'id-unique',
152
- 'spec-char-escape',
152
+ 'spec-char-escape'
153
+ ];
154
+
155
+ const warningRules = [
153
156
  'tagname-lowercase',
154
157
  'attr-lowercase',
155
158
  'attr-value-double-quotes',
156
- 'alt-require',
159
+ 'alt-require'
157
160
  ];
158
161
 
159
- if (warningRules.includes(ruleId)) {
160
- return 'warning';
161
- }
162
- // Downgrade HTMLHint "error" type to warning (Rule Group #1 is sanitizer-only)
163
- if (type === 'error') {
162
+ if (type === 'error' || errorRules.includes(ruleId)) {
163
+ return 'error';
164
+ } else if (warningRules.includes(ruleId)) {
164
165
  return 'warning';
166
+ } else {
167
+ return 'info';
165
168
  }
166
- return 'info';
167
169
  };
168
170
 
169
171
  /**
@@ -175,7 +177,6 @@ const getSeverityLevel = (type, ruleId) => {
175
177
  */
176
178
  const runCustomValidations = (html, variant, results, formatMessage = defaultMessageFormatter) => {
177
179
  // Check for unsafe protocols using RegExp.exec loop
178
- // These are BLOCKING ERRORS (Rule Group #1: sanitizer.dangerousProtocolDetected)
179
180
  const unsafeProtocolsRegex = new RegExp(CUSTOM_VALIDATIONS.UNSAFE_PROTOCOLS.source, CUSTOM_VALIDATIONS.UNSAFE_PROTOCOLS.flags);
180
181
  unsafeProtocolsRegex.lastIndex = 0; // Reset lastIndex before running
181
182
  let match;
@@ -185,9 +186,9 @@ const runCustomValidations = (html, variant, results, formatMessage = defaultMes
185
186
  message: formatMessage('validator.unsafeProtocolDetected', { protocol: match[0] }),
186
187
  line: getLineNumber(html, match.index),
187
188
  column: 1,
188
- rule: 'sanitizer.dangerousProtocolDetected',
189
+ rule: 'unsafe-protocol',
189
190
  severity: 'error',
190
- source: 'custom',
191
+ source: 'custom'
191
192
  });
192
193
  results.isValid = false;
193
194
 
@@ -208,7 +209,7 @@ const runCustomValidations = (html, variant, results, formatMessage = defaultMes
208
209
  column: 1,
209
210
  rule: 'script-tag-warning',
210
211
  severity: 'warning',
211
- source: 'custom',
212
+ source: 'custom'
212
213
  });
213
214
 
214
215
  // Guard against zero-length matches to avoid infinite loops
@@ -244,7 +245,7 @@ const validateEmailSpecific = (html, results, formatMessage = defaultMessageForm
244
245
  column: 1,
245
246
  rule: 'outlook-compatibility',
246
247
  severity: 'warning',
247
- source: 'email-specific',
248
+ source: 'email-specific'
248
249
  });
249
250
 
250
251
  // Guard against zero-length matches to avoid infinite loops
@@ -264,7 +265,7 @@ const validateEmailSpecific = (html, results, formatMessage = defaultMessageForm
264
265
  column: 1,
265
266
  rule: 'email-css-compatibility',
266
267
  severity: 'warning',
267
- source: 'email-specific',
268
+ source: 'email-specific'
268
269
  });
269
270
 
270
271
  // Guard against zero-length matches to avoid infinite loops
@@ -293,7 +294,7 @@ const validateInAppSpecific = (html, results, formatMessage = defaultMessageForm
293
294
  column: 1,
294
295
  rule: 'mobile-compatibility',
295
296
  severity: 'warning',
296
- source: 'inapp-specific',
297
+ source: 'inapp-specific'
297
298
  });
298
299
 
299
300
  // Guard against zero-length matches to avoid infinite loops
@@ -313,7 +314,7 @@ const validateInAppSpecific = (html, results, formatMessage = defaultMessageForm
313
314
  column: 1,
314
315
  rule: 'mobile-image-size',
315
316
  severity: 'info',
316
- source: 'inapp-specific',
317
+ source: 'inapp-specific'
317
318
  });
318
319
 
319
320
  // Guard against zero-length matches to avoid infinite loops
@@ -335,9 +336,8 @@ const runLiquidValidation = (html, variant, results, formatMessage = defaultMess
335
336
  const liquidResults = validateLiquidHTML(html, variant);
336
337
 
337
338
  // Merge Liquid validation results
338
- // Client-side Liquid validation errors are blocking (genuine syntax errors)
339
339
  if (liquidResults.errors) {
340
- results.errors.push(...liquidResults.errors.map((e) => ({ ...e, severity: 'error' })));
340
+ results.errors.push(...liquidResults.errors);
341
341
  if (liquidResults.errors.length > 0) {
342
342
  results.isValid = false;
343
343
  }
@@ -375,7 +375,7 @@ export const validateCSS = (css, formatMessage = defaultMessageFormatter) => {
375
375
  isValid: true,
376
376
  errors: [],
377
377
  warnings: [],
378
- info: [],
378
+ info: []
379
379
  };
380
380
 
381
381
  if (!css || typeof css !== 'string') {
@@ -388,7 +388,7 @@ export const validateCSS = (css, formatMessage = defaultMessageFormatter) => {
388
388
  unclosedBraces: /\{[^{}]*$/gm,
389
389
  invalidProperty: /[^;{}]+:\s*[^;{}]*[^;}]/g,
390
390
  missingColon: /[^;{}]+\s+[^;{}:]+;/g,
391
- emptyRule: /[^{}]+\{\s*\}/g,
391
+ emptyRule: /[^{}]+\{\s*\}/g
392
392
  };
393
393
 
394
394
  // Check for unclosed braces using RegExp.exec loop
@@ -396,15 +396,16 @@ export const validateCSS = (css, formatMessage = defaultMessageFormatter) => {
396
396
  unclosedBracesRegex.lastIndex = 0; // Reset lastIndex before running
397
397
  let match;
398
398
  while ((match = unclosedBracesRegex.exec(css)) !== null) {
399
- results.warnings.push({
400
- type: 'warning',
399
+ results.errors.push({
400
+ type: 'error',
401
401
  message: formatMessage('validator.unclosedCssRule'),
402
402
  line: getLineNumber(css, match.index),
403
403
  column: 1,
404
404
  rule: 'unclosed-brace',
405
- severity: 'warning',
406
- source: 'css-validator',
405
+ severity: 'error',
406
+ source: 'css-validator'
407
407
  });
408
+ results.isValid = false;
408
409
 
409
410
  // Guard against zero-length matches to avoid infinite loops
410
411
  if (match[0].length === 0) {
@@ -416,31 +417,34 @@ export const validateCSS = (css, formatMessage = defaultMessageFormatter) => {
416
417
  const emptyRulesRegex = new RegExp(validationPatterns.emptyRule.source, validationPatterns.emptyRule.flags);
417
418
  emptyRulesRegex.lastIndex = 0; // Reset lastIndex before running
418
419
  while ((match = emptyRulesRegex.exec(css)) !== null) {
419
- results.warnings.push({
420
- type: 'warning',
420
+ results.errors.push({
421
+ type: 'error',
421
422
  message: formatMessage('validator.emptyCssRule'),
422
423
  line: getLineNumber(css, match.index),
423
424
  column: 1,
424
425
  rule: 'empty-rule',
425
- severity: 'warning',
426
- source: 'css-validator',
426
+ severity: 'error',
427
+ source: 'css-validator'
427
428
  });
429
+ results.isValid = false;
428
430
 
429
431
  // Guard against zero-length matches to avoid infinite loops
430
432
  if (match[0].length === 0) {
431
433
  emptyRulesRegex.lastIndex++;
432
434
  }
433
435
  }
436
+
434
437
  } catch (error) {
435
- results.warnings.push({
436
- type: 'warning',
438
+ results.errors.push({
439
+ type: 'error',
437
440
  message: formatMessage('validator.cssValidationFailed', { error: error.message }),
438
441
  line: 1,
439
442
  column: 1,
440
443
  rule: 'css-validation-error',
441
- severity: 'warning',
442
- source: 'css-validator',
444
+ severity: 'error',
445
+ source: 'css-validator'
443
446
  });
447
+ results.isValid = false;
444
448
  }
445
449
 
446
450
  return results;
@@ -453,20 +457,16 @@ export const validateCSS = (css, formatMessage = defaultMessageFormatter) => {
453
457
  * @returns {Object} Combined validation results from all CSS blocks
454
458
  */
455
459
  export const extractAndValidateCSS = (html, formatMessage = defaultMessageFormatter) => {
456
- if (!html) {
457
- return {
458
- isValid: true, errors: [], warnings: [], info: [],
459
- };
460
- }
460
+ if (!html) return { isValid: true, errors: [], warnings: [], info: [] };
461
461
 
462
462
  // Extract CSS from style tags
463
463
  const styleTagPattern = /<style[^>]*>([\s\S]*?)<\/style>/gi;
464
464
  let match;
465
- const allResults = {
465
+ let allResults = {
466
466
  isValid: true,
467
467
  errors: [],
468
468
  warnings: [],
469
- info: [],
469
+ info: []
470
470
  };
471
471
 
472
472
  while ((match = styleTagPattern.exec(html)) !== null) {
@@ -483,18 +483,19 @@ export const extractAndValidateCSS = (html, formatMessage = defaultMessageFormat
483
483
  }
484
484
  }
485
485
 
486
- // Check for unclosed style tags (warning only for CKEditor legacy compatibility)
486
+ // Check for unclosed style tags
487
487
  const unclosedStylePattern = /<style[^>]*>(?![\s\S]*?<\/style>)/gi;
488
488
  if (unclosedStylePattern.test(html)) {
489
- allResults.warnings.push({
490
- type: 'warning',
489
+ allResults.errors.push({
490
+ type: 'error',
491
491
  message: formatMessage('validator.unclosedCssRule'),
492
492
  line: 1,
493
493
  column: 1,
494
494
  rule: 'unclosed-style-tag',
495
- severity: 'warning',
496
- source: 'css-validator',
495
+ severity: 'error',
496
+ source: 'css-validator'
497
497
  });
498
+ allResults.isValid = false;
498
499
  }
499
500
 
500
501
  return allResults;
@@ -503,5 +504,5 @@ export const extractAndValidateCSS = (html, formatMessage = defaultMessageFormat
503
504
  export default {
504
505
  validateHTML,
505
506
  validateCSS,
506
- extractAndValidateCSS,
507
+ extractAndValidateCSS
507
508
  };