@capillarytech/creatives-library 8.0.271 → 8.0.272

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 (149) hide show
  1. package/assets/Android.png +0 -0
  2. package/assets/iOS.png +0 -0
  3. package/constants/unified.js +2 -1
  4. package/initialReducer.js +2 -0
  5. package/package.json +1 -1
  6. package/services/api.js +10 -0
  7. package/services/tests/api.test.js +34 -0
  8. package/tests/integration/TemplateCreation/TemplateCreation.integration.test.js +17 -35
  9. package/tests/integration/TemplateCreation/api-response.js +31 -1
  10. package/tests/integration/TemplateCreation/msw-handler.js +2 -0
  11. package/utils/common.js +5 -0
  12. package/utils/commonUtils.js +28 -5
  13. package/utils/tests/commonUtil.test.js +224 -0
  14. package/utils/transformTemplateConfig.js +0 -10
  15. package/v2Components/CapDeviceContent/index.js +61 -56
  16. package/v2Components/CapTagList/index.js +6 -1
  17. package/v2Components/CapTagListWithInput/index.js +5 -1
  18. package/v2Components/CapTagListWithInput/messages.js +1 -1
  19. package/v2Components/CapWhatsappCTA/tests/index.test.js +5 -0
  20. package/v2Components/ErrorInfoNote/constants.js +1 -0
  21. package/v2Components/ErrorInfoNote/index.js +402 -72
  22. package/v2Components/ErrorInfoNote/messages.js +32 -6
  23. package/v2Components/ErrorInfoNote/style.scss +278 -6
  24. package/v2Components/FormBuilder/tests/index.test.js +13 -4
  25. package/v2Components/HtmlEditor/HTMLEditor.js +418 -99
  26. package/v2Components/HtmlEditor/__tests__/HTMLEditor.apiErrors.test.js +870 -0
  27. package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +1882 -133
  28. package/v2Components/HtmlEditor/__tests__/index.lazy.test.js +27 -16
  29. package/v2Components/HtmlEditor/_htmlEditor.scss +108 -45
  30. package/v2Components/HtmlEditor/_index.lazy.scss +0 -1
  31. package/v2Components/HtmlEditor/components/CodeEditorPane/_codeEditorPane.scss +23 -102
  32. package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +148 -140
  33. package/v2Components/HtmlEditor/components/DeviceToggle/_deviceToggle.scss +2 -1
  34. package/v2Components/HtmlEditor/components/DeviceToggle/index.js +3 -3
  35. package/v2Components/HtmlEditor/components/EditorToolbar/_editorToolbar.scss +9 -1
  36. package/v2Components/HtmlEditor/components/EditorToolbar/index.js +31 -6
  37. package/v2Components/HtmlEditor/components/FullscreenModal/_fullscreenModal.scss +22 -0
  38. package/v2Components/HtmlEditor/components/InAppPreviewPane/DeviceFrame.js +4 -7
  39. package/v2Components/HtmlEditor/components/InAppPreviewPane/__tests__/DeviceFrame.test.js +35 -45
  40. package/v2Components/HtmlEditor/components/InAppPreviewPane/_inAppPreviewPane.scss +1 -3
  41. package/v2Components/HtmlEditor/components/InAppPreviewPane/constants.js +33 -33
  42. package/v2Components/HtmlEditor/components/InAppPreviewPane/index.js +7 -6
  43. package/v2Components/HtmlEditor/components/PreviewPane/_previewPane.scss +7 -10
  44. package/v2Components/HtmlEditor/components/PreviewPane/index.js +22 -43
  45. package/v2Components/HtmlEditor/components/SplitContainer/_splitContainer.scss +1 -1
  46. package/v2Components/HtmlEditor/components/ValidationErrorDisplay/_validationErrorDisplay.scss +18 -0
  47. package/v2Components/HtmlEditor/components/ValidationErrorDisplay/index.js +36 -31
  48. package/v2Components/HtmlEditor/components/ValidationPanel/_validationPanel.scss +46 -34
  49. package/v2Components/HtmlEditor/components/ValidationPanel/constants.js +6 -0
  50. package/v2Components/HtmlEditor/components/ValidationPanel/index.js +52 -46
  51. package/v2Components/HtmlEditor/components/ValidationTabs/_validationTabs.scss +277 -0
  52. package/v2Components/HtmlEditor/components/ValidationTabs/index.js +295 -0
  53. package/v2Components/HtmlEditor/components/ValidationTabs/messages.js +51 -0
  54. package/v2Components/HtmlEditor/constants.js +45 -20
  55. package/v2Components/HtmlEditor/hooks/__tests__/useInAppContent.test.js +373 -16
  56. package/v2Components/HtmlEditor/hooks/__tests__/useValidation.test.js +351 -16
  57. package/v2Components/HtmlEditor/hooks/useEditorContent.js +5 -2
  58. package/v2Components/HtmlEditor/hooks/useInAppContent.js +88 -146
  59. package/v2Components/HtmlEditor/hooks/useValidation.js +213 -56
  60. package/v2Components/HtmlEditor/index.js +1 -1
  61. package/v2Components/HtmlEditor/messages.js +102 -94
  62. package/v2Components/HtmlEditor/utils/__tests__/htmlValidator.enhanced.test.js +214 -45
  63. package/v2Components/HtmlEditor/utils/__tests__/validationAdapter.test.js +134 -0
  64. package/v2Components/HtmlEditor/utils/contentSanitizer.js +40 -41
  65. package/v2Components/HtmlEditor/utils/htmlValidator.js +71 -72
  66. package/v2Components/HtmlEditor/utils/liquidTemplateSupport.js +158 -124
  67. package/v2Components/HtmlEditor/utils/properSyntaxHighlighting.js +23 -25
  68. package/v2Components/HtmlEditor/utils/validationAdapter.js +66 -41
  69. package/v2Components/HtmlEditor/utils/validationConstants.js +38 -0
  70. package/v2Components/MobilePushPreviewV2/constants.js +6 -0
  71. package/v2Components/MobilePushPreviewV2/index.js +33 -7
  72. package/v2Components/TemplatePreview/_templatePreview.scss +55 -24
  73. package/v2Components/TemplatePreview/index.js +47 -32
  74. package/v2Components/TemplatePreview/messages.js +4 -0
  75. package/v2Components/TestAndPreviewSlidebox/_testAndPreviewSlidebox.scss +1 -0
  76. package/v2Containers/BeeEditor/index.js +172 -90
  77. package/v2Containers/BeePopupEditor/_beePopupEditor.scss +14 -0
  78. package/v2Containers/BeePopupEditor/constants.js +10 -0
  79. package/v2Containers/BeePopupEditor/index.js +194 -0
  80. package/v2Containers/BeePopupEditor/tests/index.test.js +627 -0
  81. package/v2Containers/CreativesContainer/SlideBoxContent.js +127 -51
  82. package/v2Containers/CreativesContainer/SlideBoxFooter.js +156 -13
  83. package/v2Containers/CreativesContainer/SlideBoxHeader.js +2 -1
  84. package/v2Containers/CreativesContainer/constants.js +1 -0
  85. package/v2Containers/CreativesContainer/index.js +251 -47
  86. package/v2Containers/CreativesContainer/messages.js +8 -0
  87. package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +11 -2
  88. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +38 -50
  89. package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +103 -0
  90. package/v2Containers/Email/actions.js +7 -0
  91. package/v2Containers/Email/constants.js +5 -1
  92. package/v2Containers/Email/index.js +234 -29
  93. package/v2Containers/Email/messages.js +32 -0
  94. package/v2Containers/Email/reducer.js +12 -1
  95. package/v2Containers/Email/sagas.js +61 -7
  96. package/v2Containers/Email/tests/__snapshots__/reducer.test.js.snap +2 -0
  97. package/v2Containers/Email/tests/reducer.test.js +46 -0
  98. package/v2Containers/Email/tests/sagas.test.js +320 -29
  99. package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +1246 -0
  100. package/v2Containers/EmailWrapper/components/EmailWrapperView.js +212 -21
  101. package/v2Containers/EmailWrapper/components/HTMLEditorTesting.js +40 -74
  102. package/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +2472 -0
  103. package/v2Containers/EmailWrapper/components/__tests__/EmailWrapperView.test.js +520 -0
  104. package/v2Containers/EmailWrapper/components/__tests__/HTMLEditorTesting.test.js +2 -67
  105. package/v2Containers/EmailWrapper/constants.js +2 -0
  106. package/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +627 -79
  107. package/v2Containers/EmailWrapper/index.js +103 -23
  108. package/v2Containers/EmailWrapper/messages.js +65 -1
  109. package/v2Containers/EmailWrapper/tests/useEmailWrapper.edgeCases.test.js +955 -0
  110. package/v2Containers/EmailWrapper/tests/useEmailWrapper.test.js +596 -82
  111. package/v2Containers/InApp/__tests__/InAppHTMLEditor.test.js +376 -0
  112. package/v2Containers/InApp/__tests__/sagas.test.js +363 -0
  113. package/v2Containers/InApp/actions.js +7 -0
  114. package/v2Containers/InApp/constants.js +20 -4
  115. package/v2Containers/InApp/index.js +802 -360
  116. package/v2Containers/InApp/index.scss +4 -3
  117. package/v2Containers/InApp/messages.js +7 -3
  118. package/v2Containers/InApp/reducer.js +21 -3
  119. package/v2Containers/InApp/sagas.js +29 -9
  120. package/v2Containers/InApp/selectors.js +25 -5
  121. package/v2Containers/InApp/tests/index.test.js +154 -50
  122. package/v2Containers/InApp/tests/reducer.test.js +34 -0
  123. package/v2Containers/InApp/tests/sagas.test.js +61 -9
  124. package/v2Containers/InApp/tests/selectors.test.js +612 -0
  125. package/v2Containers/InAppWrapper/components/InAppWrapperView.js +151 -0
  126. package/v2Containers/InAppWrapper/components/__tests__/InAppWrapperView.test.js +267 -0
  127. package/v2Containers/InAppWrapper/components/inAppWrapperView.scss +23 -0
  128. package/v2Containers/InAppWrapper/constants.js +16 -0
  129. package/v2Containers/InAppWrapper/hooks/__tests__/useInAppWrapper.test.js +473 -0
  130. package/v2Containers/InAppWrapper/hooks/useInAppWrapper.js +198 -0
  131. package/v2Containers/InAppWrapper/index.js +148 -0
  132. package/v2Containers/InAppWrapper/messages.js +49 -0
  133. package/v2Containers/InappAdvance/index.js +1099 -0
  134. package/v2Containers/InappAdvance/index.scss +10 -0
  135. package/v2Containers/InappAdvance/tests/index.test.js +448 -0
  136. package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/content.test.js.snap +3 -0
  137. package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/index.test.js.snap +2 -0
  138. package/v2Containers/Line/Container/Wrapper/tests/__snapshots__/index.test.js.snap +2 -0
  139. package/v2Containers/Line/Container/tests/__snapshots__/index.test.js.snap +9 -0
  140. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +12 -0
  141. package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +4 -0
  142. package/v2Containers/TagList/index.js +62 -19
  143. package/v2Containers/Templates/_templates.scss +60 -1
  144. package/v2Containers/Templates/index.js +89 -4
  145. package/v2Containers/Templates/messages.js +4 -0
  146. package/v2Containers/TemplatesV2/TemplatesV2.style.js +4 -2
  147. package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +34 -0
  148. package/v2Components/HtmlEditor/components/ValidationErrorDisplay/__tests__/index.test.js +0 -152
  149. package/v2Containers/EmailWrapper/tests/EmailWrapperView.test.js +0 -214
@@ -7,6 +7,8 @@ import { html } from '@codemirror/lang-html';
7
7
  import { syntaxHighlighting, HighlightStyle } from '@codemirror/language';
8
8
  import { tags } from '@lezer/highlight';
9
9
  import { EditorView } from '@codemirror/view';
10
+ import { VALIDATION_SEVERITY } from '../constants';
11
+ import { ISSUE_SOURCES } from './validationConstants';
10
12
 
11
13
  /**
12
14
  * Liquid Template Syntax Patterns
@@ -34,7 +36,7 @@ export const LIQUID_PATTERNS = {
34
36
  OPERATORS: /\b(and|or|not|contains|in|==|!=|<|>|<=|>=)\b/g,
35
37
 
36
38
  // String literals in Liquid
37
- STRING_LITERALS: /(["'])((?:\\.|(?!\1)[^\\])*?)\1/g
39
+ STRING_LITERALS: /(["'])((?:\\.|(?!\1)[^\\])*?)\1/g,
38
40
  };
39
41
 
40
42
  /**
@@ -68,7 +70,7 @@ export const liquidVSCodeTheme = HighlightStyle.define([
68
70
  { tag: tags.atom, color: '#4ec9b0' }, // Liquid filters
69
71
  { tag: tags.punctuation, color: '#d4d4d4' },
70
72
  { tag: tags.bracket, color: '#ffd700' },
71
- { tag: tags.brace, color: '#ffd700' }
73
+ { tag: tags.brace, color: '#ffd700' },
72
74
  ]);
73
75
 
74
76
  /**
@@ -145,13 +147,13 @@ export class LiquidValidator {
145
147
  } else {
146
148
  // Stray closing brace - no matching opening brace
147
149
  this.errors.push({
148
- type: 'error',
150
+ type: VALIDATION_SEVERITY.ERROR,
149
151
  message: 'Stray closing }} without matching opening {{',
150
152
  line: this.getLineNumber(html, position),
151
153
  column: 1,
152
154
  rule: 'liquid-stray-closing-output',
153
- severity: 'error',
154
- source: 'liquid-validator'
155
+ severity: VALIDATION_SEVERITY.ERROR,
156
+ source: ISSUE_SOURCES.LIQUID,
155
157
  });
156
158
  }
157
159
  }
@@ -160,15 +162,15 @@ export class LiquidValidator {
160
162
  // After scan, any remaining entries on stack are unclosed opening braces
161
163
  if (stack.length > 0) {
162
164
  // Report each unclosed opening brace
163
- stack.forEach(position => {
165
+ stack.forEach((position) => {
164
166
  this.errors.push({
165
- type: 'error',
167
+ type: VALIDATION_SEVERITY.ERROR,
166
168
  message: 'unclosed Liquid output tag - missing }}',
167
169
  line: this.getLineNumber(html, position),
168
170
  column: 1,
169
171
  rule: 'liquid-unclosed-output',
170
- severity: 'error',
171
- source: 'liquid-validator'
172
+ severity: VALIDATION_SEVERITY.ERROR,
173
+ source: ISSUE_SOURCES.LIQUID,
172
174
  });
173
175
  });
174
176
  }
@@ -197,13 +199,13 @@ export class LiquidValidator {
197
199
  if (openTags.length > closeTags.length) {
198
200
  const unmatchedCount = openTags.length - closeTags.length;
199
201
  this.errors.push({
200
- type: 'error',
202
+ type: VALIDATION_SEVERITY.ERROR,
201
203
  message: `${unmatchedCount} unclosed Liquid logic tag(s) - missing %}`,
202
204
  line: this.getLineNumber(html, openTags[openTags.length - 1]),
203
205
  column: 1,
204
206
  rule: 'liquid-unclosed-logic',
205
- severity: 'error',
206
- source: 'liquid-validator'
207
+ severity: VALIDATION_SEVERITY.ERROR,
208
+ source: ISSUE_SOURCES.LIQUID,
207
209
  });
208
210
  }
209
211
  }
@@ -216,15 +218,15 @@ export class LiquidValidator {
216
218
  const nestedOutputPattern = /\{\{[^}]*\{\{[^}]*\}\}/g;
217
219
  const nestedOutput = html.match(nestedOutputPattern);
218
220
  if (nestedOutput) {
219
- nestedOutput.forEach(match => {
221
+ nestedOutput.forEach((match) => {
220
222
  this.errors.push({
221
- type: 'error',
223
+ type: VALIDATION_SEVERITY.ERROR,
222
224
  message: `Nested braces in Liquid output tag: ${match}`,
223
225
  line: this.getLineNumber(html, html.indexOf(match)),
224
226
  column: 1,
225
227
  rule: 'liquid-nested-braces',
226
- severity: 'error',
227
- source: 'liquid-validator'
228
+ severity: VALIDATION_SEVERITY.ERROR,
229
+ source: ISSUE_SOURCES.LIQUID,
228
230
  });
229
231
  });
230
232
  }
@@ -233,15 +235,15 @@ export class LiquidValidator {
233
235
  const nestedLogicPattern = /\{%[^%]*\{%[^%]*%\}/g;
234
236
  const nestedLogic = html.match(nestedLogicPattern);
235
237
  if (nestedLogic) {
236
- nestedLogic.forEach(match => {
238
+ nestedLogic.forEach((match) => {
237
239
  this.errors.push({
238
- type: 'error',
240
+ type: VALIDATION_SEVERITY.ERROR,
239
241
  message: `Nested braces in Liquid logic tag: ${match}`,
240
242
  line: this.getLineNumber(html, html.indexOf(match)),
241
243
  column: 1,
242
244
  rule: 'liquid-nested-braces',
243
- severity: 'error',
244
- source: 'liquid-validator'
245
+ severity: VALIDATION_SEVERITY.ERROR,
246
+ source: ISSUE_SOURCES.LIQUID,
245
247
  });
246
248
  });
247
249
  }
@@ -262,10 +264,10 @@ export class LiquidValidator {
262
264
 
263
265
  logicTags.push({
264
266
  full: match[0],
265
- content: content,
266
- keyword: keyword,
267
+ content,
268
+ keyword,
267
269
  position: match.index,
268
- line: this.getLineNumber(html, match.index)
270
+ line: this.getLineNumber(html, match.index),
269
271
  });
270
272
  }
271
273
 
@@ -279,61 +281,78 @@ export class LiquidValidator {
279
281
  validateBalancedTags(logicTags) {
280
282
  const stack = [];
281
283
  const pairs = {
282
- 'if': 'endif',
283
- 'unless': 'endunless',
284
- 'for': 'endfor',
285
- 'case': 'endcase',
286
- 'capture': 'endcapture',
287
- 'comment': 'endcomment',
288
- 'tablerow': 'endtablerow',
289
- 'raw': 'endraw'
284
+ if: 'endif',
285
+ unless: 'endunless',
286
+ for: 'endfor',
287
+ case: 'endcase',
288
+ capture: 'endcapture',
289
+ comment: 'endcomment',
290
+ tablerow: 'endtablerow',
291
+ raw: 'endraw',
290
292
  };
291
293
 
292
- logicTags.forEach(tag => {
293
- const keyword = tag.keyword;
294
+ logicTags.forEach((tag) => {
295
+ const {keyword} = tag;
294
296
 
295
297
  if (pairs[keyword]) {
296
298
  // Opening tag
297
299
  stack.push({ keyword, tag });
298
300
  } else if (Object.values(pairs).includes(keyword)) {
299
301
  // Closing tag
300
- const expectedOpening = Object.keys(pairs).find(key => pairs[key] === keyword);
302
+ const expectedOpening = Object.keys(pairs).find((key) => pairs[key] === keyword);
301
303
  const lastOpening = stack.pop();
302
304
 
303
305
  if (!lastOpening) {
304
306
  this.errors.push({
305
- type: 'error',
307
+ type: VALIDATION_SEVERITY.ERROR,
306
308
  message: `Unexpected closing tag: {% ${keyword} %}`,
307
309
  line: tag.line,
308
310
  column: 1,
309
311
  rule: 'liquid-unexpected-closing',
310
- severity: 'error',
311
- source: 'liquid-validator'
312
+ severity: VALIDATION_SEVERITY.ERROR,
313
+ source: ISSUE_SOURCES.LIQUID,
312
314
  });
313
315
  } else if (lastOpening.keyword !== expectedOpening) {
314
316
  this.errors.push({
315
- type: 'error',
317
+ type: VALIDATION_SEVERITY.ERROR,
316
318
  message: `Mismatched Liquid tags: {% ${lastOpening.keyword} %} ... {% ${keyword} %}`,
317
319
  line: tag.line,
318
320
  column: 1,
319
321
  rule: 'liquid-mismatched-tags',
320
- severity: 'error',
321
- source: 'liquid-validator'
322
+ severity: VALIDATION_SEVERITY.ERROR,
323
+ source: ISSUE_SOURCES.LIQUID,
322
324
  });
323
325
  }
324
326
  }
325
327
  });
326
328
 
327
329
  // Check for unclosed opening tags
328
- stack.forEach(unclosed => {
330
+ if (stack.length > 0) {
331
+ stack.forEach(({ keyword, tag }) => {
332
+ const expectedClosing = pairs[keyword];
333
+ const error = {
334
+ type: VALIDATION_SEVERITY.ERROR,
335
+ message: `Unclosed Liquid tag: {% ${keyword} %} - missing {% ${expectedClosing} %}`,
336
+ line: tag.line,
337
+ column: 1,
338
+ rule: 'liquid-unclosed-tag',
339
+ severity: VALIDATION_SEVERITY.ERROR,
340
+ source: ISSUE_SOURCES.LIQUID,
341
+ };
342
+ this.errors.push(error);
343
+ });
344
+ }
345
+
346
+ // Check for unclosed opening tags
347
+ stack.forEach((unclosed) => {
329
348
  this.errors.push({
330
- type: 'error',
349
+ type: VALIDATION_SEVERITY.ERROR,
331
350
  message: `Unclosed Liquid tag: {% ${unclosed.keyword} %}`,
332
351
  line: unclosed.tag.line,
333
352
  column: 1,
334
353
  rule: 'liquid-unclosed-tag',
335
- severity: 'error',
336
- source: 'liquid-validator'
354
+ severity: VALIDATION_SEVERITY.ERROR,
355
+ source: ISSUE_SOURCES.LIQUID,
337
356
  });
338
357
  });
339
358
  }
@@ -345,35 +364,52 @@ export class LiquidValidator {
345
364
  // Check for malformed filters
346
365
  const malformedFilters = html.match(/\|\s*\||\|\s*$/gm);
347
366
  if (malformedFilters) {
348
- malformedFilters.forEach(match => {
367
+ malformedFilters.forEach((match) => {
349
368
  this.warnings.push({
350
- type: 'warning',
369
+ type: VALIDATION_SEVERITY.WARNING,
351
370
  message: `Malformed Liquid filter: ${match.trim()}`,
352
371
  line: this.getLineNumber(html, html.indexOf(match)),
353
372
  column: 1,
354
373
  rule: 'liquid-malformed-filter',
355
- severity: 'warning',
356
- source: 'liquid-validator'
374
+ severity: VALIDATION_SEVERITY.WARNING,
375
+ source: ISSUE_SOURCES.LIQUID,
357
376
  });
358
377
  });
359
378
  }
360
379
 
361
380
  // Check for common filter usage
362
- const commonFilters = ['date', 'capitalize', 'upcase', 'downcase', 'strip', 'truncate', 'default'];
381
+ // Standard Liquid filters that are commonly used and shouldn't trigger info messages
382
+ // This list includes standard Liquid filters to avoid false positives
383
+ const commonFilters = [
384
+ // String filters
385
+ 'capitalize', 'upcase', 'downcase', 'strip', 'lstrip', 'rstrip', 'strip_html', 'strip_newlines',
386
+ 'truncate', 'truncatewords', 'prepend', 'append', 'remove', 'remove_first', 'replace', 'replace_first',
387
+ 'split', 'join', 'concat', 'escape', 'escape_once', 'newline_to_br',
388
+ // Array filters
389
+ 'first', 'last', 'size', 'slice', 'sort', 'sort_natural', 'map', 'where', 'uniq', 'compact', 'reverse',
390
+ // Number filters
391
+ 'abs', 'ceil', 'floor', 'round', 'times', 'divided_by', 'modulo', 'minus', 'plus', 'at_least', 'at_most',
392
+ // Date filters
393
+ 'date',
394
+ // Other common filters
395
+ 'default', 'url_encode', 'url_decode',
396
+ ];
363
397
  const filterPattern = /\|\s*([a-zA-Z_][a-zA-Z0-9_]*)/g;
364
398
  let filterMatch;
365
399
 
366
400
  while ((filterMatch = filterPattern.exec(html)) !== null) {
367
401
  const filterName = filterMatch[1];
368
402
  if (!commonFilters.includes(filterName)) {
403
+ // Only show info for truly custom/unknown filters
404
+ // Standard Liquid filters are now included in commonFilters list
369
405
  this.info.push({
370
- type: 'info',
406
+ type: VALIDATION_SEVERITY.INFO,
371
407
  message: `Using filter: ${filterName}`,
372
408
  line: this.getLineNumber(html, filterMatch.index),
373
409
  column: 1,
374
410
  rule: 'liquid-filter-usage',
375
- severity: 'info',
376
- source: 'liquid-validator'
411
+ severity: VALIDATION_SEVERITY.INFO,
412
+ source: ISSUE_SOURCES.LIQUID,
377
413
  });
378
414
  }
379
415
  }
@@ -386,15 +422,15 @@ export class LiquidValidator {
386
422
  // Check for undefined variable patterns (basic check)
387
423
  const suspiciousVariables = html.match(/\{\{\s*[^}]*undefined[^}]*\s*\}\}/g);
388
424
  if (suspiciousVariables) {
389
- suspiciousVariables.forEach(match => {
425
+ suspiciousVariables.forEach((match) => {
390
426
  this.warnings.push({
391
- type: 'warning',
427
+ type: VALIDATION_SEVERITY.WARNING,
392
428
  message: `Potentially undefined variable: ${match}`,
393
429
  line: this.getLineNumber(html, html.indexOf(match)),
394
430
  column: 1,
395
431
  rule: 'liquid-undefined-variable',
396
- severity: 'warning',
397
- source: 'liquid-validator'
432
+ severity: VALIDATION_SEVERITY.WARNING,
433
+ source: ISSUE_SOURCES.LIQUID,
398
434
  });
399
435
  });
400
436
  }
@@ -417,7 +453,7 @@ export class LiquidValidator {
417
453
  isValid: this.errors.length === 0,
418
454
  errors: this.errors,
419
455
  warnings: this.warnings,
420
- info: this.info
456
+ info: this.info,
421
457
  };
422
458
  }
423
459
  }
@@ -425,60 +461,58 @@ export class LiquidValidator {
425
461
  /**
426
462
  * Enhanced CodeMirror extensions with Liquid support
427
463
  */
428
- export const createLiquidExtensions = () => {
429
- return [
430
- // HTML language support (base)
431
- html(),
432
-
433
- // Enhanced syntax highlighting with Liquid support
434
- syntaxHighlighting(liquidVSCodeTheme),
435
-
436
- // Editor theme
437
- EditorView.theme({
438
- "&": {
439
- height: "500px",
440
- backgroundColor: "#1e1e1e",
441
- fontSize: "14px",
442
- fontFamily: "'DM Mono', 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace"
443
- },
444
- ".cm-content": {
445
- padding: "12px",
446
- backgroundColor: "#1e1e1e",
447
- fontSize: "14px",
448
- lineHeight: "20px",
449
- fontFamily: "'DM Mono', 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace",
450
- color: "#d4d4d4"
451
- },
452
- ".cm-focused": {
453
- outline: "none"
454
- },
455
- ".cm-lineNumbers": {
456
- fontSize: "14px",
457
- lineHeight: "20px",
458
- color: "#858585",
459
- backgroundColor: "#1e1e1e",
460
- paddingRight: "8px",
461
- paddingLeft: "8px",
462
- borderRight: "1px solid #3e3e3e",
463
- minWidth: "45px",
464
- textAlign: "right"
465
- },
466
- ".cm-gutters": {
467
- backgroundColor: "#1e1e1e",
468
- borderRight: "1px solid #3e3e3e"
469
- },
470
- ".cm-activeLine": {
471
- backgroundColor: "#2a2d2e"
472
- },
473
- ".cm-selection": {
474
- backgroundColor: "#264f78"
475
- },
476
- ".cm-cursor": {
477
- borderLeft: "2px solid #ffffff"
478
- }
479
- })
480
- ];
481
- };
464
+ export const createLiquidExtensions = () => [
465
+ // HTML language support (base)
466
+ html(),
467
+
468
+ // Enhanced syntax highlighting with Liquid support
469
+ syntaxHighlighting(liquidVSCodeTheme),
470
+
471
+ // Editor theme
472
+ EditorView.theme({
473
+ "&": {
474
+ height: "500px",
475
+ backgroundColor: "#1e1e1e",
476
+ fontSize: "14px",
477
+ fontFamily: "'DM Mono', 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace",
478
+ },
479
+ ".cm-content": {
480
+ padding: "12px",
481
+ backgroundColor: "#1e1e1e",
482
+ fontSize: "14px",
483
+ lineHeight: "20px",
484
+ fontFamily: "'DM Mono', 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace",
485
+ color: "#d4d4d4",
486
+ },
487
+ ".cm-focused": {
488
+ outline: "none",
489
+ },
490
+ ".cm-lineNumbers": {
491
+ fontSize: "14px",
492
+ lineHeight: "20px",
493
+ color: "#858585",
494
+ backgroundColor: "#1e1e1e",
495
+ paddingRight: "8px",
496
+ paddingLeft: "8px",
497
+ borderRight: "1px solid #3e3e3e",
498
+ minWidth: "45px",
499
+ textAlign: "right",
500
+ },
501
+ ".cm-gutters": {
502
+ backgroundColor: "#1e1e1e",
503
+ borderRight: "1px solid #3e3e3e",
504
+ },
505
+ ".cm-activeLine": {
506
+ backgroundColor: "#2a2d2e",
507
+ },
508
+ ".cm-selection": {
509
+ backgroundColor: "#264f78",
510
+ },
511
+ ".cm-cursor": {
512
+ borderLeft: "2px solid #ffffff",
513
+ },
514
+ }),
515
+ ];
482
516
 
483
517
  /**
484
518
  * Validates HTML content with Liquid template support
@@ -496,22 +530,22 @@ export const validateLiquidHTML = (html, variant = 'email') => {
496
530
  */
497
531
  export const LIQUID_SNIPPETS = {
498
532
  // Output tags
499
- 'customer_name': '{{ customer.first_name }} {{ customer.last_name }}',
500
- 'customer_email': '{{ customer.email }}',
501
- 'current_date': '{{ "now" | date: "%B %d, %Y" }}',
502
- 'organization_name': '{{ organization.name }}',
533
+ customer_name: '{{ customer.first_name }} {{ customer.last_name }}',
534
+ customer_email: '{{ customer.email }}',
535
+ current_date: '{{ "now" | date: "%B %d, %Y" }}',
536
+ organization_name: '{{ organization.name }}',
503
537
 
504
538
  // Logic tags
505
- 'if_statement': '{% if condition %}\n <!-- content -->\n{% endif %}',
506
- 'for_loop': '{% for item in collection %}\n {{ item.name }}\n{% endfor %}',
507
- 'unless_statement': '{% unless condition %}\n <!-- content -->\n{% endunless %}',
508
- 'case_statement': '{% case variable %}\n {% when "value1" %}\n <!-- content -->\n {% when "value2" %}\n <!-- content -->\n {% else %}\n <!-- default content -->\n{% endcase %}',
539
+ if_statement: '{% if condition %}\n <!-- content -->\n{% endif %}',
540
+ for_loop: '{% for item in collection %}\n {{ item.name }}\n{% endfor %}',
541
+ unless_statement: '{% unless condition %}\n <!-- content -->\n{% endunless %}',
542
+ case_statement: '{% case variable %}\n {% when "value1" %}\n <!-- content -->\n {% when "value2" %}\n <!-- content -->\n {% else %}\n <!-- default content -->\n{% endcase %}',
509
543
 
510
544
  // Common filters
511
- 'date_filter': '{{ date_variable | date: "%B %d, %Y" }}',
512
- 'capitalize_filter': '{{ text | capitalize }}',
513
- 'truncate_filter': '{{ text | truncate: 50 }}',
514
- 'default_filter': '{{ variable | default: "Default Value" }}'
545
+ date_filter: '{{ date_variable | date: "%B %d, %Y" }}',
546
+ capitalize_filter: '{{ text | capitalize }}',
547
+ truncate_filter: '{{ text | truncate: 50 }}',
548
+ default_filter: '{{ variable | default: "Default Value" }}',
515
549
  };
516
550
 
517
551
  export default {
@@ -520,5 +554,5 @@ export default {
520
554
  LiquidValidator,
521
555
  createLiquidExtensions,
522
556
  validateLiquidHTML,
523
- LIQUID_SNIPPETS
557
+ LIQUID_SNIPPETS,
524
558
  };
@@ -76,7 +76,7 @@ export const comprehensiveVSCodeTheme = HighlightStyle.define([
76
76
  { tag: tags.link, color: '#4fc1ff', textDecoration: 'underline' },
77
77
  { tag: tags.heading, color: '#9cdcfe', fontWeight: 'bold' },
78
78
  { tag: tags.emphasis, fontStyle: 'italic' },
79
- { tag: tags.strong, fontWeight: 'bold' }
79
+ { tag: tags.strong, fontWeight: 'bold' },
80
80
  ]);
81
81
 
82
82
  /**
@@ -88,7 +88,7 @@ export const cleanEditorTheme = EditorView.theme({
88
88
  height: "500px",
89
89
  backgroundColor: "#1e1e1e",
90
90
  fontSize: "14px",
91
- fontFamily: "'DM Mono', 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace"
91
+ fontFamily: "'DM Mono', 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace",
92
92
  },
93
93
  ".cm-content": {
94
94
  padding: "12px",
@@ -96,17 +96,17 @@ export const cleanEditorTheme = EditorView.theme({
96
96
  fontSize: "14px",
97
97
  lineHeight: "20px",
98
98
  fontFamily: "'DM Mono', 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace",
99
- color: "#d4d4d4" // Base text color for all content
99
+ color: "#d4d4d4", // Base text color for all content
100
100
  },
101
101
  ".cm-focused": {
102
- outline: "none"
102
+ outline: "none",
103
103
  },
104
104
  ".cm-editor": {
105
105
  borderRadius: "0",
106
- border: "none"
106
+ border: "none",
107
107
  },
108
108
  ".cm-scroller": {
109
- fontFamily: "'DM Mono', 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace"
109
+ fontFamily: "'DM Mono', 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace",
110
110
  },
111
111
  ".cm-lineNumbers": {
112
112
  fontSize: "14px",
@@ -117,47 +117,45 @@ export const cleanEditorTheme = EditorView.theme({
117
117
  paddingLeft: "8px",
118
118
  borderRight: "1px solid #3e3e3e",
119
119
  minWidth: "45px",
120
- textAlign: "right"
120
+ textAlign: "right",
121
121
  },
122
122
  ".cm-gutters": {
123
123
  backgroundColor: "#1e1e1e",
124
- borderRight: "1px solid #3e3e3e"
124
+ borderRight: "1px solid #3e3e3e",
125
125
  },
126
126
  ".cm-activeLine": {
127
- backgroundColor: "#2a2d2e"
127
+ backgroundColor: "#2a2d2e",
128
128
  },
129
129
  ".cm-selection": {
130
- backgroundColor: "#264f78"
130
+ backgroundColor: "#264f78",
131
131
  },
132
132
  ".cm-cursor": {
133
- borderLeft: "2px solid #ffffff"
133
+ borderLeft: "2px solid #ffffff",
134
134
  },
135
135
  // Additional fallback for text nodes
136
136
  ".cm-line": {
137
- color: "#d4d4d4"
138
- }
137
+ color: "#d4d4d4",
138
+ },
139
139
  });
140
140
 
141
141
  /**
142
142
  * ROBUST Extension Creator - Single, clean implementation
143
143
  * Uses only verified tags to avoid undefined errors
144
144
  */
145
- export const createRobustExtensions = () => {
146
- return [
147
- // 1. HTML language support with proper parsing
148
- html(),
145
+ export const createRobustExtensions = () => [
146
+ // 1. HTML language support with proper parsing
147
+ html(),
149
148
 
150
- // 2. SAFE syntax highlighting (using only confirmed tags)
151
- syntaxHighlighting(comprehensiveVSCodeTheme),
149
+ // 2. SAFE syntax highlighting (using only confirmed tags)
150
+ syntaxHighlighting(comprehensiveVSCodeTheme),
152
151
 
153
- // 3. Clean theme (structure only, no color conflicts)
154
- cleanEditorTheme
155
- ];
156
- };
152
+ // 3. Clean theme (structure only, no color conflicts)
153
+ cleanEditorTheme,
154
+ ];
157
155
 
158
156
  // Export the main function
159
157
  export default {
160
158
  comprehensiveVSCodeTheme,
161
159
  cleanEditorTheme,
162
- createRobustExtensions
163
- };
160
+ createRobustExtensions,
161
+ };