@capillarytech/creatives-library 8.0.250-alpha.2 → 8.0.251
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/Android.png +0 -0
- package/assets/iOS.png +0 -0
- package/constants/unified.js +1 -3
- package/initialReducer.js +0 -2
- package/package.json +1 -1
- package/services/api.js +0 -15
- package/services/tests/api.test.js +0 -34
- package/translations/en.json +3 -4
- package/utils/common.js +0 -11
- package/utils/commonUtils.js +5 -28
- package/utils/tests/commonUtil.test.js +0 -224
- package/utils/tests/transformerUtils.test.js +0 -297
- package/utils/transformTemplateConfig.js +10 -0
- package/utils/transformerUtils.js +0 -40
- package/v2Components/CapDeviceContent/index.js +56 -61
- package/v2Components/CapImageUpload/constants.js +0 -2
- package/v2Components/CapImageUpload/index.js +16 -65
- package/v2Components/CapImageUpload/index.scss +1 -4
- package/v2Components/CapImageUpload/messages.js +1 -5
- package/v2Components/CapTagList/index.js +1 -6
- package/v2Components/CapTagListWithInput/index.js +1 -5
- package/v2Components/CapTagListWithInput/messages.js +1 -1
- package/v2Components/CapWhatsappCTA/tests/index.test.js +0 -5
- package/v2Components/ErrorInfoNote/index.js +72 -455
- package/v2Components/ErrorInfoNote/messages.js +6 -36
- package/v2Components/ErrorInfoNote/style.scss +4 -280
- package/v2Components/FormBuilder/tests/index.test.js +4 -13
- package/v2Components/HtmlEditor/HTMLEditor.js +94 -547
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +133 -1358
- package/v2Components/HtmlEditor/__tests__/index.lazy.test.js +16 -27
- package/v2Components/HtmlEditor/_htmlEditor.scss +45 -108
- package/v2Components/HtmlEditor/_index.lazy.scss +1 -1
- package/v2Components/HtmlEditor/components/CodeEditorPane/_codeEditorPane.scss +101 -22
- package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +140 -146
- package/v2Components/HtmlEditor/components/DeviceToggle/_deviceToggle.scss +1 -2
- package/v2Components/HtmlEditor/components/DeviceToggle/index.js +3 -3
- package/v2Components/HtmlEditor/components/EditorToolbar/_editorToolbar.scss +0 -9
- package/v2Components/HtmlEditor/components/EditorToolbar/index.js +1 -1
- package/v2Components/HtmlEditor/components/FullscreenModal/_fullscreenModal.scss +0 -22
- package/v2Components/HtmlEditor/components/InAppPreviewPane/DeviceFrame.js +7 -4
- package/v2Components/HtmlEditor/components/InAppPreviewPane/__tests__/DeviceFrame.test.js +45 -35
- package/v2Components/HtmlEditor/components/InAppPreviewPane/_inAppPreviewPane.scss +3 -1
- package/v2Components/HtmlEditor/components/InAppPreviewPane/constants.js +33 -33
- package/v2Components/HtmlEditor/components/InAppPreviewPane/index.js +6 -7
- package/v2Components/HtmlEditor/components/PreviewPane/_previewPane.scss +6 -3
- package/v2Components/HtmlEditor/components/PreviewPane/index.js +34 -24
- package/v2Components/HtmlEditor/components/SplitContainer/_splitContainer.scss +1 -1
- package/v2Components/HtmlEditor/components/ValidationErrorDisplay/__tests__/index.test.js +152 -0
- package/v2Components/HtmlEditor/components/ValidationErrorDisplay/index.js +31 -49
- package/v2Components/HtmlEditor/components/ValidationPanel/_validationPanel.scss +34 -50
- package/v2Components/HtmlEditor/components/ValidationPanel/index.js +41 -70
- package/v2Components/HtmlEditor/constants.js +20 -42
- package/v2Components/HtmlEditor/hooks/__tests__/useInAppContent.test.js +16 -373
- package/v2Components/HtmlEditor/hooks/useEditorContent.js +2 -5
- package/v2Components/HtmlEditor/hooks/useInAppContent.js +146 -88
- package/v2Components/HtmlEditor/hooks/useValidation.js +53 -189
- package/v2Components/HtmlEditor/index.js +1 -1
- package/v2Components/HtmlEditor/messages.js +85 -95
- package/v2Components/HtmlEditor/utils/__tests__/htmlValidator.enhanced.test.js +45 -94
- package/v2Components/HtmlEditor/utils/__tests__/validationAdapter.test.js +0 -134
- package/v2Components/HtmlEditor/utils/contentSanitizer.js +41 -40
- package/v2Components/HtmlEditor/utils/htmlValidator.js +72 -71
- package/v2Components/HtmlEditor/utils/liquidTemplateSupport.js +102 -134
- package/v2Components/HtmlEditor/utils/properSyntaxHighlighting.js +25 -23
- package/v2Components/HtmlEditor/utils/validationAdapter.js +41 -66
- package/v2Components/MobilePushPreviewV2/index.js +7 -32
- package/v2Components/TemplatePreview/_templatePreview.scss +24 -55
- package/v2Components/TemplatePreview/index.js +32 -47
- package/v2Components/TemplatePreview/messages.js +0 -4
- package/v2Components/TestAndPreviewSlidebox/_testAndPreviewSlidebox.scss +0 -1
- package/v2Containers/App/constants.js +0 -5
- package/v2Containers/BeeEditor/index.js +90 -172
- package/v2Containers/Cap/tests/__snapshots__/index.test.js.snap +3 -4
- package/v2Containers/CreativesContainer/SlideBoxContent.js +53 -184
- package/v2Containers/CreativesContainer/SlideBoxFooter.js +13 -163
- package/v2Containers/CreativesContainer/SlideBoxHeader.js +1 -3
- package/v2Containers/CreativesContainer/constants.js +0 -4
- package/v2Containers/CreativesContainer/index.js +46 -407
- package/v2Containers/CreativesContainer/messages.js +0 -12
- package/v2Containers/CreativesContainer/tests/SlideBoxContent.test.js +0 -210
- package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +2 -11
- package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +50 -342
- package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +0 -106
- package/v2Containers/Email/actions.js +0 -7
- package/v2Containers/Email/constants.js +1 -5
- package/v2Containers/Email/index.js +29 -234
- package/v2Containers/Email/messages.js +0 -32
- package/v2Containers/Email/reducer.js +1 -12
- package/v2Containers/Email/sagas.js +7 -61
- package/v2Containers/Email/tests/__snapshots__/reducer.test.js.snap +0 -2
- package/v2Containers/Email/tests/reducer.test.js +0 -46
- package/v2Containers/Email/tests/sagas.test.js +29 -320
- package/v2Containers/EmailWrapper/components/EmailWrapperView.js +19 -207
- package/v2Containers/EmailWrapper/components/HTMLEditorTesting.js +74 -40
- package/v2Containers/EmailWrapper/components/__tests__/HTMLEditorTesting.test.js +67 -2
- package/v2Containers/EmailWrapper/constants.js +0 -2
- package/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +77 -629
- package/v2Containers/EmailWrapper/index.js +23 -103
- package/v2Containers/EmailWrapper/messages.js +1 -61
- package/v2Containers/EmailWrapper/tests/EmailWrapperView.test.js +214 -0
- package/v2Containers/EmailWrapper/tests/useEmailWrapper.test.js +77 -594
- package/v2Containers/InApp/actions.js +0 -7
- package/v2Containers/InApp/constants.js +4 -20
- package/v2Containers/InApp/index.js +359 -802
- package/v2Containers/InApp/index.scss +3 -4
- package/v2Containers/InApp/messages.js +3 -7
- package/v2Containers/InApp/reducer.js +3 -21
- package/v2Containers/InApp/sagas.js +9 -29
- package/v2Containers/InApp/selectors.js +5 -25
- package/v2Containers/InApp/tests/index.test.js +50 -154
- package/v2Containers/InApp/tests/reducer.test.js +0 -34
- package/v2Containers/InApp/tests/sagas.test.js +9 -61
- package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/content.test.js.snap +9 -15
- package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/index.test.js.snap +6 -10
- package/v2Containers/Line/Container/Wrapper/tests/__snapshots__/index.test.js.snap +75 -102
- package/v2Containers/Line/Container/tests/__snapshots__/index.test.js.snap +54 -81
- package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +174 -244
- package/v2Containers/SmsTrai/Create/tests/__snapshots__/index.test.js.snap +12 -16
- package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +36 -52
- package/v2Containers/TagList/index.js +19 -62
- package/v2Containers/Templates/ChannelTypeIllustration.js +1 -13
- package/v2Containers/Templates/_templates.scss +1 -265
- package/v2Containers/Templates/actions.js +1 -2
- package/v2Containers/Templates/constants.js +0 -1
- package/v2Containers/Templates/index.js +38 -363
- package/v2Containers/Templates/messages.js +0 -28
- package/v2Containers/Templates/reducer.js +0 -4
- package/v2Containers/Templates/tests/index.test.js +0 -10
- package/v2Containers/TemplatesV2/index.js +7 -15
- package/v2Containers/TemplatesV2/messages.js +0 -4
- package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +486 -682
- package/utils/imageUrlUpload.js +0 -141
- package/v2Components/CapImageUrlUpload/constants.js +0 -26
- package/v2Components/CapImageUrlUpload/index.js +0 -365
- package/v2Components/CapImageUrlUpload/index.scss +0 -35
- package/v2Components/CapImageUrlUpload/messages.js +0 -47
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.apiErrors.test.js +0 -874
- package/v2Components/HtmlEditor/components/ValidationPanel/constants.js +0 -6
- package/v2Components/HtmlEditor/components/ValidationTabs/_validationTabs.scss +0 -254
- package/v2Components/HtmlEditor/components/ValidationTabs/index.js +0 -364
- package/v2Components/HtmlEditor/components/ValidationTabs/messages.js +0 -51
- package/v2Components/HtmlEditor/hooks/__tests__/useValidation.apiErrors.test.js +0 -795
- package/v2Components/HtmlEditor/utils/validationConstants.js +0 -40
- package/v2Containers/BeePopupEditor/_beePopupEditor.scss +0 -14
- package/v2Containers/BeePopupEditor/constants.js +0 -10
- package/v2Containers/BeePopupEditor/index.js +0 -194
- package/v2Containers/BeePopupEditor/tests/index.test.js +0 -627
- package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +0 -1285
- package/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +0 -1870
- package/v2Containers/EmailWrapper/components/__tests__/EmailWrapperView.test.js +0 -520
- package/v2Containers/EmailWrapper/tests/useEmailWrapper.edgeCases.test.js +0 -643
- package/v2Containers/InApp/__tests__/InAppHTMLEditor.test.js +0 -376
- package/v2Containers/InApp/__tests__/sagas.test.js +0 -363
- package/v2Containers/InApp/tests/selectors.test.js +0 -612
- package/v2Containers/InAppWrapper/components/InAppWrapperView.js +0 -151
- package/v2Containers/InAppWrapper/components/__tests__/InAppWrapperView.test.js +0 -267
- package/v2Containers/InAppWrapper/components/inAppWrapperView.scss +0 -23
- package/v2Containers/InAppWrapper/constants.js +0 -16
- package/v2Containers/InAppWrapper/hooks/__tests__/useInAppWrapper.test.js +0 -473
- package/v2Containers/InAppWrapper/hooks/useInAppWrapper.js +0 -198
- package/v2Containers/InAppWrapper/index.js +0 -148
- package/v2Containers/InAppWrapper/messages.js +0 -49
- package/v2Containers/InappAdvance/index.js +0 -1099
- package/v2Containers/InappAdvance/index.scss +0 -10
- package/v2Containers/InappAdvance/tests/index.test.js +0 -448
- package/v2Containers/WebPush/Create/components/BrandIconSection.js +0 -108
- package/v2Containers/WebPush/Create/components/ButtonForm.js +0 -172
- package/v2Containers/WebPush/Create/components/ButtonItem.js +0 -101
- package/v2Containers/WebPush/Create/components/ButtonList.js +0 -107
- package/v2Containers/WebPush/Create/components/ButtonsLinksSection.js +0 -160
- package/v2Containers/WebPush/Create/components/ButtonsLinksSection.test.js +0 -476
- package/v2Containers/WebPush/Create/components/FormActions.js +0 -54
- package/v2Containers/WebPush/Create/components/FormActions.test.js +0 -163
- package/v2Containers/WebPush/Create/components/MediaSection.js +0 -143
- package/v2Containers/WebPush/Create/components/MediaSection.test.js +0 -341
- package/v2Containers/WebPush/Create/components/MessageSection.js +0 -103
- package/v2Containers/WebPush/Create/components/MessageSection.test.js +0 -268
- package/v2Containers/WebPush/Create/components/NotificationTitleSection.js +0 -87
- package/v2Containers/WebPush/Create/components/NotificationTitleSection.test.js +0 -210
- package/v2Containers/WebPush/Create/components/TemplateNameSection.js +0 -54
- package/v2Containers/WebPush/Create/components/TemplateNameSection.test.js +0 -143
- package/v2Containers/WebPush/Create/components/__snapshots__/ButtonsLinksSection.test.js.snap +0 -82
- package/v2Containers/WebPush/Create/components/__snapshots__/FormActions.test.js.snap +0 -16
- package/v2Containers/WebPush/Create/components/__snapshots__/MediaSection.test.js.snap +0 -41
- package/v2Containers/WebPush/Create/components/__snapshots__/MessageSection.test.js.snap +0 -54
- package/v2Containers/WebPush/Create/components/__snapshots__/NotificationTitleSection.test.js.snap +0 -37
- package/v2Containers/WebPush/Create/components/__snapshots__/TemplateNameSection.test.js.snap +0 -21
- package/v2Containers/WebPush/Create/components/_buttons.scss +0 -246
- package/v2Containers/WebPush/Create/components/tests/ButtonForm.test.js +0 -554
- package/v2Containers/WebPush/Create/components/tests/ButtonItem.test.js +0 -607
- package/v2Containers/WebPush/Create/components/tests/ButtonList.test.js +0 -515
- package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonForm.test.js.snap +0 -666
- package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonItem.test.js.snap +0 -74
- package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonList.test.js.snap +0 -46
- package/v2Containers/WebPush/Create/hooks/useButtonManagement.js +0 -150
- package/v2Containers/WebPush/Create/hooks/useButtonManagement.test.js +0 -406
- package/v2Containers/WebPush/Create/hooks/useCharacterCount.js +0 -30
- package/v2Containers/WebPush/Create/hooks/useCharacterCount.test.js +0 -151
- package/v2Containers/WebPush/Create/hooks/useImageUpload.js +0 -104
- package/v2Containers/WebPush/Create/hooks/useImageUpload.test.js +0 -538
- package/v2Containers/WebPush/Create/hooks/useTagManagement.js +0 -122
- package/v2Containers/WebPush/Create/hooks/useTagManagement.test.js +0 -633
- package/v2Containers/WebPush/Create/index.js +0 -1148
- package/v2Containers/WebPush/Create/index.scss +0 -134
- package/v2Containers/WebPush/Create/messages.js +0 -203
- package/v2Containers/WebPush/Create/preview/DevicePreviewContent.js +0 -228
- package/v2Containers/WebPush/Create/preview/NotificationContainer.js +0 -294
- package/v2Containers/WebPush/Create/preview/PreviewContent.js +0 -90
- package/v2Containers/WebPush/Create/preview/PreviewControls.js +0 -305
- package/v2Containers/WebPush/Create/preview/PreviewDisclaimer.js +0 -23
- package/v2Containers/WebPush/Create/preview/WebPushPreview.js +0 -155
- package/v2Containers/WebPush/Create/preview/assets/Light.svg +0 -53
- package/v2Containers/WebPush/Create/preview/assets/Top.svg +0 -5
- package/v2Containers/WebPush/Create/preview/assets/android-arrow-down.svg +0 -9
- package/v2Containers/WebPush/Create/preview/assets/android-arrow-up.svg +0 -9
- package/v2Containers/WebPush/Create/preview/assets/chrome-icon.png +0 -0
- package/v2Containers/WebPush/Create/preview/assets/edge-icon.png +0 -0
- package/v2Containers/WebPush/Create/preview/assets/firefox-icon.svg +0 -106
- package/v2Containers/WebPush/Create/preview/assets/iOS.svg +0 -26
- package/v2Containers/WebPush/Create/preview/assets/macos-arrow-down-icon.svg +0 -9
- package/v2Containers/WebPush/Create/preview/assets/macos-triple-dot-icon.svg +0 -9
- package/v2Containers/WebPush/Create/preview/assets/opera-icon.svg +0 -18
- package/v2Containers/WebPush/Create/preview/assets/safari-icon.svg +0 -29
- package/v2Containers/WebPush/Create/preview/assets/windows-close-icon.svg +0 -9
- package/v2Containers/WebPush/Create/preview/assets/windows-triple-dot-icon.svg +0 -9
- package/v2Containers/WebPush/Create/preview/components/AndroidMobileChromeHeader.js +0 -47
- package/v2Containers/WebPush/Create/preview/components/AndroidMobileExpanded.js +0 -141
- package/v2Containers/WebPush/Create/preview/components/IOSHeader.js +0 -45
- package/v2Containers/WebPush/Create/preview/components/NotificationExpandedContent.js +0 -68
- package/v2Containers/WebPush/Create/preview/components/NotificationHeader.js +0 -61
- package/v2Containers/WebPush/Create/preview/components/WindowsChromeExpanded.js +0 -99
- package/v2Containers/WebPush/Create/preview/components/tests/AndroidMobileExpanded.test.js +0 -733
- package/v2Containers/WebPush/Create/preview/components/tests/WindowsChromeExpanded.test.js +0 -571
- package/v2Containers/WebPush/Create/preview/components/tests/__snapshots__/AndroidMobileExpanded.test.js.snap +0 -81
- package/v2Containers/WebPush/Create/preview/components/tests/__snapshots__/WindowsChromeExpanded.test.js.snap +0 -81
- package/v2Containers/WebPush/Create/preview/config/notificationMappings.js +0 -50
- package/v2Containers/WebPush/Create/preview/constants.js +0 -637
- package/v2Containers/WebPush/Create/preview/notification-container.scss +0 -79
- package/v2Containers/WebPush/Create/preview/preview.scss +0 -351
- package/v2Containers/WebPush/Create/preview/styles/_android-mobile-chrome.scss +0 -370
- package/v2Containers/WebPush/Create/preview/styles/_android-mobile-edge.scss +0 -12
- package/v2Containers/WebPush/Create/preview/styles/_android-mobile-firefox.scss +0 -12
- package/v2Containers/WebPush/Create/preview/styles/_android-mobile-opera.scss +0 -12
- package/v2Containers/WebPush/Create/preview/styles/_android-tablet-chrome.scss +0 -47
- package/v2Containers/WebPush/Create/preview/styles/_android-tablet-edge.scss +0 -11
- package/v2Containers/WebPush/Create/preview/styles/_android-tablet-firefox.scss +0 -11
- package/v2Containers/WebPush/Create/preview/styles/_android-tablet-opera.scss +0 -11
- package/v2Containers/WebPush/Create/preview/styles/_base.scss +0 -207
- package/v2Containers/WebPush/Create/preview/styles/_ios.scss +0 -153
- package/v2Containers/WebPush/Create/preview/styles/_ipados.scss +0 -107
- package/v2Containers/WebPush/Create/preview/styles/_macos-chrome.scss +0 -101
- package/v2Containers/WebPush/Create/preview/styles/_windows-chrome.scss +0 -229
- package/v2Containers/WebPush/Create/preview/tests/DevicePreviewContent.test.js +0 -909
- package/v2Containers/WebPush/Create/preview/tests/NotificationContainer.test.js +0 -1081
- package/v2Containers/WebPush/Create/preview/tests/PreviewControls.test.js +0 -723
- package/v2Containers/WebPush/Create/preview/tests/WebPushPreview.test.js +0 -1327
- package/v2Containers/WebPush/Create/preview/tests/__snapshots__/DevicePreviewContent.test.js.snap +0 -131
- package/v2Containers/WebPush/Create/preview/tests/__snapshots__/NotificationContainer.test.js.snap +0 -112
- package/v2Containers/WebPush/Create/preview/tests/__snapshots__/PreviewControls.test.js.snap +0 -144
- package/v2Containers/WebPush/Create/preview/tests/__snapshots__/WebPushPreview.test.js.snap +0 -129
- package/v2Containers/WebPush/Create/utils/payloadBuilder.js +0 -96
- package/v2Containers/WebPush/Create/utils/payloadBuilder.test.js +0 -396
- package/v2Containers/WebPush/Create/utils/previewUtils.js +0 -89
- package/v2Containers/WebPush/Create/utils/urlValidation.js +0 -115
- package/v2Containers/WebPush/Create/utils/urlValidation.test.js +0 -449
- package/v2Containers/WebPush/Create/utils/validation.js +0 -75
- package/v2Containers/WebPush/Create/utils/validation.test.js +0 -283
- package/v2Containers/WebPush/actions.js +0 -60
- package/v2Containers/WebPush/constants.js +0 -132
- package/v2Containers/WebPush/index.js +0 -2
- package/v2Containers/WebPush/reducer.js +0 -104
- package/v2Containers/WebPush/sagas.js +0 -119
- package/v2Containers/WebPush/selectors.js +0 -65
- package/v2Containers/WebPush/tests/reducer.test.js +0 -863
- package/v2Containers/WebPush/tests/sagas.test.js +0 -566
- package/v2Containers/WebPush/tests/selectors.test.js +0 -960
|
@@ -1,16 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Validation Hook for HTML Editor
|
|
3
|
-
* Manages real-time validation and error display
|
|
4
|
-
* UI gating: only Rule Group #1 (Input & Sanitization) blocks Save/Update/Preview/Test.
|
|
5
|
-
* All other rules are warnings for backward compatibility with CKEditor legacy templates.
|
|
3
|
+
* Manages real-time validation and error display
|
|
6
4
|
*/
|
|
7
5
|
|
|
8
|
-
import {
|
|
9
|
-
useState, useEffect, useCallback, useRef,
|
|
10
|
-
} from 'react';
|
|
6
|
+
import { useState, useEffect, useCallback, useRef } from 'react';
|
|
11
7
|
import { validateHTML, extractAndValidateCSS } from '../utils/htmlValidator';
|
|
12
8
|
import { sanitizeHTML, isContentSafe, findUnsafeContent } from '../utils/contentSanitizer';
|
|
13
|
-
import { BLOCKING_ERROR_RULE_IDS } from '../constants';
|
|
14
9
|
|
|
15
10
|
/**
|
|
16
11
|
* Custom hook for managing HTML/CSS validation
|
|
@@ -21,46 +16,12 @@ import { BLOCKING_ERROR_RULE_IDS } from '../constants';
|
|
|
21
16
|
* @param {Function} formatValidatorMessage - Message formatter function for validator internationalization
|
|
22
17
|
* @returns {Object} Validation state and methods
|
|
23
18
|
*/
|
|
24
|
-
/**
|
|
25
|
-
* Get line number for a character position in text
|
|
26
|
-
*/
|
|
27
|
-
const getLineNumberFromPosition = (text, position) => {
|
|
28
|
-
if (position === undefined || position < 0) return 1;
|
|
29
|
-
return text.substring(0, position).split('\n').length;
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Find line number for a tag or pattern in content
|
|
34
|
-
* Used for API errors to locate where the error occurs
|
|
35
|
-
*/
|
|
36
|
-
const findLineNumberForTag = (content, tagName) => {
|
|
37
|
-
if (!content || !tagName) return null;
|
|
38
|
-
|
|
39
|
-
// Try to find the tag in the content
|
|
40
|
-
// Look for patterns like {{ tagName }}, {{tagName}}, etc.
|
|
41
|
-
const escapedTagName = tagName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
42
|
-
const patterns = [
|
|
43
|
-
new RegExp(`\\{\\{\\s*${escapedTagName}\\s*\\}\\}`, 'g'),
|
|
44
|
-
new RegExp(`\\{%[^%]*${escapedTagName}[^%]*%\\}`, 'g'),
|
|
45
|
-
];
|
|
46
|
-
|
|
47
|
-
for (const pattern of patterns) {
|
|
48
|
-
const match = pattern.exec(content);
|
|
49
|
-
if (match) {
|
|
50
|
-
return getLineNumberFromPosition(content, match.index);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return null;
|
|
55
|
-
};
|
|
56
|
-
|
|
57
19
|
export const useValidation = (content, variant = 'email', options = {}, formatSanitizerMessage = null, formatValidatorMessage = null) => {
|
|
58
20
|
const {
|
|
59
21
|
enableRealTime = true,
|
|
60
22
|
debounceMs = 500,
|
|
61
23
|
enableSanitization = true,
|
|
62
|
-
securityLevel = 'standard'
|
|
63
|
-
apiValidationErrors = null, // API validation errors from validateLiquidTemplateContent
|
|
24
|
+
securityLevel = 'standard'
|
|
64
25
|
} = options;
|
|
65
26
|
|
|
66
27
|
// Validation state
|
|
@@ -81,8 +42,8 @@ export const useValidation = (content, variant = 'email', options = {}, formatSa
|
|
|
81
42
|
totalErrors: 0,
|
|
82
43
|
totalWarnings: 0,
|
|
83
44
|
totalInfo: 0,
|
|
84
|
-
hasSecurityIssues: false
|
|
85
|
-
}
|
|
45
|
+
hasSecurityIssues: false
|
|
46
|
+
}
|
|
86
47
|
});
|
|
87
48
|
|
|
88
49
|
// Refs for debouncing
|
|
@@ -94,7 +55,7 @@ export const useValidation = (content, variant = 'email', options = {}, formatSa
|
|
|
94
55
|
*/
|
|
95
56
|
const performValidation = useCallback(async (htmlContent) => {
|
|
96
57
|
if (!htmlContent) {
|
|
97
|
-
setValidationState(
|
|
58
|
+
setValidationState(prev => ({
|
|
98
59
|
...prev,
|
|
99
60
|
isValidating: false,
|
|
100
61
|
htmlErrors: [],
|
|
@@ -111,13 +72,13 @@ export const useValidation = (content, variant = 'email', options = {}, formatSa
|
|
|
111
72
|
totalErrors: 0,
|
|
112
73
|
totalWarnings: 0,
|
|
113
74
|
totalInfo: 0,
|
|
114
|
-
hasSecurityIssues: false
|
|
115
|
-
}
|
|
75
|
+
hasSecurityIssues: false
|
|
76
|
+
}
|
|
116
77
|
}));
|
|
117
78
|
return;
|
|
118
79
|
}
|
|
119
80
|
|
|
120
|
-
setValidationState(
|
|
81
|
+
setValidationState(prev => ({ ...prev, isValidating: true }));
|
|
121
82
|
|
|
122
83
|
try {
|
|
123
84
|
// 1. HTML Validation
|
|
@@ -130,21 +91,15 @@ export const useValidation = (content, variant = 'email', options = {}, formatSa
|
|
|
130
91
|
const isSecure = isContentSafe(htmlContent);
|
|
131
92
|
const securityIssues = isSecure ? [] : findUnsafeContent(htmlContent);
|
|
132
93
|
|
|
133
|
-
// 4. Sanitization (if enabled)
|
|
94
|
+
// 4. Sanitization (if enabled)
|
|
134
95
|
let sanitizationResult = null;
|
|
135
96
|
if (enableSanitization) {
|
|
136
97
|
sanitizationResult = sanitizeHTML(htmlContent, variant, securityLevel, formatSanitizerMessage);
|
|
137
98
|
}
|
|
138
99
|
|
|
139
|
-
|
|
140
|
-
const
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
// Summary: totalErrors/totalWarnings are for display; blocking count is for gating
|
|
144
|
-
const totalErrors = htmlValidation.errors.length + cssValidation.errors.length + blockingSanitizerCount + protocolSecurityCount;
|
|
145
|
-
const totalWarnings = htmlValidation.warnings.length + cssValidation.warnings.length
|
|
146
|
-
+ (sanitizationWarnings.length - blockingSanitizerCount)
|
|
147
|
-
+ (securityIssues.length - protocolSecurityCount);
|
|
100
|
+
// Calculate summary
|
|
101
|
+
const totalErrors = htmlValidation.errors.length + cssValidation.errors.length;
|
|
102
|
+
const totalWarnings = htmlValidation.warnings.length + cssValidation.warnings.length;
|
|
148
103
|
const totalInfo = htmlValidation.info.length + cssValidation.info.length;
|
|
149
104
|
const hasSecurityIssues = securityIssues.length > 0;
|
|
150
105
|
|
|
@@ -159,19 +114,20 @@ export const useValidation = (content, variant = 'email', options = {}, formatSa
|
|
|
159
114
|
cssWarnings: cssValidation.warnings,
|
|
160
115
|
cssInfo: cssValidation.info,
|
|
161
116
|
securityIssues,
|
|
162
|
-
sanitizationWarnings,
|
|
117
|
+
sanitizationWarnings: sanitizationResult?.warnings || [],
|
|
163
118
|
isValid: htmlValidation.isValid && cssValidation.isValid,
|
|
164
119
|
isSecure,
|
|
165
120
|
summary: {
|
|
166
121
|
totalErrors,
|
|
167
122
|
totalWarnings,
|
|
168
123
|
totalInfo,
|
|
169
|
-
hasSecurityIssues
|
|
170
|
-
}
|
|
124
|
+
hasSecurityIssues
|
|
125
|
+
}
|
|
171
126
|
});
|
|
127
|
+
|
|
172
128
|
} catch (error) {
|
|
173
129
|
console.error('Validation error:', error);
|
|
174
|
-
setValidationState(
|
|
130
|
+
setValidationState(prev => ({
|
|
175
131
|
...prev,
|
|
176
132
|
isValidating: false,
|
|
177
133
|
htmlErrors: [{
|
|
@@ -181,13 +137,13 @@ export const useValidation = (content, variant = 'email', options = {}, formatSa
|
|
|
181
137
|
column: 1,
|
|
182
138
|
rule: 'validation-error',
|
|
183
139
|
severity: 'error',
|
|
184
|
-
source: 'validator'
|
|
140
|
+
source: 'validator'
|
|
185
141
|
}],
|
|
186
142
|
isValid: false,
|
|
187
143
|
summary: {
|
|
188
144
|
...prev.summary,
|
|
189
|
-
totalErrors: 1
|
|
190
|
-
}
|
|
145
|
+
totalErrors: 1
|
|
146
|
+
}
|
|
191
147
|
}));
|
|
192
148
|
}
|
|
193
149
|
}, [variant, enableSanitization, securityLevel, formatSanitizerMessage, formatValidatorMessage]);
|
|
@@ -252,8 +208,8 @@ export const useValidation = (content, variant = 'email', options = {}, formatSa
|
|
|
252
208
|
totalErrors: 0,
|
|
253
209
|
totalWarnings: 0,
|
|
254
210
|
totalInfo: 0,
|
|
255
|
-
hasSecurityIssues: false
|
|
256
|
-
}
|
|
211
|
+
hasSecurityIssues: false
|
|
212
|
+
}
|
|
257
213
|
});
|
|
258
214
|
}, []);
|
|
259
215
|
|
|
@@ -267,10 +223,10 @@ export const useValidation = (content, variant = 'email', options = {}, formatSa
|
|
|
267
223
|
...validationState.htmlInfo,
|
|
268
224
|
...validationState.cssErrors,
|
|
269
225
|
...validationState.cssWarnings,
|
|
270
|
-
...validationState.cssInfo
|
|
226
|
+
...validationState.cssInfo
|
|
271
227
|
];
|
|
272
228
|
|
|
273
|
-
return allErrors.filter(
|
|
229
|
+
return allErrors.filter(error => error.severity === severity);
|
|
274
230
|
}, [validationState]);
|
|
275
231
|
|
|
276
232
|
/**
|
|
@@ -283,111 +239,32 @@ export const useValidation = (content, variant = 'email', options = {}, formatSa
|
|
|
283
239
|
...validationState.htmlInfo,
|
|
284
240
|
...validationState.cssErrors,
|
|
285
241
|
...validationState.cssWarnings,
|
|
286
|
-
...validationState.cssInfo
|
|
242
|
+
...validationState.cssInfo
|
|
287
243
|
];
|
|
288
244
|
|
|
289
|
-
return allErrors.filter(
|
|
245
|
+
return allErrors.filter(error => error.source === source);
|
|
290
246
|
}, [validationState]);
|
|
291
247
|
|
|
292
|
-
/**
|
|
293
|
-
* Extract line number from error message if present
|
|
294
|
-
* API errors might contain line numbers in messages like "Error at line 5" or "Line 10: error"
|
|
295
|
-
* Also tries to find line number by searching for the problematic tag in content
|
|
296
|
-
*/
|
|
297
|
-
const extractLineNumberFromMessage = useCallback((message) => {
|
|
298
|
-
if (!message || typeof message !== 'string') {
|
|
299
|
-
return null;
|
|
300
|
-
}
|
|
301
|
-
// Try to match patterns like "line 5", "Line 10", "at line 15", "line: 20", etc.
|
|
302
|
-
const lineMatch = message.match(/\b(?:line|Line|LINE)\s*:?\s*(\d+)\b/i);
|
|
303
|
-
if (lineMatch && lineMatch[1]) {
|
|
304
|
-
return parseInt(lineMatch[1], 10);
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
// Try to extract tag name from error message (e.g., "Unsupported tags: test" -> "test")
|
|
308
|
-
const tagMatch = message.match(/(?:tag|tags|Tag|Tags)[\s:]+([a-zA-Z_][a-zA-Z0-9_.]*)/i);
|
|
309
|
-
if (tagMatch && tagMatch[1] && content) {
|
|
310
|
-
const tagName = tagMatch[1];
|
|
311
|
-
const lineNumber = findLineNumberForTag(content, tagName);
|
|
312
|
-
if (lineNumber) {
|
|
313
|
-
return lineNumber;
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
return null;
|
|
318
|
-
}, [content]);
|
|
319
|
-
|
|
320
248
|
/**
|
|
321
249
|
* Get all errors and warnings combined
|
|
322
|
-
* Includes both client-side validation errors and API validation errors
|
|
323
250
|
*/
|
|
324
251
|
const getAllIssues = useCallback(() => {
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
rule: 'liquid-api-validation',
|
|
334
|
-
severity: 'error',
|
|
335
|
-
source: 'liquid-validator',
|
|
336
|
-
};
|
|
337
|
-
});
|
|
338
|
-
|
|
339
|
-
const apiStandardErrors = (apiValidationErrors?.standardErrors || []).map((errorMessage) => {
|
|
340
|
-
const extractedLine = extractLineNumberFromMessage(errorMessage);
|
|
341
|
-
return {
|
|
252
|
+
return [
|
|
253
|
+
...validationState.htmlErrors,
|
|
254
|
+
...validationState.htmlWarnings,
|
|
255
|
+
...validationState.htmlInfo,
|
|
256
|
+
...validationState.cssErrors,
|
|
257
|
+
...validationState.cssWarnings,
|
|
258
|
+
...validationState.cssInfo,
|
|
259
|
+
...validationState.securityIssues.map(issue => ({
|
|
342
260
|
type: 'error',
|
|
343
|
-
message: errorMessage,
|
|
344
|
-
line: extractedLine,
|
|
345
|
-
column: null,
|
|
346
|
-
rule: 'standard-api-validation',
|
|
347
|
-
severity: 'error',
|
|
348
|
-
source: 'api-validator',
|
|
349
|
-
};
|
|
350
|
-
});
|
|
351
|
-
|
|
352
|
-
// Security: protocol types are Rule Group #1 (blocking); others are warnings
|
|
353
|
-
const PROTOCOL_TYPES = ['JavaScript Protocol', 'Data URL', 'VBScript Protocol'];
|
|
354
|
-
const securityAsIssues = (validationState.securityIssues || []).map((issue) => {
|
|
355
|
-
const isBlocking = PROTOCOL_TYPES.includes(issue?.type);
|
|
356
|
-
return {
|
|
357
|
-
type: isBlocking ? 'error' : 'warning',
|
|
358
261
|
message: `Security issue: ${issue.type}`,
|
|
359
262
|
line: 1,
|
|
360
263
|
column: 1,
|
|
361
|
-
rule:
|
|
362
|
-
severity:
|
|
363
|
-
source: 'security'
|
|
364
|
-
}
|
|
365
|
-
});
|
|
366
|
-
|
|
367
|
-
// Sanitization warnings (Rule Group #1 entries have rule set by contentSanitizer)
|
|
368
|
-
const sanitizationAsIssues = (validationState.sanitizationWarnings || []).map((w) => {
|
|
369
|
-
const sev = BLOCKING_ERROR_RULE_IDS.includes(w.rule) ? 'error' : 'warning';
|
|
370
|
-
return {
|
|
371
|
-
...w,
|
|
372
|
-
severity: sev,
|
|
373
|
-
rule: w.rule || 'sanitizer.unknown',
|
|
374
|
-
line: w.line ?? 1,
|
|
375
|
-
column: w.column ?? 1,
|
|
376
|
-
source: w.source || 'sanitizer',
|
|
377
|
-
};
|
|
378
|
-
});
|
|
379
|
-
|
|
380
|
-
const allIssues = [
|
|
381
|
-
...(validationState.htmlErrors || []),
|
|
382
|
-
...(validationState.htmlWarnings || []),
|
|
383
|
-
...(validationState.htmlInfo || []),
|
|
384
|
-
...(validationState.cssErrors || []),
|
|
385
|
-
...(validationState.cssWarnings || []),
|
|
386
|
-
...(validationState.cssInfo || []),
|
|
387
|
-
...securityAsIssues,
|
|
388
|
-
...sanitizationAsIssues,
|
|
389
|
-
...apiLiquidErrors,
|
|
390
|
-
...apiStandardErrors,
|
|
264
|
+
rule: 'security-violation',
|
|
265
|
+
severity: 'error',
|
|
266
|
+
source: 'security'
|
|
267
|
+
}))
|
|
391
268
|
].sort((a, b) => {
|
|
392
269
|
// Sort by severity (error > warning > info) then by line number
|
|
393
270
|
const severityOrder = { error: 0, warning: 1, info: 2 };
|
|
@@ -396,22 +273,16 @@ export const useValidation = (content, variant = 'email', options = {}, formatSa
|
|
|
396
273
|
}
|
|
397
274
|
return (a.line || 0) - (b.line || 0);
|
|
398
275
|
});
|
|
399
|
-
|
|
400
|
-
// Ensure we always return an array
|
|
401
|
-
return Array.isArray(allIssues) ? allIssues : [];
|
|
402
|
-
}, [validationState, apiValidationErrors, extractLineNumberFromMessage]);
|
|
276
|
+
}, [validationState]);
|
|
403
277
|
|
|
404
278
|
/**
|
|
405
279
|
* Check if validation is clean (no errors or warnings)
|
|
406
|
-
* Includes API validation errors in the check
|
|
407
280
|
*/
|
|
408
281
|
const isClean = useCallback(() => {
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
&& !hasApiErrors;
|
|
414
|
-
}, [validationState.summary, apiValidationErrors]);
|
|
282
|
+
return validationState.summary.totalErrors === 0 &&
|
|
283
|
+
validationState.summary.totalWarnings === 0 &&
|
|
284
|
+
!validationState.summary.hasSecurityIssues;
|
|
285
|
+
}, [validationState.summary]);
|
|
415
286
|
|
|
416
287
|
// Effect to validate content when it changes
|
|
417
288
|
useEffect(() => {
|
|
@@ -421,19 +292,14 @@ export const useValidation = (content, variant = 'email', options = {}, formatSa
|
|
|
421
292
|
}, [content, validateContent, enableRealTime]);
|
|
422
293
|
|
|
423
294
|
// Cleanup on unmount
|
|
424
|
-
useEffect(() =>
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
295
|
+
useEffect(() => {
|
|
296
|
+
return () => {
|
|
297
|
+
if (debounceRef.current) {
|
|
298
|
+
clearTimeout(debounceRef.current);
|
|
299
|
+
}
|
|
300
|
+
};
|
|
428
301
|
}, []);
|
|
429
302
|
|
|
430
|
-
const hasApiErrors = (apiValidationErrors?.liquidErrors?.length || 0) + (apiValidationErrors?.standardErrors?.length || 0) > 0;
|
|
431
|
-
|
|
432
|
-
const protocolTypes = ['JavaScript Protocol', 'Data URL', 'VBScript Protocol'];
|
|
433
|
-
// Client-side Liquid validation errors are blocking (genuine syntax errors)
|
|
434
|
-
const hasClientSideLiquidErrors = (validationState.htmlErrors || []).some((e) => e.source === 'liquid-validator' && e.severity === 'error');
|
|
435
|
-
const hasBlockingErrors = (validationState.sanitizationWarnings || []).some((w) => BLOCKING_ERROR_RULE_IDS.includes(w.rule)) || (validationState.securityIssues || []).some((s) => protocolTypes.includes(s?.type)) || hasApiErrors || hasClientSideLiquidErrors;
|
|
436
|
-
|
|
437
303
|
return {
|
|
438
304
|
// Validation state
|
|
439
305
|
...validationState,
|
|
@@ -450,12 +316,10 @@ export const useValidation = (content, variant = 'email', options = {}, formatSa
|
|
|
450
316
|
isClean,
|
|
451
317
|
|
|
452
318
|
// Computed properties
|
|
453
|
-
hasErrors: validationState.summary.totalErrors > 0
|
|
319
|
+
hasErrors: validationState.summary.totalErrors > 0,
|
|
454
320
|
hasWarnings: validationState.summary.totalWarnings > 0,
|
|
455
|
-
hasSecurityIssues: validationState.summary.hasSecurityIssues
|
|
456
|
-
/** True only when Rule Group #1 (Input & Sanitization) issues exist. Use for UI gating. */
|
|
457
|
-
hasBlockingErrors,
|
|
321
|
+
hasSecurityIssues: validationState.summary.hasSecurityIssues
|
|
458
322
|
};
|
|
459
323
|
};
|
|
460
324
|
|
|
461
|
-
export default useValidation;
|
|
325
|
+
export default useValidation;
|