@lyads/visual-editor 0.0.0-stage → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (258) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/LICENSE +201 -0
  3. package/NOTICE +8 -0
  4. package/README.md +135 -2
  5. package/THIRD_PARTY_NOTICES.md +21259 -0
  6. package/dist/application/block-placement.d.ts +30 -0
  7. package/dist/application/block-session.d.ts +135 -0
  8. package/dist/application/content-service.d.ts +73 -0
  9. package/dist/application/document-commands.d.ts +51 -0
  10. package/dist/application/document-metadata.d.ts +30 -0
  11. package/dist/application/document-presentation.d.ts +35 -0
  12. package/dist/application/email-insertion.d.ts +76 -0
  13. package/dist/application/host.d.ts +36 -0
  14. package/dist/application/image-link.d.ts +36 -0
  15. package/dist/application/section-layout.d.ts +25 -0
  16. package/dist/application/session.d.ts +128 -0
  17. package/dist/assets/browser-worker-D56tNvnb.js +1014 -0
  18. package/dist/assets/browser-worker-D56tNvnb.js.map +1 -0
  19. package/dist/block-controller-RjYGvOcn.js +2468 -0
  20. package/dist/block-controller-RjYGvOcn.js.map +1 -0
  21. package/dist/block-factory-C5oHi4Fm.js +5397 -0
  22. package/dist/block-factory-C5oHi4Fm.js.map +1 -0
  23. package/dist/blocks/block-checks.d.ts +34 -0
  24. package/dist/blocks/block-inspector.d.ts +55 -0
  25. package/dist/blocks/block-output.d.ts +28 -0
  26. package/dist/blocks/block-type.d.ts +124 -0
  27. package/dist/blocks/content-guard.d.ts +52 -0
  28. package/dist/blocks/conversion.d.ts +22 -0
  29. package/dist/blocks/definitions.d.ts +43 -0
  30. package/dist/blocks/device-styles.d.ts +31 -0
  31. package/dist/blocks/email-generator.d.ts +22 -0
  32. package/dist/blocks/email-preview.d.ts +23 -0
  33. package/dist/blocks/email-renderer.d.ts +20 -0
  34. package/dist/blocks/fields.d.ts +34 -0
  35. package/dist/blocks/page-generator.d.ts +16 -0
  36. package/dist/blocks/render-context.d.ts +58 -0
  37. package/dist/blocks/styles.d.ts +54 -0
  38. package/dist/blocks/types/embed.d.ts +40 -0
  39. package/dist/blocks/types/layout.d.ts +41 -0
  40. package/dist/blocks/types/media.d.ts +53 -0
  41. package/dist/blocks/types/structure.d.ts +44 -0
  42. package/dist/blocks/types/text.d.ts +88 -0
  43. package/dist/blocks/values.d.ts +64 -0
  44. package/dist/browser.js +69 -0
  45. package/dist/browser.js.map +1 -0
  46. package/dist/canvas-runtime/action-bar.d.ts +19 -0
  47. package/dist/canvas-runtime/auto-scroll.d.ts +10 -0
  48. package/dist/canvas-runtime/block-drag.d.ts +29 -0
  49. package/dist/canvas-runtime/bridge.d.ts +6 -0
  50. package/dist/canvas-runtime/context.d.ts +53 -0
  51. package/dist/canvas-runtime/document-sync.d.ts +21 -0
  52. package/dist/canvas-runtime/drop-targets.d.ts +34 -0
  53. package/dist/canvas-runtime/embed-markers.d.ts +15 -0
  54. package/dist/canvas-runtime/file-guard.d.ts +12 -0
  55. package/dist/canvas-runtime/image-tools.d.ts +31 -0
  56. package/dist/canvas-runtime/keyboard.d.ts +18 -0
  57. package/dist/canvas-runtime/main.d.ts +1 -0
  58. package/dist/canvas-runtime/messages.d.ts +26 -0
  59. package/dist/canvas-runtime/morph.d.ts +21 -0
  60. package/dist/canvas-runtime/navigation.d.ts +29 -0
  61. package/dist/canvas-runtime/overlay.d.ts +15 -0
  62. package/dist/canvas-runtime/pointer-intents.d.ts +14 -0
  63. package/dist/canvas-runtime/selection-layer.d.ts +16 -0
  64. package/dist/canvas-runtime/shared/shortcuts.d.ts +27 -0
  65. package/dist/canvas-runtime/text-editor.d.ts +55 -0
  66. package/dist/canvas-runtime/text-session.d.ts +39 -0
  67. package/dist/canvas-runtime/variable-marks.d.ts +20 -0
  68. package/dist/canvas-runtime/viewport.d.ts +10 -0
  69. package/dist/codecs/css.d.ts +74 -0
  70. package/dist/codecs/html.d.ts +81 -0
  71. package/dist/compilation/browser-compiler.d.ts +14 -0
  72. package/dist/compilation/browser-worker.d.ts +1 -0
  73. package/dist/compilation/compile-lanes.d.ts +18 -0
  74. package/dist/compilation/generated-mjml.d.ts +25 -0
  75. package/dist/compilation/guard.d.ts +40 -0
  76. package/dist/compilation/node-compiler.d.ts +17 -0
  77. package/dist/compilation/node-worker.d.ts +1 -0
  78. package/dist/composition/block-factory.d.ts +84 -0
  79. package/dist/composition/browser.d.ts +48 -0
  80. package/dist/composition/factory.d.ts +48 -0
  81. package/dist/composition/server.d.ts +43 -0
  82. package/dist/core/any-document.d.ts +16 -0
  83. package/dist/core/block-document.d.ts +215 -0
  84. package/dist/core/budget.d.ts +32 -0
  85. package/dist/core/canvas-contract.d.ts +29 -0
  86. package/dist/core/canvas-layout.d.ts +66 -0
  87. package/dist/core/catalog.d.ts +35 -0
  88. package/dist/core/document-presentation.d.ts +21 -0
  89. package/dist/core/document.d.ts +99 -0
  90. package/dist/core/history.d.ts +26 -0
  91. package/dist/core/html-content-model.d.ts +32 -0
  92. package/dist/core/html-escape.d.ts +2 -0
  93. package/dist/core/rich-text-format.d.ts +14 -0
  94. package/dist/core/rich-text-markup.d.ts +28 -0
  95. package/dist/core/section-layout.d.ts +83 -0
  96. package/dist/generated-mjml-CtzE-f3v.js +1235 -0
  97. package/dist/generated-mjml-CtzE-f3v.js.map +1 -0
  98. package/dist/identity-CJHb6l9N.js +13759 -0
  99. package/dist/identity-CJHb6l9N.js.map +1 -0
  100. package/dist/renderers/canvas-bridge.d.ts +75 -0
  101. package/dist/renderers/canvas-icons.d.ts +1 -0
  102. package/dist/renderers/canvas-runtime.generated.d.ts +3 -0
  103. package/dist/renderers/element-source.d.ts +13 -0
  104. package/dist/renderers/email-renderer.d.ts +14 -0
  105. package/dist/renderers/marked-preview.d.ts +34 -0
  106. package/dist/renderers/markup-tree.d.ts +36 -0
  107. package/dist/renderers/page-renderer.d.ts +15 -0
  108. package/dist/renderers/preview-document.d.ts +39 -0
  109. package/dist/renderers/preview-frame.d.ts +102 -0
  110. package/dist/renderers/section-scaffold.d.ts +16 -0
  111. package/dist/renderers/selection-preview.d.ts +47 -0
  112. package/dist/rich-text/command-executor.d.ts +26 -0
  113. package/dist/rich-text/commands.d.ts +36 -0
  114. package/dist/rich-text/document-builder.d.ts +52 -0
  115. package/dist/rich-text/formatting.d.ts +17 -0
  116. package/dist/rich-text/projection-export.d.ts +17 -0
  117. package/dist/rich-text/projection-rules.d.ts +13 -0
  118. package/dist/rich-text/schema.d.ts +50 -0
  119. package/dist/rich-text/whitespace.d.ts +7 -0
  120. package/dist/security/bounded-parser.d.ts +18 -0
  121. package/dist/security/conditional-comment.d.ts +30 -0
  122. package/dist/security/content-inventory.d.ts +78 -0
  123. package/dist/security/email-sanitizer.d.ts +36 -0
  124. package/dist/security/identity.d.ts +6 -0
  125. package/dist/security/markup-rules.d.ts +31 -0
  126. package/dist/security/policy.d.ts +61 -0
  127. package/dist/security/preview-message.d.ts +317 -0
  128. package/dist/security/rich-text-projection.d.ts +19 -0
  129. package/dist/security/sha256.d.ts +6 -0
  130. package/dist/security/source-markup.d.ts +53 -0
  131. package/dist/security/text-presentation.d.ts +19 -0
  132. package/dist/security/url-policy.d.ts +23 -0
  133. package/dist/server-worker.js +17 -0
  134. package/dist/server-worker.js.map +1 -0
  135. package/dist/server.js +79 -0
  136. package/dist/server.js.map +1 -0
  137. package/dist/templates/blank-email.d.ts +6 -0
  138. package/dist/templates/blocks/catalog.d.ts +31 -0
  139. package/dist/templates/catalog.d.ts +31 -0
  140. package/dist/visual-editor.css +2 -0
  141. package/dist/vue/block-controller.d.ts +106 -0
  142. package/dist/vue/block-workbench.d.ts +70 -0
  143. package/dist/vue/canvas/canvas-theme.d.ts +8 -0
  144. package/dist/vue/canvas/file-drop.d.ts +38 -0
  145. package/dist/vue/canvas/frame-window.d.ts +26 -0
  146. package/dist/vue/canvas/inline-text.d.ts +98 -0
  147. package/dist/vue/canvas/palette-drag.d.ts +55 -0
  148. package/dist/vue/canvas/piece-requests.d.ts +48 -0
  149. package/dist/vue/canvas/strip-reserve.d.ts +14 -0
  150. package/dist/vue/canvas-content-label.d.ts +5 -0
  151. package/dist/vue/components/BlockVisualEditor.vue.d.ts +44 -0
  152. package/dist/vue/components/CanvasSurface.vue.d.ts +11 -0
  153. package/dist/vue/components/CodeEditor.vue.d.ts +22 -0
  154. package/dist/vue/components/EditorBlockMenus.vue.d.ts +3 -0
  155. package/dist/vue/components/EditorBlockPalette.vue.d.ts +3 -0
  156. package/dist/vue/components/EditorDiagnostics.vue.d.ts +3 -0
  157. package/dist/vue/components/EditorDialogs.vue.d.ts +16 -0
  158. package/dist/vue/components/EditorDocumentMetadata.vue.d.ts +3 -0
  159. package/dist/vue/components/EditorDocumentStyles.vue.d.ts +15 -0
  160. package/dist/vue/components/EditorImageSizeControls.vue.d.ts +23 -0
  161. package/dist/vue/components/EditorLayoutControls.vue.d.ts +16 -0
  162. package/dist/vue/components/EditorLeftPanel.vue.d.ts +3 -0
  163. package/dist/vue/components/EditorNoticeIndicator.vue.d.ts +3 -0
  164. package/dist/vue/components/EditorPreview.vue.d.ts +8 -0
  165. package/dist/vue/components/EditorProperties.vue.d.ts +14 -0
  166. package/dist/vue/components/EditorRichTextControls.vue.d.ts +25 -0
  167. package/dist/vue/components/EditorSelectionPath.vue.d.ts +11 -0
  168. package/dist/vue/components/EditorShortcutHelp.vue.d.ts +3 -0
  169. package/dist/vue/components/EditorSourcePane.vue.d.ts +3 -0
  170. package/dist/vue/components/EditorStructureTree.vue.d.ts +3 -0
  171. package/dist/vue/components/EditorTemplateGallery.vue.d.ts +15 -0
  172. package/dist/vue/components/EditorTopBar.vue.d.ts +33 -0
  173. package/dist/vue/components/RichTextEditor.vue.d.ts +47 -0
  174. package/dist/vue/components/SelectionPreviewFrame.vue.d.ts +212 -0
  175. package/dist/vue/components/VisualEditor.vue.d.ts +53 -0
  176. package/dist/vue/components/blocks/BlockCanvas.vue.d.ts +15 -0
  177. package/dist/vue/components/blocks/BlockFieldControl.vue.d.ts +39 -0
  178. package/dist/vue/components/blocks/BlockGlobalStyles.vue.d.ts +3 -0
  179. package/dist/vue/components/blocks/BlockPalette.vue.d.ts +6 -0
  180. package/dist/vue/components/blocks/BlockProperties.vue.d.ts +5 -0
  181. package/dist/vue/components/blocks/BlockReview.vue.d.ts +5 -0
  182. package/dist/vue/components/properties/EditorPropertyAdvanced.vue.d.ts +8 -0
  183. package/dist/vue/components/properties/EditorPropertyContent.vue.d.ts +13 -0
  184. package/dist/vue/components/properties/EditorPropertyStyle.vue.d.ts +8 -0
  185. package/dist/vue/components/ui/EditorAnchoredMenu.vue.d.ts +36 -0
  186. package/dist/vue/components/ui/EditorBadge.vue.d.ts +18 -0
  187. package/dist/vue/components/ui/EditorButton.vue.d.ts +28 -0
  188. package/dist/vue/components/ui/EditorCheckbox.vue.d.ts +13 -0
  189. package/dist/vue/components/ui/EditorColorInput.vue.d.ts +27 -0
  190. package/dist/vue/components/ui/EditorConfirmDialog.vue.d.ts +35 -0
  191. package/dist/vue/components/ui/EditorContextMenu.vue.d.ts +27 -0
  192. package/dist/vue/components/ui/EditorContextPopover.vue.d.ts +33 -0
  193. package/dist/vue/components/ui/EditorEmpty.vue.d.ts +8 -0
  194. package/dist/vue/components/ui/EditorField.vue.d.ts +24 -0
  195. package/dist/vue/components/ui/EditorGroup.vue.d.ts +16 -0
  196. package/dist/vue/components/ui/EditorIcon.vue.d.ts +6 -0
  197. package/dist/vue/components/ui/EditorIconButton.vue.d.ts +19 -0
  198. package/dist/vue/components/ui/EditorInput.vue.d.ts +41 -0
  199. package/dist/vue/components/ui/EditorKeys.vue.d.ts +6 -0
  200. package/dist/vue/components/ui/EditorMeasurement.vue.d.ts +34 -0
  201. package/dist/vue/components/ui/EditorMenu.vue.d.ts +56 -0
  202. package/dist/vue/components/ui/EditorNotice.vue.d.ts +30 -0
  203. package/dist/vue/components/ui/EditorPropertyGroup.vue.d.ts +22 -0
  204. package/dist/vue/components/ui/EditorRecoveryDialog.vue.d.ts +23 -0
  205. package/dist/vue/components/ui/EditorScrollArea.vue.d.ts +13 -0
  206. package/dist/vue/components/ui/EditorSelect.vue.d.ts +25 -0
  207. package/dist/vue/components/ui/EditorSeparator.vue.d.ts +8 -0
  208. package/dist/vue/components/ui/EditorSidePanel.vue.d.ts +26 -0
  209. package/dist/vue/components/ui/EditorSwitch.vue.d.ts +12 -0
  210. package/dist/vue/components/ui/EditorTabs.vue.d.ts +28 -0
  211. package/dist/vue/components/ui/EditorTemplatePreview.vue.d.ts +9 -0
  212. package/dist/vue/components/ui/EditorTextToolbar.vue.d.ts +16 -0
  213. package/dist/vue/components/ui/EditorTree.vue.d.ts +37 -0
  214. package/dist/vue/components/ui/EditorUiProvider.vue.d.ts +13 -0
  215. package/dist/vue/components/ui/EditorVariablePicker.vue.d.ts +20 -0
  216. package/dist/vue/components/ui/color-style-value.d.ts +9 -0
  217. package/dist/vue/components/ui/composition-dismissal.d.ts +1 -0
  218. package/dist/vue/components/ui/editor-dialog-focus.d.ts +6 -0
  219. package/dist/vue/components/ui/numeric-style-value.d.ts +15 -0
  220. package/dist/vue/controller.d.ts +115 -0
  221. package/dist/vue/font-options.d.ts +6 -0
  222. package/dist/vue/icon-data.d.ts +233 -0
  223. package/dist/vue/icons.d.ts +5 -0
  224. package/dist/vue/locale.d.ts +7 -0
  225. package/dist/vue/outline.d.ts +26 -0
  226. package/dist/vue/projection-key.d.ts +7 -0
  227. package/dist/vue/properties/selection-properties.d.ts +40 -0
  228. package/dist/vue/properties/style-fields.d.ts +30 -0
  229. package/dist/vue/public.d.ts +14 -0
  230. package/dist/vue/recovery.d.ts +30 -0
  231. package/dist/vue/responsive-panel.d.ts +1 -0
  232. package/dist/vue/rich-text-commands.d.ts +29 -0
  233. package/dist/vue/services/block-command-definitions.d.ts +14 -0
  234. package/dist/vue/services/block-commands.d.ts +114 -0
  235. package/dist/vue/services/block-menu.d.ts +12 -0
  236. package/dist/vue/services/block-palette.d.ts +21 -0
  237. package/dist/vue/services/block-presentation.d.ts +16 -0
  238. package/dist/vue/services/diagnostic-groups.d.ts +25 -0
  239. package/dist/vue/services/image-requests.d.ts +80 -0
  240. package/dist/vue/services/live-change.d.ts +26 -0
  241. package/dist/vue/services/property-commands.d.ts +28 -0
  242. package/dist/vue/services/saved-blocks.d.ts +32 -0
  243. package/dist/vue/services/selection-path.d.ts +20 -0
  244. package/dist/vue/services/shortcuts.d.ts +39 -0
  245. package/dist/vue/services/structure-tree.d.ts +38 -0
  246. package/dist/vue/services/template-application.d.ts +33 -0
  247. package/dist/vue/services/tree-drag.d.ts +28 -0
  248. package/dist/vue/session/blocks.d.ts +44 -0
  249. package/dist/vue/session/guard.d.ts +13 -0
  250. package/dist/vue/session/structure.d.ts +36 -0
  251. package/dist/vue/session/text.d.ts +23 -0
  252. package/dist/vue/session/transfer.d.ts +23 -0
  253. package/dist/vue/theme.d.ts +20 -0
  254. package/dist/vue/variables.d.ts +21 -0
  255. package/dist/vue/workbench.d.ts +100 -0
  256. package/dist/vue.js +71418 -0
  257. package/dist/vue.js.map +1 -0
  258. package/package.json +125 -4
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generated-mjml-CtzE-f3v.js","names":["DocumentBudget","HtmlContentModel","serializeOuter","defaultTreeAdapter","DOCUMENT_LIMITS","BlockCatalog","parseFragment","NS","BoundedHtmlParser","CssDocumentCodec","UrlPolicy","SecureIdentifier","serialize","DocumentValidationError","DocumentBudgetError","HTML_VOID_ELEMENTS","EditorDocument","EMBEDS","URL_ATTRIBUTES","ANIMATIONS","ANIMATION_VALUES","ENGINE_HANDLER","HANDLERS","event","ActiveMarkupRules","urls","name","tag","attrs","key","value","attributes","content","separator","target","attribute","character","SOURCE_CONTEXTS","isConditionalComment","RAW_TEXT","ROUNDS","SourceMarkup","rules","styles","source","context","element","child","current","removed","round","cuts","merged","cut","left","right","last","output","cursor","elements","location","kind","whole","finding","position","sheet","options","locations","fragment","#parser","stack","count","node","children","index","entry","EXECUTABLE_TYPES","ContentInspector","#css","css","#rules","#sources","sources","input","tally","document","text","owner","mark","topic","active","type","rel","reference","charset","style","hint","survey","part","url","parsed","UTF8_CONTENT_TYPE","EmailSanitizer","#styles","stripped","cleaned","nodes","i","next","changed","candidate","parameter","ContentPolicyError","diagnostics","HTML_NAMESPACE","FOREIGN_ROOTS","REMOVAL_CODES","REFUSAL_CODES","ContentPolicy","#urls","#inspector","#emails","error","removal","diagnostic","result","purpose","notices","add","code","nodeId","inventory","anchors","opener","identifiers","first","grouped","existing","FEATURES","COMPARISONS","EXPRESSION_OPERATORS","MAX_EXPRESSION_LENGTH","DownlevelRevealedConditional","open","comments","tokens","expression","word","start","inner","parts","digit","LEADING_NEWLINE_ELEMENTS","TABLE_PARTS","WIDE_FRAGMENT_NODES","HtmlDocumentCodec","cacheSize","#policy","policy","#catalog","catalog","#cacheSize","previous","settled","#budget","markup","kept","parsedNodes","draft","sanitized","regions","pending","frame","slice","slices","remember","roots","counted","total","contained","convert","depth","id","metadata","converted","island","descriptor","#conditionals","located","end","aggregate","record","#records","#exported","fingerprint","preserved","html","failure","#model","closed","offset","region","quote","publicId","systemId","declaration","template","written","skeleton","closing","opening","restoresNewline","flow","root","section","nested","prefix","#instanceId","#nextId","candidates","fingerprints","previousStack","known","currentStack","used","cursors","unused","list","reconcile","previousAtPosition","#digests","digest","second","faithful","weight","#cacheCharacters","sum","ids","oldest","COMPILE_LIMITS","FORBIDDEN","RAW_CELL_CLASS","RAW_CELL_STYLE","CompilationGuard","allowed","fragments","parent","row","cell","MJML_OPTIONS","GeneratedMjml","readCompileRequest","request"],"sources":["../src/security/markup-rules.ts","../src/security/source-markup.ts","../src/security/content-inventory.ts","../src/security/email-sanitizer.ts","../src/security/policy.ts","../src/security/conditional-comment.ts","../src/codecs/html.ts","../src/compilation/guard.ts","../src/compilation/generated-mjml.ts"],"sourcesContent":["import { UrlPolicy } from './url-policy';\n\n/** What an e-mail may not carry and a page is merely told it carries. */\nexport type ActiveMarkup = 'script' | 'embed' | 'handler' | 'url' | 'style';\n\n/** Elements which bring another document or program into the one which holds them. */\nconst EMBEDS: ReadonlySet<string> = new Set([\n 'iframe',\n 'object',\n 'embed',\n 'applet',\n 'frame',\n 'portal',\n 'fencedframe',\n]);\nconst URL_ATTRIBUTES: ReadonlySet<string> = new Set([\n 'href',\n 'src',\n 'action',\n 'formaction',\n 'background',\n 'poster',\n 'cite',\n 'longdesc',\n 'xlink:href',\n 'lowsrc',\n 'dynsrc',\n 'data',\n 'codebase',\n 'ping',\n 'manifest',\n]);\n/** SMIL elements which write an attribute of the element they animate. */\nconst ANIMATIONS: ReadonlySet<string> = new Set([\n 'set',\n 'animate',\n 'animatetransform',\n 'animatemotion',\n 'animatecolor',\n]);\nconst ANIMATION_VALUES: readonly string[] = ['to', 'from', 'by', 'values'];\n/**\n * The event handler content attributes of HTML, SVG and the old engines mail programs still\n * embed. A closed list: an attribute an author named `onboarding` is not a handler.\n */\n/**\n * Handlers outside the list which engines add under a prefix of their own (`onwebkit…`,\n * `onmoz…`, `onms…`) or as a `before`/`after` pair. Matching the shape keeps a future one of\n * these families out without treating an ordinary attribute such as `onboarding` as a handler.\n */\nconst ENGINE_HANDLER = /^on(?:webkit|moz|ms|before|after)[a-z]+$/;\n\nconst HANDLERS: ReadonlySet<string> = new Set(\n (\n 'abort activate afterprint afterscriptexecute afterupdate animationcancel animationend ' +\n 'animationiteration animationstart auxclick beforeactivate beforecopy beforecut ' +\n 'beforedeactivate beforeeditfocus beforeinput beforematch beforepaste beforeprint ' +\n 'beforescriptexecute beforetoggle beforeunload beforeupdate begin blur bounce cancel canplay ' +\n 'canplaythrough cellchange change click close command contentvisibilityautostatechange ' +\n 'contextlost contextmenu contextrestored controlselect copy cuechange cut dataavailable ' +\n 'datasetchanged datasetcomplete dblclick deactivate drag dragend dragenter dragexit ' +\n 'dragleave dragover dragstart drop durationchange emptied end ended error errorupdate ' +\n 'filterchange finish focus focusin focusout formdata fullscreenchange fullscreenerror ' +\n 'gesturechange gestureend gesturestart gotpointercapture hashchange help input invalid ' +\n 'keydown keypress keyup languagechange layoutcomplete load loadeddata loadedmetadata ' +\n 'loadstart losecapture lostpointercapture message messageerror mousedown mouseenter ' +\n 'mouseleave mousemove mouseout mouseover mouseup mousewheel move moveend movestart offline ' +\n 'online pagehide pagereveal pageshow pageswap paste pause play playing pointercancel ' +\n 'pointerdown pointerenter pointerleave pointerlockchange pointerlockerror pointermove ' +\n 'pointerout pointerover pointerrawupdate pointerup popstate progress propertychange ' +\n 'ratechange readystatechange rejectionhandled repeat reset resize resizeend resizestart ' +\n 'rowenter rowexit rowsdelete rowsinserted scroll scrollend scrollsnapchange ' +\n 'scrollsnapchanging search securitypolicyviolation seeked seeking select selectionchange ' +\n 'selectstart show slotchange stalled start stop storage submit suspend timeupdate toggle ' +\n 'touchcancel touchend touchmove touchstart transitioncancel transitionend transitionrun ' +\n 'transitionstart unhandledrejection unload volumechange waiting webkitanimationend ' +\n 'webkitanimationiteration webkitanimationstart webkitfullscreenchange ' +\n 'webkitfullscreenerror webkittransitionend wheel zoom'\n )\n .split(' ')\n .map((event) => `on${event}`),\n);\n\n/**\n * One classification of markup which runs or loads code, shared by the inventory, the e-mail\n * sanitizer and the scan of source kept as text. It decides nothing about publication.\n */\nexport class ActiveMarkupRules {\n constructor(private readonly urls = new UrlPolicy()) {}\n\n element(tag: string): Extract<ActiveMarkup, 'script' | 'embed'> | undefined {\n const name = tag.toLowerCase();\n if (name === 'script') return 'script';\n return EMBEDS.has(name) ? 'embed' : undefined;\n }\n\n /**\n * An element which is only active because of what its attributes say together: an HTML\n * import, a refresh to a code address, an animation which writes a code address into a link.\n */\n elementWith(\n tag: string,\n attributes: Readonly<Record<string, string>>,\n ): Extract<ActiveMarkup, 'embed' | 'url'> | undefined {\n const name = tag.toLowerCase();\n const attrs: Record<string, string> = Object.create(null) as Record<string, string>;\n for (const [key, value] of Object.entries(attributes)) attrs[key.toLowerCase()] = value;\n if (name === 'link' && (attrs.rel ?? '').toLowerCase().split(/\\s+/).includes('import'))\n return 'embed';\n if (name === 'meta' && (attrs['http-equiv'] ?? '').trim().toLowerCase() === 'refresh') {\n // `5; url=address`, with or without the name, quotes and spaces.\n const content = attrs.content ?? '';\n const separator = content.search(/[;,]/);\n let target = separator < 0 ? '' : content.slice(separator + 1).trim();\n if (/^url\\s*=/i.test(target)) target = target.slice(target.indexOf('=') + 1).trim();\n target = target.replace(/^['\"]/, '');\n return this.urls.isActive(target) ? 'url' : undefined;\n }\n if (\n ANIMATIONS.has(name) &&\n ['href', 'xlink:href'].includes((attrs.attributename ?? '').trim().toLowerCase()) &&\n ANIMATION_VALUES.some((key) =>\n (attrs[key] ?? '').split(';').some((value) => this.urls.isActive(value)),\n )\n )\n return 'url';\n return undefined;\n }\n\n /**\n * What sends an e-mail somewhere else or changes where its addresses point: any refresh\n * (with or without a target) and any `base`. Removed from e-mails and never written by the\n * editor; a page keeps them, as its author wrote them.\n */\n navigation(tag: string, attributes: Readonly<Record<string, string>>): 'url' | undefined {\n const name = tag.toLowerCase();\n if (name === 'base') return 'url';\n if (name !== 'meta') return undefined;\n const directive = Object.entries(attributes).find(\n ([key]) => key.toLowerCase() === 'http-equiv',\n )?.[1];\n return directive?.trim().toLowerCase() === 'refresh' ? 'url' : undefined;\n }\n\n attribute(name: string, value: string): Extract<ActiveMarkup, 'handler' | 'url'> | undefined {\n const attribute = name.toLowerCase();\n if (HANDLERS.has(attribute) || ENGINE_HANDLER.test(attribute)) return 'handler';\n return URL_ATTRIBUTES.has(attribute) && this.urls.isActive(value) ? 'url' : undefined;\n }\n\n /**\n * `on` followed by letters only, as every handler is and as any future one will be. The rule\n * for what the editor itself writes, which never needs an attribute of that shape.\n */\n handlerLike(name: string): boolean {\n const attribute = name.toLowerCase();\n if (attribute.length < 3 || !attribute.startsWith('on')) return false;\n return [...attribute.slice(2)].every((character) => character >= 'a' && character <= 'z');\n }\n\n /** URL attributes and what each loads, for the strict rule of what the editor writes. */\n urlPurpose(name: string): 'link' | 'image' | undefined {\n const attribute = name.toLowerCase();\n if (!URL_ATTRIBUTES.has(attribute)) return undefined;\n return ['src', 'background', 'poster', 'lowsrc', 'dynsrc'].includes(attribute)\n ? 'image'\n : 'link';\n }\n}\n","import { defaultTreeAdapter, html } from 'parse5';\nimport type { DefaultTreeAdapterMap } from 'parse5';\nimport { DocumentBudget } from '../core/budget';\nimport { BoundedHtmlParser } from './bounded-parser';\nimport { ActiveMarkupRules } from './markup-rules';\nimport type { ActiveMarkup } from './markup-rules';\n\n/** Where a block of source kept as text would be parsed by whoever renders it. */\nexport type SourceContext = 'html' | 'svg' | 'math';\n\n/** The elements whose content the document keeps as source, and how that source is read. */\nexport const SOURCE_CONTEXTS: Readonly<Record<string, SourceContext>> = Object.freeze({\n noscript: 'html',\n noembed: 'html',\n noframes: 'html',\n template: 'html',\n svg: 'svg',\n math: 'math',\n});\n\n/** A conditional comment hides markup which Outlook, or an old browser, does render. */\nexport function isConditionalComment(value: string): boolean {\n return value.trimStart().toLowerCase().startsWith('[if');\n}\n\n/** Active CSS is removed from a style attribute or sheet; absent, styles are left as written. */\nexport interface ActiveStyleRemover {\n stripActive(\n css: string,\n context?: 'stylesheet' | 'declarationList',\n ): { readonly css: string; readonly removed: number };\n}\n\nexport interface SourceElement {\n readonly tag: string;\n readonly attrs: Readonly<Record<string, string>>;\n /** Text directly inside the element, e.g. the code of an inline script. */\n readonly text: string;\n}\n\nexport interface StrippedSource {\n readonly source: string;\n readonly removed: readonly ActiveMarkup[];\n}\n\ninterface Cut {\n readonly start: number;\n readonly end: number;\n readonly kind: ActiveMarkup;\n}\n\ntype Element = DefaultTreeAdapterMap['element'];\n\nconst RAW_TEXT: ReadonlySet<string> = new Set(['script', 'iframe']);\nconst ROUNDS = 4;\n\n/**\n * Reads markup the document keeps as text: conditional comments, `noscript`, `template` and\n * inline SVG or MathML. It is parsed only to be inspected; what is not removed stays byte for\n * byte, because these blocks are often unbalanced fragments no serializer would reproduce.\n */\nexport class SourceMarkup {\n /** A block nests no deeper than a document may: beyond that the parse ends with its error. */\n readonly #parser = new BoundedHtmlParser();\n\n constructor(\n private readonly rules = new ActiveMarkupRules(),\n private readonly styles?: ActiveStyleRemover,\n ) {}\n\n /**\n * Every element in the block, nested templates included. Empty when it has too many nodes;\n * throws `DOCUMENT_TOO_DEEP` when it nests beyond the limit of a document.\n */\n elements(source: string, context: SourceContext = 'html'): readonly SourceElement[] {\n return (\n this.walk(source, context, false)?.map((element) => ({\n tag: element.tagName,\n attrs: Object.fromEntries(\n element.attrs.map((attribute) => [this.name(attribute), attribute.value]),\n ),\n text: element.childNodes\n .map((child) => (defaultTreeAdapter.isTextNode(child) ? child.value : ''))\n .join(''),\n })) ?? []\n );\n }\n\n /**\n * Cuts scripts, embeds, inline handlers and code URLs out of the text by their source\n * positions and checks the result again. Undefined when it could not be made clean: the\n * caller then drops the whole block rather than keep something it cannot vouch for.\n */\n strip(source: string, context: SourceContext = 'html'): StrippedSource | undefined {\n let current = source;\n const removed: ActiveMarkup[] = [];\n for (let round = 0; round < ROUNDS; round++) {\n const cuts = this.cuts(current, context);\n if (!cuts) return undefined;\n if (!cuts.length) return { source: current, removed };\n const merged: Cut[] = [];\n for (const cut of [...cuts].sort((left, right) => left.start - right.start)) {\n const last = merged.at(-1);\n if (last && cut.start < last.end)\n merged[merged.length - 1] = { ...last, end: Math.max(last.end, cut.end) };\n else merged.push(cut);\n }\n let output = '';\n let cursor = 0;\n for (const cut of merged) {\n output += current.slice(cursor, cut.start);\n cursor = cut.end;\n removed.push(cut.kind);\n }\n current = output + current.slice(cursor);\n }\n return undefined;\n }\n\n private cuts(source: string, context: SourceContext): readonly Cut[] | undefined {\n const elements = this.walk(source, context, true);\n if (!elements) return undefined;\n const cuts: Cut[] = [];\n for (const element of elements) {\n const location = element.sourceCodeLocation;\n const kind =\n this.rules.element(element.tagName) ??\n this.rules.elementWith(element.tagName, this.attributes(element)) ??\n this.rules.navigation(element.tagName, this.attributes(element)) ??\n this.activeSheet(element);\n if (kind) {\n // Without positions the element cannot be cut: the block is not kept at all.\n if (!location) return undefined;\n const whole =\n location.endTag ||\n (element.namespaceURI === html.NS.HTML && RAW_TEXT.has(element.tagName));\n cuts.push({\n kind,\n start: location.startOffset,\n end: whole ? location.endOffset : (location.startTag?.endOffset ?? location.endOffset),\n });\n continue;\n }\n for (const attribute of element.attrs) {\n const name = this.name(attribute);\n const finding =\n this.rules.attribute(name, attribute.value) ??\n (name.toLowerCase() === 'style' &&\n this.styles?.stripActive(attribute.value, 'declarationList').removed\n ? ('style' as const)\n : undefined);\n if (!finding) continue;\n const position = Object.entries(location?.attrs ?? {}).find(\n ([key]) => key.toLowerCase() === name.toLowerCase(),\n )?.[1];\n if (!position) return undefined;\n cuts.push({ kind: finding, start: position.startOffset, end: position.endOffset });\n }\n }\n return cuts;\n }\n\n /** A style sheet inside the block which holds active CSS leaves whole. */\n private activeSheet(element: Element): 'style' | undefined {\n if (element.tagName !== 'style' || !this.styles) return undefined;\n const sheet = element.childNodes\n .map((child) => (defaultTreeAdapter.isTextNode(child) ? child.value : ''))\n .join('');\n return this.styles.stripActive(sheet).removed ? 'style' : undefined;\n }\n\n private walk(\n source: string,\n context: SourceContext,\n locations: boolean,\n ): readonly Element[] | undefined {\n const options = { sourceCodeLocationInfo: locations, scriptingEnabled: false };\n const fragment =\n context === 'html'\n ? this.#parser.fragment(source, options)\n : this.#parser.fragment(\n source,\n options,\n defaultTreeAdapter.createElement(\n context,\n context === 'svg' ? html.NS.SVG : html.NS.MATHML,\n [],\n ),\n );\n const elements: Element[] = [];\n const stack = [...fragment.childNodes].reverse();\n let count = 0;\n while (stack.length) {\n const node = stack.pop();\n if (!node) break;\n if (++count > DocumentBudget.limits.totalNodes) return undefined;\n if (!defaultTreeAdapter.isElementNode(node)) continue;\n elements.push(node);\n const children = 'content' in node ? node.content.childNodes : node.childNodes;\n for (let index = children.length - 1; index >= 0; index--) {\n const child = children[index];\n if (child) stack.push(child);\n }\n }\n return elements;\n }\n\n private attributes(element: {\n readonly attrs: readonly {\n readonly name: string;\n readonly prefix?: string;\n readonly value: string;\n }[];\n }): Readonly<Record<string, string>> {\n return Object.fromEntries(element.attrs.map((entry) => [this.name(entry), entry.value]));\n }\n\n private name(attribute: { readonly name: string; readonly prefix?: string }): string {\n return attribute.prefix ? `${attribute.prefix}:${attribute.name}` : attribute.name;\n }\n}\n","import { CssDocumentCodec } from '../codecs/css';\nimport { EditorDocument } from '../core/document';\nimport type { DocumentKind, DocumentNode, EditorDocumentData } from '../core/document';\nimport { ActiveMarkupRules } from './markup-rules';\nimport { isConditionalComment, SOURCE_CONTEXTS, SourceMarkup } from './source-markup';\nimport type { SourceContext } from './source-markup';\n\n/** A resource the document points to. `origin` is absent for relative URLs and merge tags. */\nexport interface ExternalReference {\n readonly url: string;\n readonly origin?: string;\n}\n\n/**\n * What a document contains that a publisher may want to decide about. The package reports;\n * the host applies its own rule. Counts include markup kept as source (conditional comments,\n * `noscript`, `template`, inline SVG).\n */\nexport interface ContentInventory {\n readonly kind: DocumentKind;\n readonly scripts: {\n /** Executable scripts written in the document. */\n readonly inline: number;\n /** Executable scripts loaded by `src`. */\n readonly external: readonly ExternalReference[];\n /** `<script>` data blocks such as JSON-LD, which browsers do not run. */\n readonly data: number;\n };\n /** `iframe` and `frame` sources. */\n readonly frames: readonly ExternalReference[];\n /** `object`, `embed` and `applet` elements. */\n readonly embeds: number;\n /** `<link rel=\"stylesheet\">` and `@import` targets. */\n readonly stylesheets: readonly ExternalReference[];\n /** Every other `<link>`: fonts preconnect, icons, preloads. */\n readonly links: readonly (ExternalReference & { readonly rel: string })[];\n readonly forms: { readonly count: number; readonly actions: readonly ExternalReference[] };\n /** `on*` attributes. */\n readonly inlineHandlers: number;\n /** `javascript:`, `vbscript:` and `data:` document URLs in attributes. */\n readonly scriptUrls: number;\n readonly metaRefresh: number;\n readonly baseUrls: readonly string[];\n /** Encodings declared by `<meta>`, lower case, as written. */\n readonly charsets: readonly string[];\n readonly fontFaces: number;\n /** `expression()`, `behavior`, `-moz-binding` and code URLs inside CSS. */\n readonly activeCss: number;\n}\n\nexport type InventoryTopic = 'script' | 'embed' | 'stylesheet' | 'form' | 'handler' | 'charset';\n\nexport interface ContentSurvey {\n readonly inventory: ContentInventory;\n /** First document node of each topic, for a notice which can point at it. */\n readonly anchors: Readonly<Partial<Record<InventoryTopic, string>>>;\n}\n\nconst EXECUTABLE_TYPES: ReadonlySet<string> = new Set([\n '',\n 'module',\n 'text/javascript',\n 'application/javascript',\n 'application/x-javascript',\n 'text/ecmascript',\n 'application/ecmascript',\n 'text/jscript',\n 'text/livescript',\n 'text/javascript1.0',\n 'text/javascript1.1',\n 'text/javascript1.2',\n 'text/javascript1.3',\n 'text/javascript1.4',\n 'text/javascript1.5',\n 'text/x-javascript',\n 'text/x-ecmascript',\n]);\n\ninterface Tally {\n inline: number;\n data: number;\n external: ExternalReference[];\n frames: ExternalReference[];\n embeds: number;\n stylesheets: ExternalReference[];\n links: (ExternalReference & { rel: string })[];\n forms: number;\n actions: ExternalReference[];\n inlineHandlers: number;\n scriptUrls: number;\n metaRefresh: number;\n baseUrls: string[];\n charsets: string[];\n fontFaces: number;\n activeCss: number;\n anchors: Partial<Record<InventoryTopic, string>>;\n}\n\n/** Builds the typed inventory of a document. It never changes or refuses anything. */\nexport class ContentInspector {\n readonly #css: CssDocumentCodec;\n readonly #rules: ActiveMarkupRules;\n readonly #sources: SourceMarkup;\n\n constructor(css: CssDocumentCodec, rules: ActiveMarkupRules, sources = new SourceMarkup(rules)) {\n this.#css = css;\n this.#rules = rules;\n this.#sources = sources;\n }\n\n inspect(input: EditorDocumentData): ContentInventory {\n return this.survey(EditorDocument.from(input).snapshot()).inventory;\n }\n\n /** The caller hands in a snapshot which already passed `EditorDocument.from`. */\n survey(document: EditorDocumentData): ContentSurvey {\n const tally: Tally = {\n inline: 0,\n data: 0,\n external: [],\n frames: [],\n embeds: 0,\n stylesheets: [],\n links: [],\n forms: 0,\n actions: [],\n inlineHandlers: 0,\n scriptUrls: 0,\n metaRefresh: 0,\n baseUrls: [],\n charsets: [],\n fontFaces: 0,\n activeCss: 0,\n anchors: {},\n };\n this.stylesheet(document.css, tally, undefined);\n const stack = [...document.nodes].reverse();\n while (stack.length) {\n const node = stack.pop();\n if (!node) break;\n if (node.type === 'comment' && this.conditional(node.value ?? ''))\n this.source(node.value ?? '', 'html', tally, node.id);\n if (node.type !== 'element') continue;\n const tag = (node.tag ?? '').toLowerCase();\n const text = this.text(node);\n this.element(tag, node.attrs ?? {}, text, tally, node.id);\n if (tag === 'style') this.stylesheet(text, tally, node.id);\n const context = SOURCE_CONTEXTS[tag];\n if (context) this.source(text, context, tally, node.id);\n const children = node.children ?? [];\n for (let index = children.length - 1; index >= 0; index--) {\n const child = children[index];\n if (child) stack.push(child);\n }\n }\n return {\n anchors: tally.anchors,\n inventory: {\n kind: document.kind,\n scripts: { inline: tally.inline, external: tally.external, data: tally.data },\n frames: tally.frames,\n embeds: tally.embeds,\n stylesheets: tally.stylesheets,\n links: tally.links,\n forms: { count: tally.forms, actions: tally.actions },\n inlineHandlers: tally.inlineHandlers,\n scriptUrls: tally.scriptUrls,\n metaRefresh: tally.metaRefresh,\n baseUrls: tally.baseUrls,\n charsets: tally.charsets,\n fontFaces: tally.fontFaces,\n activeCss: tally.activeCss,\n },\n };\n }\n\n /** A conditional comment hides markup which Outlook, or an old browser, does render. */\n conditional(value: string): boolean {\n return isConditionalComment(value);\n }\n\n private source(text: string, context: SourceContext, tally: Tally, owner: string): void {\n for (const element of this.#sources.elements(text, context)) {\n const tag = element.tag.toLowerCase();\n this.element(tag, element.attrs, element.text, tally, owner);\n if (tag === 'style') this.stylesheet(element.text, tally, owner);\n }\n }\n\n private element(\n tag: string,\n attributes: Readonly<Record<string, string>>,\n text: string,\n tally: Tally,\n owner: string,\n ): void {\n const attrs: Record<string, string> = Object.create(null) as Record<string, string>;\n for (const [name, value] of Object.entries(attributes)) attrs[name.toLowerCase()] = value;\n const mark = (topic: InventoryTopic): void => {\n tally.anchors[topic] ??= owner;\n };\n const active = this.#rules.element(tag);\n // A refresh to a code address or an animation which writes one into a link is a code URL.\n if (this.#rules.elementWith(tag, attributes) === 'url') {\n tally.scriptUrls++;\n mark('handler');\n }\n if (active === 'script') {\n const type = (attrs.type ?? '').trim().toLowerCase().split(';', 1)[0] ?? '';\n if (!EXECUTABLE_TYPES.has(type.trim())) tally.data++;\n else {\n if (attrs.src !== undefined) tally.external.push(this.reference(attrs.src));\n else if (text.trim()) tally.inline++;\n mark('script');\n }\n } else if (active === 'embed') {\n if (tag === 'iframe' || tag === 'frame') tally.frames.push(this.reference(attrs.src ?? ''));\n else tally.embeds++;\n mark('embed');\n }\n if (tag === 'link') {\n const rel = (attrs.rel ?? '').trim().toLowerCase();\n const reference = this.reference(attrs.href ?? '');\n if (rel.split(/\\s+/).includes('stylesheet')) {\n tally.stylesheets.push(reference);\n mark('stylesheet');\n } else tally.links.push({ ...reference, rel });\n }\n if (tag === 'form') {\n tally.forms++;\n if (attrs.action !== undefined) tally.actions.push(this.reference(attrs.action));\n mark('form');\n }\n if (tag === 'base' && attrs.href !== undefined) tally.baseUrls.push(attrs.href);\n if (tag === 'meta') {\n const charset = this.declaredCharset(attrs);\n if (charset !== undefined) {\n tally.charsets.push(charset);\n if (charset !== 'utf-8') mark('charset');\n }\n if ((attrs['http-equiv'] ?? '').trim().toLowerCase() === 'refresh') tally.metaRefresh++;\n }\n for (const [name, value] of Object.entries(attrs)) {\n const finding = this.#rules.attribute(name, value);\n if (finding === 'handler') tally.inlineHandlers++;\n if (finding === 'url') tally.scriptUrls++;\n if (finding) mark('handler');\n if (name === 'style' && this.mayBeActive(value))\n tally.activeCss += this.#css.survey(value, 'declarationList').active;\n }\n }\n\n /**\n * Most inline styles are plain declarations. Only one which could hold what the survey\n * counts (a URL, a legacy expression or binding, or an escape hiding either) is parsed.\n */\n private mayBeActive(style: string): boolean {\n const value = style.toLowerCase();\n return ['url', 'expression', 'behavior', 'binding', '\\\\'].some((hint) => value.includes(hint));\n }\n\n private stylesheet(css: string, tally: Tally, owner: string | undefined): void {\n const survey = this.#css.survey(css);\n tally.fontFaces += survey.fontFaces;\n tally.activeCss += survey.active;\n for (const target of survey.imports) {\n tally.stylesheets.push(this.reference(target));\n if (owner) tally.anchors.stylesheet ??= owner;\n }\n }\n\n /** The encoding a `<meta>` declares, by either syntax; undefined when it declares none. */\n declaredCharset(attrs: Readonly<Record<string, string>>): string | undefined {\n if (attrs.charset !== undefined) return attrs.charset.trim().toLowerCase();\n if ((attrs['http-equiv'] ?? '').trim().toLowerCase() !== 'content-type') return undefined;\n for (const part of (attrs.content ?? '').split(';')) {\n const [name, value] = part.split('=');\n if (name?.trim().toLowerCase() === 'charset' && value !== undefined)\n return value.trim().toLowerCase();\n }\n return undefined;\n }\n\n private reference(url: string): ExternalReference {\n const value = url.trim();\n try {\n const parsed = new URL(value.startsWith('//') ? `https:${value}` : value);\n return parsed.protocol === 'https:' || parsed.protocol === 'http:'\n ? { url: value, origin: parsed.origin }\n : { url: value };\n } catch {\n return { url: value };\n }\n }\n\n private text(node: DocumentNode): string {\n return (node.children ?? [])\n .map((child) => (child.type === 'text' ? (child.value ?? '') : ''))\n .join('');\n }\n}\n","import type { DocumentNode } from '../core/document';\nimport { ActiveMarkupRules } from './markup-rules';\nimport type { ActiveMarkup } from './markup-rules';\nimport { isConditionalComment, SOURCE_CONTEXTS, SourceMarkup } from './source-markup';\nimport type { ActiveStyleRemover, SourceContext } from './source-markup';\n\n/** What was taken out of an e-mail, or rewritten in it. */\nexport type EmailRemoval = ActiveMarkup | 'charset';\n\nexport interface SanitizedEmail {\n readonly nodes: readonly DocumentNode[];\n /** One entry per occurrence; empty when the tree is returned untouched. */\n readonly removed: readonly EmailRemoval[];\n}\n\nconst UTF8_CONTENT_TYPE = 'text/html; charset=utf-8';\n\n/**\n * An e-mail never carries scripts, embedded documents, inline handlers, code URLs, CSS which\n * would run code, a refresh or a `base`: no client runs them and several\n * reject the whole message. They are removed,\n * never refused. Elements leave with their content; an attribute leaves and its element stays;\n * a declaration leaves and the rest of its style stays. Everything else, conditional comments\n * and VML included, is kept as written.\n */\nexport class EmailSanitizer {\n readonly #rules: ActiveMarkupRules;\n readonly #sources: SourceMarkup;\n readonly #styles: ActiveStyleRemover | undefined;\n\n constructor(\n rules = new ActiveMarkupRules(),\n styles?: ActiveStyleRemover,\n sources = new SourceMarkup(rules, styles),\n ) {\n this.#rules = rules;\n this.#styles = styles;\n this.#sources = sources;\n }\n\n /** The panel CSS of the document, under the same rule as its style elements. */\n stylesheet(css: string): { readonly css: string; readonly removed: readonly EmailRemoval[] } {\n const stripped = this.#styles?.stripActive(css);\n return stripped?.removed\n ? { css: stripped.css, removed: Array<EmailRemoval>(stripped.removed).fill('style') }\n : { css, removed: [] };\n }\n\n sanitize(nodes: readonly DocumentNode[]): SanitizedEmail {\n const removed: EmailRemoval[] = [];\n const cleaned = this.nodes(nodes, removed);\n return removed.length ? { nodes: cleaned, removed } : { nodes, removed };\n }\n\n private nodes(nodes: readonly DocumentNode[], removed: EmailRemoval[]): readonly DocumentNode[] {\n const output: DocumentNode[] = [];\n for (const node of nodes) {\n const cleaned = this.node(node, removed);\n if (cleaned) output.push(cleaned);\n }\n return output;\n }\n\n private node(node: DocumentNode, removed: EmailRemoval[]): DocumentNode | undefined {\n if (node.type === 'comment') {\n const value = node.value ?? '';\n if (!isConditionalComment(value)) return node;\n const stripped = this.source(value, 'html', removed);\n if (stripped === undefined) return undefined;\n return stripped === value ? node : { ...node, value: stripped };\n }\n if (node.type !== 'element') return node;\n const tag = (node.tag ?? '').toLowerCase();\n const active =\n this.#rules.element(tag) ??\n this.#rules.elementWith(tag, node.attrs ?? {}) ??\n this.#rules.navigation(tag, node.attrs ?? {});\n if (active) {\n removed.push(active);\n return undefined;\n }\n let attrs = node.attrs;\n for (const [name, value] of Object.entries(node.attrs ?? {})) {\n const finding = this.#rules.attribute(name, value);\n if (finding) {\n removed.push(finding);\n attrs = Object.fromEntries(Object.entries(attrs ?? {}).filter(([key]) => key !== name));\n continue;\n }\n if (name.toLowerCase() !== 'style') continue;\n const stripped = this.#styles?.stripActive(value, 'declarationList');\n if (!stripped?.removed) continue;\n removed.push(...Array<EmailRemoval>(stripped.removed).fill('style'));\n attrs = Object.fromEntries(\n Object.entries(attrs ?? {}).flatMap(([key, current]) =>\n key !== name ? [[key, current]] : stripped.css.trim() ? [[key, stripped.css]] : [],\n ),\n );\n }\n if (tag === 'meta') attrs = this.charset(attrs, removed);\n const context = SOURCE_CONTEXTS[tag];\n let children = node.children;\n if (context) {\n const text = (children ?? []).map((child) => child.value ?? '').join('');\n const stripped = this.source(text, context, removed);\n if (stripped === undefined) return undefined;\n if (stripped !== text)\n children = stripped\n ? [{ id: children?.[0]?.id ?? `${node.id}-source`, type: 'text', value: stripped }]\n : [];\n } else if (tag === 'style') {\n const text = (children ?? []).map((child) => child.value ?? '').join('');\n const stripped = this.#styles?.stripActive(text);\n if (stripped?.removed) {\n removed.push(...Array<EmailRemoval>(stripped.removed).fill('style'));\n children = stripped.css\n ? [{ id: children?.[0]?.id ?? `${node.id}-source`, type: 'text', value: stripped.css }]\n : [];\n }\n } else if (children) {\n const cleaned = this.nodes(children, removed);\n if (cleaned.length !== children.length || cleaned.some((child, i) => child !== children?.[i]))\n children = cleaned;\n }\n if (attrs === node.attrs && children === node.children) return node;\n return {\n ...node,\n ...(attrs ? { attrs } : {}),\n ...(children ? { children } : {}),\n };\n }\n\n /** Undefined when the block could not be made clean and is dropped as a whole. */\n private source(\n text: string,\n context: SourceContext,\n removed: EmailRemoval[],\n ): string | undefined {\n const stripped = this.#sources.strip(text, context);\n if (!stripped) {\n removed.push('embed');\n return undefined;\n }\n removed.push(...stripped.removed);\n return stripped.source;\n }\n\n /** The source reaches the editor as decoded text; whatever it declared, it is UTF-8 now. */\n private charset(\n attrs: Readonly<Record<string, string>> | undefined,\n removed: EmailRemoval[],\n ): Readonly<Record<string, string>> | undefined {\n if (!attrs) return attrs;\n const next: Record<string, string> = { ...attrs };\n let changed = false;\n for (const [name, value] of Object.entries(attrs)) {\n const key = name.toLowerCase();\n if (key === 'charset' && value.trim().toLowerCase() !== 'utf-8') {\n next[name] = 'utf-8';\n changed = true;\n }\n if (key !== 'content') continue;\n const directive = Object.entries(attrs).find(\n ([candidate]) => candidate.toLowerCase() === 'http-equiv',\n )?.[1];\n if (directive?.trim().toLowerCase() !== 'content-type') continue;\n const charset = value\n .split(';')\n .map((part) => part.split('='))\n .find(([parameter]) => parameter?.trim().toLowerCase() === 'charset')?.[1];\n if (charset !== undefined && charset.trim().toLowerCase() !== 'utf-8') {\n next[name] = UTF8_CONTENT_TYPE;\n changed = true;\n }\n }\n if (!changed) return attrs;\n removed.push('charset');\n return next;\n }\n}\n","import { CssDocumentCodec } from '../codecs/css';\nimport { DocumentValidationError, EditorDocument } from '../core/document';\nimport type { Diagnostic, DocumentNode, EditorDocumentData } from '../core/document';\nimport { ContentInspector } from './content-inventory';\nimport type { ContentInventory } from './content-inventory';\nimport { EmailSanitizer } from './email-sanitizer';\nimport type { EmailRemoval } from './email-sanitizer';\nimport { ActiveMarkupRules } from './markup-rules';\nimport { UrlPolicy } from './url-policy';\n\nexport class ContentPolicyError extends Error {\n constructor(readonly diagnostics: readonly Diagnostic[]) {\n super('UNSAFE_DOCUMENT');\n this.name = 'ContentPolicyError';\n }\n}\n\nexport interface SanitizedDocument {\n readonly document: EditorDocumentData;\n /** Grouped warnings saying what was removed or rewritten; empty when nothing was. */\n readonly diagnostics: readonly Diagnostic[];\n}\n\nconst HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';\nconst FOREIGN_ROOTS: Readonly<Record<string, string>> = Object.freeze({\n svg: 'http://www.w3.org/2000/svg',\n math: 'http://www.w3.org/1998/Math/MathML',\n});\nconst REMOVAL_CODES: Readonly<Record<EmailRemoval, string>> = Object.freeze({\n script: 'SCRIPT_REMOVED',\n embed: 'EMBED_REMOVED',\n handler: 'INLINE_HANDLER_REMOVED',\n url: 'UNSAFE_URL_REMOVED',\n style: 'ACTIVE_STYLE_REMOVED',\n charset: 'CHARSET_NORMALIZED',\n});\nconst REFUSAL_CODES: Readonly<Record<EmailRemoval, string>> = Object.freeze({\n script: 'FORBIDDEN_HTML_TAG',\n embed: 'FORBIDDEN_HTML_TAG',\n handler: 'FORBIDDEN_HTML_ATTRIBUTE',\n url: 'UNSAFE_HTML_URL',\n style: 'UNSAFE_CSS',\n charset: 'FORBIDDEN_META_DIRECTIVE',\n});\n\n/**\n * The rules of a document by kind. The editor never refuses the author's work for what it\n * contains:\n *\n * - a page keeps everything, scripts included, and `validate` only reports it (`info`);\n * - an e-mail has scripts, embeds, inline handlers and code URLs removed by `sanitize` at\n * every entry (source or JSON), with a grouped `warning`; if they are still present,\n * `validate` reports an error, because only a caller which skipped `sanitize` gets there.\n *\n * `assertSafe` therefore means \"structurally sound, within limits and following the rules\n * of its kind\". It does not mean \"free of script\": nothing of a document may run in the\n * editor because of the sandboxed frame and its nonce CSP, not because of this class.\n * Publication is the host's decision, taken over `inspect`.\n */\nexport class ContentPolicy {\n readonly #urls: UrlPolicy;\n readonly #rules: ActiveMarkupRules;\n readonly #css: CssDocumentCodec;\n readonly #inspector: ContentInspector;\n readonly #emails: EmailSanitizer;\n\n constructor(urls = new UrlPolicy(), css?: CssDocumentCodec) {\n this.#urls = urls;\n this.#css = css ?? new CssDocumentCodec(urls);\n const rules = new ActiveMarkupRules(urls);\n this.#rules = rules;\n this.#inspector = new ContentInspector(this.#css, rules);\n this.#emails = new EmailSanitizer(rules, this.#css);\n }\n\n /** An `EditorDocument` was validated when it was built and is not parsed again. */\n validate(input: EditorDocumentData | EditorDocument): readonly Diagnostic[] {\n let document: EditorDocumentData;\n try {\n document = this.snapshot(input);\n } catch (error: unknown) {\n return [\n this.error(\n error instanceof DocumentValidationError ? error.code : 'INVALID_DOCUMENT_SCHEMA',\n ),\n ];\n }\n const diagnostics: Diagnostic[] = [...this.#css.documentDiagnostics(document.css)];\n const stack = [...document.nodes];\n while (stack.length) {\n const node = stack.pop();\n if (!node) break;\n this.structure(node, diagnostics);\n stack.push(...(node.children ?? []));\n }\n try {\n if (document.kind === 'email')\n for (const removal of [\n ...this.#emails.sanitize(document.nodes).removed,\n ...this.#emails.stylesheet(document.css).removed,\n ])\n diagnostics.push(this.error(REFUSAL_CODES[removal]));\n return this.group([...diagnostics, ...this.notices(document)]);\n } catch (error: unknown) {\n // Markup kept as source (a conditional comment, `noscript`, an SVG) nests beyond the limit.\n if (!(error instanceof DocumentValidationError)) throw error;\n return this.group([...diagnostics, this.error(error.code)]);\n }\n }\n\n assertSafe(document: EditorDocumentData | EditorDocument): void {\n const diagnostics = this.validate(document);\n if (diagnostics.some((diagnostic) => diagnostic.severity === 'error'))\n throw new ContentPolicyError(diagnostics);\n }\n\n /**\n * Applies the removals of the kind. A page is returned as it came. Throws\n * `DocumentValidationError` when the input is not a document within the limits.\n */\n sanitize(input: EditorDocumentData | EditorDocument): SanitizedDocument {\n const document = this.snapshot(input);\n if (document.kind !== 'email') return { document, diagnostics: [] };\n const result = this.#emails.sanitize(document.nodes);\n const sheet = this.#emails.stylesheet(document.css);\n const removed = [...result.removed, ...sheet.removed];\n if (!removed.length) return { document, diagnostics: [] };\n return {\n document: EditorDocument.from({\n ...document,\n nodes: result.nodes,\n css: sheet.css,\n }).snapshot(),\n diagnostics: this.group(\n removed.map((removal) => this.notice(REMOVAL_CODES[removal], 'warning', 1)),\n ),\n };\n }\n\n /**\n * What the editor itself may write through its commands (an attribute, a link, a text\n * coming back from the editing frame), in either kind. It is stricter than what an author\n * may import: no script or embed, no handler, and URLs only under the strict `UrlPolicy`.\n */\n writable(nodes: readonly DocumentNode[]): boolean {\n const stack = [...nodes];\n while (stack.length) {\n const node = stack.pop();\n if (!node) break;\n if (node.type !== 'element') continue;\n if (\n this.#rules.element(node.tag ?? '') ||\n this.#rules.elementWith(node.tag ?? '', node.attrs ?? {}) ||\n this.#rules.navigation(node.tag ?? '', node.attrs ?? {})\n )\n return false;\n for (const [name, value] of Object.entries(node.attrs ?? {})) {\n if (this.#rules.attribute(name, value) || this.#rules.handlerLike(name)) return false;\n const purpose = this.#rules.urlPurpose(name);\n if (purpose && !this.#urls.isSafe(value, purpose)) return false;\n if (['srcdoc', 'srcset', 'imagesrcset'].includes(name.toLowerCase())) return false;\n }\n stack.push(...(node.children ?? []));\n }\n return true;\n }\n\n /** The typed inventory a host uses to decide whether and how to publish the document. */\n inspect(input: EditorDocumentData): ContentInventory {\n return this.#inspector.inspect(input);\n }\n\n private notices(document: EditorDocumentData): readonly Diagnostic[] {\n const { inventory, anchors } = this.#inspector.survey(document);\n const notices: Diagnostic[] = [];\n const add = (code: string, count: number, nodeId: string | undefined): void => {\n if (count > 0) notices.push(this.notice(code, 'info', count, nodeId));\n };\n if (document.kind === 'page') {\n add(\n 'SCRIPT_PRESERVED',\n inventory.scripts.inline + inventory.scripts.external.length,\n anchors.script,\n );\n add('EMBED_PRESERVED', inventory.frames.length + inventory.embeds, anchors.embed);\n add(\n 'INLINE_HANDLER_PRESERVED',\n inventory.inlineHandlers + inventory.scriptUrls,\n anchors.handler,\n );\n }\n add('EXTERNAL_STYLE_PRESERVED', inventory.stylesheets.length, anchors.stylesheet);\n add('FORM_PRESERVED', inventory.forms.count, anchors.form);\n return notices;\n }\n\n private snapshot(input: EditorDocumentData | EditorDocument): EditorDocumentData {\n return (input instanceof EditorDocument ? input : EditorDocument.from(input)).snapshot();\n }\n\n /** Integrity of the tree itself: what no parser could have produced or written back. */\n private structure(node: DocumentNode, diagnostics: Diagnostic[]): void {\n if (\n node.value?.includes('\\u0000') ||\n Object.values(node.attrs ?? {}).some((value) => value.includes('\\u0000'))\n )\n diagnostics.push(this.error('INVALID_HTML_CHARACTER', node.id));\n if (node.type === 'element') {\n const tag = (node.tag ?? '').toLowerCase();\n if (!this.tagName(tag)) diagnostics.push(this.error('FORBIDDEN_HTML_TAG', node.id));\n const namespace = node.metadata?.namespace ?? FOREIGN_ROOTS[tag] ?? HTML_NAMESPACE;\n // Foreign content only exists as a whole svg or math island kept as source.\n if (namespace !== (FOREIGN_ROOTS[tag] ?? HTML_NAMESPACE))\n diagnostics.push(this.error('FORBIDDEN_NAMESPACE', node.id));\n for (const attribute of Object.keys(node.attrs ?? {}))\n if (!this.attributeName(attribute))\n diagnostics.push(this.error('FORBIDDEN_HTML_ATTRIBUTE', node.id));\n return;\n }\n if (node.type === 'comment') {\n const value = node.value ?? '';\n const opener = node.metadata?.commentOpener ?? '<!--';\n // Neither form may be closed from inside by the text it carries.\n if (\n opener === '<!--'\n ? value.includes('-->') || value.includes('--!>')\n : value.includes('>') || (opener === '<?' && !value.startsWith('?'))\n )\n diagnostics.push(this.error('INVALID_HTML_COMMENT', node.id));\n }\n if (node.type === 'doctype') {\n const identifiers = Object.entries(node.attrs ?? {});\n if (\n !this.tagName((node.value ?? '').toLowerCase() || 'html') ||\n identifiers.some(([name]) => !['publicId', 'systemId'].includes(name)) ||\n identifiers.some(\n ([, value]) => value.includes('>') || (value.includes('\"') && value.includes(\"'\")),\n )\n )\n diagnostics.push(this.error('INVALID_DOCTYPE', node.id));\n return;\n }\n if (node.attrs && Object.keys(node.attrs).length)\n diagnostics.push(this.error('INVALID_LEAF', node.id));\n }\n\n /** A letter, then anything the tokenizer keeps in a tag name. */\n private tagName(name: string): boolean {\n const first = name.charCodeAt(0);\n return (\n ((first >= 65 && first <= 90) || (first >= 97 && first <= 122)) && this.nameCharacters(name)\n );\n }\n\n /** Framework and merge syntaxes (`@click`, `:class`, `mc:edit`) are ordinary names. */\n private attributeName(name: string): boolean {\n return (\n name.length > 0 &&\n name !== '__proto__' &&\n !name.slice(1).includes('=') &&\n this.nameCharacters(name)\n );\n }\n\n private nameCharacters(name: string): boolean {\n return ![...name].some(\n (character) =>\n character === '/' ||\n character === '>' ||\n character === '\\u0000' ||\n character === ' ' ||\n character === '\\t' ||\n character === '\\n' ||\n character === '\\f' ||\n character === '\\r',\n );\n }\n\n /** One entry per code: the first node it refers to and how many times it happened. */\n private group(diagnostics: readonly Diagnostic[]): readonly Diagnostic[] {\n const grouped = new Map<string, Diagnostic>();\n for (const diagnostic of diagnostics) {\n const existing = grouped.get(diagnostic.code);\n if (!existing) {\n grouped.set(diagnostic.code, diagnostic);\n continue;\n }\n const nodeId = existing.nodeId ?? diagnostic.nodeId;\n grouped.set(diagnostic.code, {\n code: existing.code,\n severity: existing.severity,\n messageKey: existing.messageKey,\n ...(nodeId ? { nodeId } : {}),\n count: (existing.count ?? 1) + (diagnostic.count ?? 1),\n });\n }\n return [...grouped.values()];\n }\n\n private notice(\n code: string,\n severity: 'warning' | 'info',\n count: number,\n nodeId?: string,\n ): Diagnostic {\n return {\n code,\n severity,\n messageKey: `diagnostics.${code}`,\n ...(nodeId ? { nodeId } : {}),\n count,\n };\n }\n\n private error(code: string, nodeId?: string): Diagnostic {\n return {\n code,\n severity: 'error',\n messageKey: `diagnostics.${code}`,\n ...(nodeId ? { nodeId } : {}),\n };\n }\n}\n","const FEATURES: ReadonlySet<string> = new Set(['mso', 'ie']);\nconst COMPARISONS: ReadonlySet<string> = new Set(['gt', 'gte', 'lt', 'lte']);\nconst EXPRESSION_OPERATORS: ReadonlySet<string> = new Set(['!', '(', ')', '&', '|']);\nconst MAX_EXPRESSION_LENGTH = 100;\n\n/**\n * Downlevel-revealed conditionals (`<![if !mso]>` ... `<![endif]>`) reach the tree as bogus\n * comments. Only the exact opening and closing forms over a closed vocabulary are recognized;\n * the content between the markers is ordinary markup validated like the rest of the document.\n */\nexport class DownlevelRevealedConditional {\n isOpening(value: string): boolean {\n if (value.length > MAX_EXPRESSION_LENGTH || !value.startsWith('[if ') || !value.endsWith(']'))\n return false;\n return this.validExpression(value.slice(4, -1));\n }\n\n isClosing(value: string): boolean {\n return value === '[endif]';\n }\n\n isMarker(value: string): boolean {\n return this.isOpening(value) || this.isClosing(value);\n }\n\n /**\n * `<![ENDIF]>` or `<![endif] >` would only survive as an ordinary comment, which no longer\n * closes the revealed block for Outlook. Anything but the exact closer is refused.\n */\n isClosingLookalike(value: string): boolean {\n return !this.isClosing(value) && value.trim().toLowerCase() === '[endif]';\n }\n\n /**\n * Document-order comment values: every revealed opener needs a later exact closer and a\n * second opener may not appear before it. A closer on its own stays an inert comment.\n */\n isBalanced(comments: Iterable<string>): boolean {\n let open = false;\n for (const value of comments) {\n if (this.isOpening(value)) {\n if (open) return false;\n open = true;\n } else if (this.isClosing(value)) open = false;\n }\n return !open;\n }\n\n /**\n * expression := term (('&' | '|') term)*\n * term := ['!'] ('(' expression ')' | [gt | gte | lt | lte] (mso | IE) [version])\n */\n private validExpression(expression: string): boolean {\n const tokens = this.tokens(expression);\n if (!tokens?.length) return false;\n const end = this.expression(tokens, 0);\n return end === tokens.length;\n }\n\n private tokens(expression: string): readonly string[] | undefined {\n const tokens: string[] = [];\n let word = '';\n for (const character of expression) {\n if (character === ' ' || EXPRESSION_OPERATORS.has(character)) {\n if (word) tokens.push(word.toLowerCase());\n word = '';\n if (character !== ' ') tokens.push(character);\n continue;\n }\n const code = character.charCodeAt(0);\n const letter = (code >= 65 && code <= 90) || (code >= 97 && code <= 122);\n const digit = code >= 48 && code <= 57;\n if (!letter && !digit && character !== '.') return undefined;\n word += character;\n }\n if (word) tokens.push(word.toLowerCase());\n return tokens;\n }\n\n /** Index after the expression which starts at `start`, or -1 when none is well formed. */\n private expression(tokens: readonly string[], start: number): number {\n let index = this.term(tokens, start);\n while (index >= 0 && (tokens[index] === '&' || tokens[index] === '|'))\n index = this.term(tokens, index + 1);\n return index;\n }\n\n private term(tokens: readonly string[], start: number): number {\n let index = tokens[start] === '!' ? start + 1 : start;\n if (tokens[index] === '(') {\n const inner = this.expression(tokens, index + 1);\n return inner >= 0 && tokens[inner] === ')' ? inner + 1 : -1;\n }\n if (COMPARISONS.has(tokens[index] ?? '')) index++;\n if (!FEATURES.has(tokens[index] ?? '')) return -1;\n index++;\n return this.version(tokens[index] ?? '') ? index + 1 : index;\n }\n\n private version(value: string): boolean {\n const parts = value.split('.');\n return (\n parts.length <= 2 &&\n parts.every(\n (part) =>\n part.length > 0 &&\n part.length <= 3 &&\n [...part].every((digit) => digit.charCodeAt(0) >= 48 && digit.charCodeAt(0) <= 57),\n )\n );\n }\n}\n","import { defaultTreeAdapter, html, serialize, serializeOuter } from 'parse5';\nimport type { DefaultTreeAdapterMap } from 'parse5';\nimport { BlockCatalog } from '../core/catalog';\nimport { DocumentBudget, DocumentBudgetError } from '../core/budget';\nimport { HtmlContentModel } from '../core/html-content-model';\nimport {\n DOCUMENT_LIMITS,\n DocumentValidationError,\n EditorDocument,\n HTML_VOID_ELEMENTS,\n} from '../core/document';\nimport type {\n CommentOpener,\n Diagnostic,\n DocumentKind,\n DocumentNode,\n EditorDocumentData,\n ImportResult,\n NodeMetadata,\n SourceInput,\n} from '../core/document';\nimport { ContentPolicy } from '../security/policy';\nimport { SecureIdentifier } from '../security/identity';\nimport { BoundedHtmlParser } from '../security/bounded-parser';\nimport { DownlevelRevealedConditional } from '../security/conditional-comment';\n\n/** parse5 drops the first line feed of these elements, so the serializer must restore it. */\nconst LEADING_NEWLINE_ELEMENTS: readonly string[] = Object.freeze(['pre', 'textarea', 'listing']);\n\n/** Elements which only exist inside a table; alone at the top of a fragment they are orphans. */\nconst TABLE_PARTS: ReadonlySet<string> = new Set([\n 'td',\n 'th',\n 'tr',\n 'tbody',\n 'thead',\n 'tfoot',\n 'caption',\n 'colgroup',\n 'col',\n]);\n\n/** Top-level nodes above which a fragment is read from the document parse instead. */\nconst WIDE_FRAGMENT_NODES = 20_000;\n\ninterface SourceRegion {\n readonly node: DocumentNode;\n readonly start: number;\n readonly end: number;\n}\n\ninterface SourceRecord {\n /** Absent when the tree is not what the source parses to, e.g. after an e-mail was cleaned. */\n readonly fingerprint: string | undefined;\n readonly source: SourceInput;\n readonly regions: ReadonlyMap<string, SourceRegion>;\n readonly weight: number;\n}\n\n/** HTML5 parser, structural recognition and a bounded, private source-preservation cache. */\nexport class HtmlDocumentCodec {\n readonly #policy: ContentPolicy;\n readonly #catalog: BlockCatalog;\n readonly #records = new Map<string, SourceRecord>();\n /** Documents which were exported are being edited; unrelated imports must not evict them. */\n readonly #exported = new Set<string>();\n readonly #cacheSize: number;\n readonly #cacheCharacters = 8_000_000;\n #nextId = 0;\n readonly #instanceId = new SecureIdentifier().next();\n readonly #conditionals = new DownlevelRevealedConditional();\n readonly #model = new HtmlContentModel();\n readonly #digests = new WeakMap<DocumentNode, string>();\n readonly #budget = new DocumentBudget();\n /** Ends a parse at the first element nested beyond the limit, before it costs quadratic time. */\n readonly #parser = new BoundedHtmlParser(DOCUMENT_LIMITS.depth);\n\n constructor(policy = new ContentPolicy(), catalog = new BlockCatalog(), cacheSize = 20) {\n if (!Number.isInteger(cacheSize) || cacheSize < 1 || cacheSize > 100)\n throw new RangeError('INVALID_CODEC_CACHE_LIMIT');\n this.#policy = policy;\n this.#catalog = catalog;\n this.#cacheSize = cacheSize;\n }\n\n /**\n * Never refuses a document for what it contains. A source is only turned down when it is\n * over the limits or when its tree cannot be written back as the same tree; a tree which\n * needed one pass of the serializer to settle is accepted in that settled form.\n */\n import(source: SourceInput, kind: DocumentKind, previous?: EditorDocumentData): ImportResult {\n const result = this.read(source, kind, previous, true);\n if (!result.document || this.roundTrips(result.document)) return result;\n this.forget(result.document.id);\n const settled = this.read(\n { html: this.plain(result.document), css: source.css },\n kind,\n previous,\n true,\n );\n if (!settled.document || !this.roundTrips(settled.document)) {\n if (settled.document) this.forget(settled.document.id);\n return { diagnostics: [this.error('INVALID_HTML')] };\n }\n const diagnostics = new Map<string, Diagnostic>();\n for (const diagnostic of [\n ...result.diagnostics.filter((entry) => entry.severity === 'warning'),\n ...settled.diagnostics,\n this.notice('HTML_NORMALIZED'),\n ])\n if (!diagnostics.has(diagnostic.code)) diagnostics.set(diagnostic.code, diagnostic);\n return { document: settled.document, diagnostics: [...diagnostics.values()] };\n }\n\n /**\n * Parses and validates auxiliary source (rich text projections, snippets, verification)\n * without touching the preservation cache of the documents being edited.\n */\n inspect(source: SourceInput, kind: DocumentKind): ImportResult {\n return this.read(source, kind, undefined, false);\n }\n\n private read(\n source: SourceInput,\n kind: DocumentKind,\n previous: EditorDocumentData | undefined,\n remember: boolean,\n ): ImportResult {\n if (\n typeof source?.html !== 'string' ||\n typeof source.css !== 'string' ||\n !['email', 'page'].includes(kind)\n )\n return { diagnostics: [this.error('INVALID_SOURCE')] };\n try {\n this.#budget.assertSource(source.html, source.css);\n } catch (error: unknown) {\n return {\n diagnostics: [\n this.error(error instanceof DocumentBudgetError ? error.code : 'DOCUMENT_TOO_LARGE'),\n ],\n };\n }\n if (previous) {\n try {\n this.#policy.assertSafe(previous);\n } catch {\n return { diagnostics: [this.error('INVALID_PREVIOUS_DOCUMENT')] };\n }\n if (previous.kind !== kind) return { diagnostics: [this.error('DOCUMENT_KIND_MISMATCH')] };\n }\n // The parser drops or replaces U+0000; without it positions and tree agree again.\n const markup = source.html.includes('\\u0000')\n ? source.html.replaceAll('\\u0000', '')\n : source.html;\n const kept: SourceInput = { html: markup, css: source.css };\n try {\n const { nodes: parsedNodes, slices } = this.tree(markup);\n // The rules of the kind are applied to the tree: an e-mail loses what it may not carry.\n const draft = EditorDocument.from({\n schemaVersion: 1,\n id: previous?.id ?? this.newId('document'),\n kind,\n revision: (previous?.revision ?? -1) + 1,\n title: (this.findTitle(parsedNodes) ?? previous?.title ?? '').slice(0, 1_000),\n nodes: parsedNodes,\n css: source.css,\n });\n const sanitized = this.#policy.sanitize(draft);\n const cleaned = sanitized.document.nodes;\n const nodes = previous ? this.reconcileIds(cleaned, previous.nodes) : cleaned;\n // Reconciliation keeps the shape, so both trees are walked in lockstep.\n const regions = new Map<string, SourceRegion>();\n const pending = nodes.map((node, index) => ({ node, origin: cleaned[index] }));\n while (pending.length) {\n const frame = pending.pop();\n if (!frame) break;\n const slice = frame.origin ? slices.get(frame.origin.id) : undefined;\n if (slice) regions.set(frame.node.id, slice);\n (frame.node.children ?? []).forEach((child, index) =>\n pending.push({ node: child, origin: frame.origin?.children?.[index] }),\n );\n }\n // The draft is the document unless the kind rules or older identities changed its tree.\n const settled =\n previous || sanitized.diagnostics.length\n ? EditorDocument.from({ ...sanitized.document, nodes })\n : draft;\n const diagnostics = this.#policy.validate(settled);\n if (diagnostics.some((diagnostic) => diagnostic.severity === 'error')) return { diagnostics };\n const document = settled.snapshot();\n if (remember) this.remember(document, kept, regions, sanitized.diagnostics.length === 0);\n return {\n document,\n validated: settled,\n diagnostics: [...sanitized.diagnostics, ...diagnostics],\n };\n } catch (error: unknown) {\n return {\n diagnostics: [\n this.error(error instanceof DocumentValidationError ? error.code : 'INVALID_HTML'),\n ],\n };\n }\n }\n\n /**\n * The tree the parser builds for this markup, in the shape of the document model, and the\n * source slice of every node which stands alone in it. Throws over the node limits.\n */\n private tree(markup: string): {\n readonly nodes: readonly DocumentNode[];\n readonly slices: ReadonlyMap<string, SourceRegion>;\n } {\n // Scripting is on, as in the browsers which will render the result: `noscript` is text.\n const options = { sourceCodeLocationInfo: true, scriptingEnabled: true };\n const parsed = this.#parser.document(markup, options);\n const roots = this.isDocument(parsed) ? parsed.childNodes : this.fragment(parsed, markup);\n let counted = 0;\n let total = 0;\n const contained = new WeakSet<DocumentNode>();\n const convert = (node: DefaultTreeAdapterMap['childNode'], depth: number): DocumentNode => {\n if (depth > DOCUMENT_LIMITS.depth) throw new DocumentValidationError('DOCUMENT_TOO_DEEP');\n const id = this.newId('node');\n const location = node.sourceCodeLocation;\n const metadata: NodeMetadata = location\n ? { sourceStart: location.startOffset, sourceEnd: location.endOffset }\n : {};\n let converted: DocumentNode;\n if (defaultTreeAdapter.isElementNode(node)) {\n const attrs = Object.fromEntries(\n node.attrs\n .map((attribute) => [\n attribute.prefix ? `${attribute.prefix}:${attribute.name}` : attribute.name,\n attribute.value,\n ])\n // Never an HTML attribute; as an object key it would be the prototype.\n .filter(([name]) => name !== '__proto__'),\n );\n const island = this.island(node, markup, id);\n const children =\n island?.children ??\n defaultTreeAdapter.getChildNodes(node).map((child) => convert(child, depth + 1));\n converted = {\n id,\n type: 'element',\n tag: node.tagName,\n attrs,\n children,\n metadata: { ...metadata, namespace: node.namespaceURI },\n };\n const descriptor = this.#catalog.recognize(converted);\n if (descriptor)\n converted = {\n ...converted,\n metadata: { ...converted.metadata, blockType: descriptor.type },\n };\n if (island ? island.contained : this.selfContainedElement(node, children, contained))\n contained.add(converted);\n } else if (defaultTreeAdapter.isTextNode(node)) {\n converted = { id, type: 'text', value: node.value, metadata };\n // Adjacent character tokens are merged: a slice holding markup is not this text alone.\n if (location && !markup.slice(location.startOffset, location.endOffset).includes('<'))\n contained.add(converted);\n } else if (defaultTreeAdapter.isCommentNode(node)) {\n // The tree cannot tell `<!--[if mso]-->` from `<![if mso]>` nor `<?xml ?>` from a\n // comment: how it was written is read from the source and kept with the node.\n const opener = location ? this.opener(markup, location.startOffset) : '<!--';\n converted = {\n id,\n type: 'comment',\n value: node.data,\n metadata:\n opener !== '<!--' || this.#conditionals.isMarker(node.data)\n ? { ...metadata, commentOpener: opener }\n : metadata,\n };\n if (location) contained.add(converted);\n } else if (defaultTreeAdapter.isDocumentTypeNode(node)) {\n converted = {\n id,\n type: 'doctype',\n value: node.name,\n attrs: { publicId: node.publicId, systemId: node.systemId },\n metadata,\n };\n if (location) contained.add(converted);\n } else {\n throw new DocumentValidationError('UNSUPPORTED_HTML_NODE');\n }\n if (this.#budget.countable(converted)) counted++;\n if (counted > DOCUMENT_LIMITS.nodes || ++total > DOCUMENT_LIMITS.totalNodes)\n throw new DocumentValidationError('DOCUMENT_TOO_MANY_NODES');\n return converted;\n };\n const parsedNodes = roots.map((node) => convert(node, 0));\n const slices = new Map<string, SourceRegion>();\n const located = [...parsedNodes];\n while (located.length) {\n const node = located.pop();\n if (!node) break;\n const start = node.metadata?.sourceStart;\n const end = node.metadata?.sourceEnd;\n if (contained.has(node) && start !== undefined && end !== undefined && end > start)\n slices.set(node.id, { node, start, end });\n located.push(...(node.children ?? []));\n }\n return { nodes: parsedNodes, slices };\n }\n\n export(input: EditorDocumentData | EditorDocument): SourceInput {\n const aggregate = input instanceof EditorDocument ? input : EditorDocument.from(input);\n this.#policy.assertSafe(aggregate);\n const document = aggregate.snapshot();\n const record = this.#records.get(document.id);\n if (record) {\n // Exporting is the session's use of its record: keep it the most recent entry.\n this.#records.delete(document.id);\n this.#records.set(document.id, record);\n this.#exported.add(document.id);\n }\n const fingerprint = this.documentFingerprint(document);\n if (record?.fingerprint !== undefined && record.fingerprint === fingerprint)\n return { ...record.source };\n if (record) {\n const preserved = document.nodes.map((node) => this.serialize(node, record)).join('');\n if (this.verification(preserved, document, fingerprint) === undefined)\n return { html: preserved, css: document.css };\n // A preserved slice was not as self-contained as its locations suggested: serialize plainly.\n }\n const html = this.plain(document);\n const failure = this.verification(html, document, fingerprint);\n if (failure) throw new Error(failure);\n return { html, css: document.css };\n }\n\n clearCache(): void {\n this.#records.clear();\n this.#exported.clear();\n }\n\n private plain(document: EditorDocumentData): string {\n return document.nodes.map((node) => this.serialize(node)).join('');\n }\n\n private roundTrips(document: EditorDocumentData): boolean {\n return (\n this.verification(this.plain(document), document, this.documentFingerprint(document)) ===\n undefined\n );\n }\n\n private forget(id: string): void {\n this.#records.delete(id);\n this.#exported.delete(id);\n }\n\n /**\n * `template`, `svg` and `math` are kept as one block of source. Their inner markup follows\n * other parsing rules (inert content, foreign elements, CDATA) which a tree of HTML nodes\n * would not write back as it was read.\n */\n private island(\n node: DefaultTreeAdapterMap['element'],\n markup: string,\n id: string,\n ): { readonly children: readonly DocumentNode[]; readonly contained: boolean } | undefined {\n if (\n !this.#model.isSourceIsland(node.tagName) ||\n (node.tagName === 'template') !== (node.namespaceURI === html.NS.HTML)\n )\n return undefined;\n const start = node.sourceCodeLocation?.startTag?.endOffset;\n const end = node.sourceCodeLocation?.endTag?.startOffset;\n const closed = start !== undefined && end !== undefined;\n // Without its own end tag the positions say nothing certain about what it holds.\n const source = closed ? markup.slice(start, end) : serialize(node);\n return {\n children: source ? [{ id: `${id}-source`, type: 'text', value: source }] : [],\n contained: closed,\n };\n }\n\n private opener(markup: string, offset: number): CommentOpener {\n if (markup.startsWith('<!--', offset)) return '<!--';\n if (markup.startsWith('<!', offset)) return '<!';\n if (markup.startsWith('</', offset)) return '</';\n return markup.startsWith('<?', offset) ? '<?' : '<!--';\n }\n\n /** How a comment is written: as recorded, or by the grammar of old documents without it. */\n private commentOpener(node: DocumentNode): CommentOpener {\n return (\n node.metadata?.commentOpener ??\n (this.#conditionals.isMarker(node.value ?? '') ? '<!' : '<!--')\n );\n }\n\n private namespace(node: DocumentNode): string {\n const tag = node.tag?.toLowerCase();\n if (tag === 'svg') return html.NS.SVG;\n if (tag === 'math') return html.NS.MATHML;\n return node.metadata?.namespace ?? html.NS.HTML;\n }\n\n /**\n * Reparse output before returning it; serializer edge cases are a security boundary too.\n * The tree read back has to be the tree which was written: the same nodes, attributes,\n * text, comment forms and namespaces. Anything a parser would read differently, such as\n * text which closes its own script or comment, fails here whatever the kind allows.\n */\n private verification(\n html: string,\n document: EditorDocumentData,\n fingerprint: string,\n ): string | undefined {\n try {\n this.#budget.assertSource(html, document.css);\n const nodes = this.tree(html).nodes;\n return this.documentFingerprint({ ...document, nodes }) === fingerprint\n ? undefined\n : 'SERIALIZED_STRUCTURE_CHANGED';\n } catch {\n return 'UNSAFE_SERIALIZED_DOCUMENT';\n }\n }\n\n /**\n * A source slice may stand for a node only when it holds that node and nothing else.\n * Foster parenting, formatting reconstruction and ignored tokens leave foreign source\n * between the located children; implied elements carry no location and are transparent.\n */\n private selfContainedElement(\n node: DefaultTreeAdapterMap['element'],\n children: readonly DocumentNode[],\n contained: WeakSet<DocumentNode>,\n ): boolean {\n const location = node.sourceCodeLocation;\n if (!location?.startTag) return false;\n const cursor = { offset: location.startTag.endOffset };\n return (\n this.tile(defaultTreeAdapter.getChildNodes(node), children, contained, cursor) &&\n cursor.offset === (location.endTag?.startOffset ?? location.endOffset)\n );\n }\n\n private tile(\n parsed: readonly DefaultTreeAdapterMap['childNode'][],\n converted: readonly DocumentNode[],\n contained: WeakSet<DocumentNode>,\n cursor: { offset: number },\n ): boolean {\n for (const [index, child] of parsed.entries()) {\n const node = converted[index];\n if (!node) return false;\n const location = child.sourceCodeLocation;\n if (!location) {\n if (\n !defaultTreeAdapter.isElementNode(child) ||\n !this.tile(\n defaultTreeAdapter.getChildNodes(child),\n node.children ?? [],\n contained,\n cursor,\n )\n )\n return false;\n continue;\n }\n if (location.startOffset !== cursor.offset) return false;\n if (node.type === 'element' && !contained.has(node)) return false;\n cursor.offset = location.endOffset;\n }\n return true;\n }\n\n private serialize(node: DocumentNode, record?: SourceRecord): string {\n const region = record?.regions.get(node.id);\n if (region && this.nodeFingerprint(region.node) === this.nodeFingerprint(node))\n return record?.source.html.slice(region.start, region.end) ?? '';\n if (node.type === 'doctype') {\n const quote = (value: string): string => (value.includes('\"') ? `'${value}'` : `\"${value}\"`);\n const publicId = node.attrs?.publicId ?? '';\n const systemId = node.attrs?.systemId ?? '';\n const declaration = publicId\n ? ` PUBLIC ${quote(publicId)}${systemId ? ` ${quote(systemId)}` : ''}`\n : systemId\n ? ` SYSTEM ${quote(systemId)}`\n : '';\n return `<!DOCTYPE ${node.value || 'html'}${declaration}>`;\n }\n if (node.type === 'comment') {\n const value = node.value ?? '';\n // A downlevel-revealed marker or a processing instruction written as a regular\n // comment would no longer mean what the author wrote.\n const opener = this.commentOpener(node);\n if (opener === '<!--') return `<!--${value}-->`;\n // The data of `<?xml ?>` already starts with its question mark.\n return opener === '<?' ? `<${value}>` : `${opener}${value}>`;\n }\n if (node.type === 'text') {\n const element = defaultTreeAdapter.createElement('div', html.NS.HTML, []);\n defaultTreeAdapter.insertText(element, node.value ?? '');\n const text = element.childNodes[0];\n return text ? serializeOuter(text).replaceAll('\\r', '&#13;') : '';\n }\n const tag = node.tag ?? 'div';\n // The serializer reads a template through a content fragment this skeleton does not have:\n // its tags are written over a stand-in element with the same attributes.\n const template = tag.toLowerCase() === 'template';\n const element = defaultTreeAdapter.createElement(\n template ? 'div' : tag,\n html.NS.HTML,\n Object.entries(node.attrs ?? {}).map(([name, value]) => ({ name, value })),\n );\n const written = serializeOuter(element).replaceAll('\\r', '&#13;');\n const skeleton = template\n ? `<${tag}${written.slice('<div'.length, written.length - '</div>'.length)}</${tag}>`\n : written;\n const closing = `</${tag}>`;\n // The parser decides what is void: never cut a start tag which has no end tag.\n if (HTML_VOID_ELEMENTS.includes(tag.toLowerCase()) || !skeleton.endsWith(closing))\n return skeleton;\n const opening = skeleton.slice(0, skeleton.length - closing.length);\n const children = node.children ?? [];\n // Raw text and source islands are written as they were read: escaping would change them.\n if (this.#model.holdsSource(tag)) {\n const source = children.map((child) => child.value ?? '').join('');\n // Nothing ends `plaintext`: an end tag would become part of its text.\n return tag.toLowerCase() === 'plaintext'\n ? `${opening}${source}`\n : `${opening}${source}${closing}`;\n }\n const restoresNewline = LEADING_NEWLINE_ELEMENTS.includes(tag.toLowerCase());\n const content = children\n .map((child, index) =>\n // The slice of that first text may or may not hold the line feed the parser dropped.\n this.serialize(child, restoresNewline && index === 0 ? undefined : record),\n )\n .join('');\n const first = children[0];\n const newline =\n restoresNewline && first?.type === 'text' && first.value?.startsWith('\\n') ? '\\n' : '';\n return `${opening}${newline}${content}${closing}`;\n }\n\n /**\n * Markup without `html`, `head` or `body` is read as a fragment. The fragment parser moves\n * its result node by node, which is quadratic over tens of thousands of top-level nodes:\n * such a wide source uses the flow content of the document parse, which is the same tree\n * for everything a browser would place in a body.\n */\n private fragment(\n document: DefaultTreeAdapterMap['document'],\n markup: string,\n ): readonly DefaultTreeAdapterMap['childNode'][] {\n const flow = document.childNodes.flatMap((root) =>\n defaultTreeAdapter.isElementNode(root)\n ? root.childNodes.flatMap((section) =>\n defaultTreeAdapter.isElementNode(section) ? section.childNodes : [section],\n )\n : [],\n );\n if (flow.length > WIDE_FRAGMENT_NODES) return flow;\n const fragment = this.#parser.fragment(markup, {\n sourceCodeLocationInfo: true,\n scriptingEnabled: true,\n }).childNodes;\n // A row or a cell pasted without its table has no place in a document. Rather than\n // refuse it, its content is kept the way a browser keeps it when it lands in a body.\n return fragment.some(\n (node) => defaultTreeAdapter.isElementNode(node) && TABLE_PARTS.has(node.tagName),\n )\n ? flow\n : fragment;\n }\n\n private isDocument(document: DefaultTreeAdapterMap['document']): boolean {\n const stack = [...document.childNodes];\n while (stack.length) {\n const node = stack.pop();\n if (!node) break;\n if (defaultTreeAdapter.isDocumentTypeNode(node)) return true;\n if (defaultTreeAdapter.isElementNode(node)) {\n if (['html', 'head', 'body'].includes(node.tagName) && node.sourceCodeLocation?.startTag)\n return true;\n stack.push(...node.childNodes);\n }\n }\n return false;\n }\n\n private findTitle(nodes: readonly DocumentNode[]): string | undefined {\n for (const node of nodes) {\n if (node.type === 'element' && node.tag === 'title')\n return (node.children ?? []).map((child) => child.value ?? '').join('');\n const nested = this.findTitle(node.children ?? []);\n if (nested !== undefined) return nested;\n }\n return undefined;\n }\n\n private newId(prefix: string): string {\n return `${prefix}-${this.#instanceId}-${++this.#nextId}`;\n }\n\n private reconcileIds(\n nodes: readonly DocumentNode[],\n previous: readonly DocumentNode[],\n ): readonly DocumentNode[] {\n const candidates = new Map<string, DocumentNode[]>();\n const fingerprints = new Set<string>();\n const previousStack = [...previous];\n while (previousStack.length) {\n const node = previousStack.pop();\n if (!node) break;\n const fingerprint = this.nodeFingerprint(node);\n const known = candidates.get(fingerprint);\n if (known) known.push(node);\n else candidates.set(fingerprint, [node]);\n previousStack.push(...(node.children ?? []));\n }\n const currentStack = [...nodes];\n while (currentStack.length) {\n const node = currentStack.pop();\n if (!node) break;\n fingerprints.add(this.nodeFingerprint(node));\n currentStack.push(...(node.children ?? []));\n }\n const used = new Set<string>();\n // Identities are only ever marked as used, so each list is read once, from where it stopped.\n const cursors = new Map<string, number>();\n const unused = (fingerprint: string): DocumentNode | undefined => {\n const list = candidates.get(fingerprint);\n if (!list) return undefined;\n let cursor = cursors.get(fingerprint) ?? 0;\n while (cursor < list.length && used.has(list[cursor]?.id ?? '')) cursor++;\n cursors.set(fingerprint, cursor);\n return list[cursor];\n };\n const reconcile = (node: DocumentNode, previousAtPosition?: DocumentNode): DocumentNode => {\n const fingerprint = this.nodeFingerprint(node);\n let candidate = unused(fingerprint);\n if (\n previousAtPosition &&\n this.nodeFingerprint(previousAtPosition) === fingerprint &&\n !used.has(previousAtPosition.id)\n )\n candidate = previousAtPosition;\n if (\n !candidate &&\n previousAtPosition &&\n previousAtPosition.type === node.type &&\n previousAtPosition.tag === node.tag &&\n !used.has(previousAtPosition.id) &&\n !fingerprints.has(this.nodeFingerprint(previousAtPosition))\n ) {\n candidate = previousAtPosition;\n }\n const id = candidate?.id ?? node.id;\n used.add(id);\n return {\n ...node,\n id,\n ...(node.children\n ? {\n children: node.children.map((child, index) =>\n reconcile(child, candidate?.children?.[index]),\n ),\n }\n : {}),\n };\n };\n return nodes.map((node, index) => reconcile(node, previous[index]));\n }\n\n /**\n * Digest of a subtree, remembered per node object so that matching preserved slices and\n * older identities costs one pass over the tree. It only chooses candidates: whatever is\n * written is still verified against the exact document fingerprint by reparse.\n */\n private nodeFingerprint(node: DocumentNode): string {\n const known = this.#digests.get(node);\n if (known !== undefined) return known;\n const children = (node.children ?? []).map((child) => this.nodeFingerprint(child)).join(',');\n const digest = this.digest(`${JSON.stringify(this.ownStructure(node))}|${children}`);\n this.#digests.set(node, digest);\n return digest;\n }\n\n /** Two independent 32-bit mixes and the length: enough to pick a candidate, never a proof. */\n private digest(text: string): string {\n let first = 0x811c9dc5;\n let second = 0x9e3779b9;\n for (let index = 0; index < text.length; index++) {\n const code = text.charCodeAt(index);\n first = Math.imul(first ^ code, 0x01000193);\n second = Math.imul(second ^ code, 0x85ebca6b) ^ (second >>> 13);\n }\n return `${(first >>> 0).toString(36)}.${(second >>> 0).toString(36)}.${text.length.toString(36)}`;\n }\n\n private ownStructure(node: DocumentNode): object {\n const attributes =\n node.type === 'doctype'\n ? { publicId: node.attrs?.publicId ?? '', systemId: node.attrs?.systemId ?? '' }\n : (node.attrs ?? {});\n return {\n type: node.type,\n tag: node.tag?.toLowerCase(),\n value: node.type === 'doctype' ? node.value?.toLowerCase() : node.value,\n opener: node.type === 'comment' ? this.commentOpener(node) : undefined,\n attrs: Object.entries(attributes)\n .map(([key, value]) => [node.type === 'doctype' ? key : key.toLowerCase(), value] as const)\n .sort(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0)),\n namespace: node.type === 'element' ? this.namespace(node) : undefined,\n };\n }\n\n private nodeStructure(node: DocumentNode): object {\n return {\n ...this.ownStructure(node),\n children: (node.children ?? []).map((child) => this.nodeStructure(child)),\n };\n }\n\n private documentFingerprint(document: EditorDocumentData): string {\n return JSON.stringify({\n kind: document.kind,\n css: document.css,\n nodes: document.nodes.map((node) => this.nodeStructure(node)),\n });\n }\n\n private remember(\n document: EditorDocumentData,\n source: SourceInput,\n regions: ReadonlyMap<string, SourceRegion>,\n faithful: boolean,\n ): void {\n this.#records.delete(document.id);\n // A cleaned tree is not what the source parses to: the source is never returned whole.\n const fingerprint = faithful ? this.documentFingerprint(document) : undefined;\n const weight =\n source.html.length + source.css.length + (fingerprint?.length ?? source.html.length);\n if (weight > this.#cacheCharacters) {\n this.#exported.delete(document.id);\n return;\n }\n this.#records.set(document.id, { source: { ...source }, fingerprint, regions, weight });\n while (\n this.#records.size > this.#cacheSize ||\n [...this.#records.values()].reduce((sum, record) => sum + record.weight, 0) >\n this.#cacheCharacters\n ) {\n const ids = [...this.#records.keys()];\n const oldest = ids.find((id) => !this.#exported.has(id)) ?? ids[0];\n if (oldest === undefined) break;\n this.#records.delete(oldest);\n this.#exported.delete(oldest);\n }\n }\n\n private error(code: string): Diagnostic {\n return { code, severity: 'error', messageKey: `diagnostics.${code}` };\n }\n\n private notice(code: string): Diagnostic {\n return { code, severity: 'info', messageKey: `diagnostics.${code}` };\n }\n}\n","import { defaultTreeAdapter, html, parseFragment, serialize } from 'parse5';\nimport type { DefaultTreeAdapterMap } from 'parse5';\nimport { HtmlDocumentCodec } from '../codecs/html';\nimport { ContentPolicy } from '../security/policy';\n\nexport const COMPILE_LIMITS = Object.freeze({\n sourceBytes: 200_000,\n outputBytes: 2_000_000,\n timeoutMs: 15_000,\n parallelJobs: 2,\n});\n\nconst FORBIDDEN = ['mj-include', 'mj-font', 'mj-raw', 'script', 'iframe', 'object', 'embed'];\n/** Preview class of a raw region: `ve-p-<token of the rendering>-<block id>`. */\nconst RAW_CELL_CLASS = /^ve-p-[a-f0-9]{32}-[A-Za-z0-9_-]{1,64}$/;\nconst RAW_CELL_STYLE = /^padding:(0|\\d{1,3}(px)?)( (0|\\d{1,3}(px)?)){0,3}$/;\n\n/** Compilation accepts content, never filesystem paths, configuration or plugins. */\nexport class CompilationGuard {\n private readonly codec = new HtmlDocumentCodec(new ContentPolicy());\n\n /**\n * Without `fragments` (MJML from outside) `mj-raw` is refused like an include. With them\n * (MJML of the block codec) an `mj-raw` is accepted only as a child of `mj-column`, only\n * when its content is exactly one of the fragments, and each fragment must pass\n * `rawFragment`.\n */\n source(source: string, fragments?: readonly string[]): void {\n if (new TextEncoder().encode(source).length > COMPILE_LIMITS.sourceBytes)\n throw new Error('COMPILE_SOURCE_LIMIT');\n const allowed = fragments ? new Set(fragments) : undefined;\n for (const fragment of allowed ?? []) this.rawFragment(fragment);\n const root = parseFragment(source, { sourceCodeLocationInfo: true });\n const stack: { node: DefaultTreeAdapterMap['childNode']; parent: string }[] =\n root.childNodes.map((node) => ({ node, parent: '' }));\n let count = 0;\n while (stack.length) {\n const frame = stack.pop();\n if (!frame) break;\n const { node } = frame;\n if (++count > 10_000) throw new Error('COMPILE_NODE_LIMIT');\n if ('tagName' in node) {\n if (node.tagName === 'mj-raw' && allowed)\n this.rawRegion(node, frame.parent, source, allowed);\n else if (FORBIDDEN.includes(node.tagName)) throw new Error('COMPILE_FORBIDDEN_TAG');\n }\n if ('childNodes' in node) {\n const parent = 'tagName' in node ? node.tagName : '';\n stack.push(...node.childNodes.map((child) => ({ node: child, parent })));\n }\n }\n }\n\n /**\n * A raw region of generated MJML. MJML writes it, as it is, inside the `tbody` of the column,\n * so it is read here the way a browser reads it there: one row, one cell with only a class\n * and a padding, and a content the e-mail rules keep without removing or rewriting anything.\n */\n rawFragment(fragment: string): void {\n // MJML ends a raw region at its closing tag wherever it is, attributes included.\n if (/<\\/?mj-/i.test(fragment)) throw new Error('COMPILE_UNSAFE_RAW');\n const context = defaultTreeAdapter.createElement('tbody', html.NS.HTML, []);\n const parsed = parseFragment(context, fragment, {});\n const row = parsed.childNodes[0];\n if (parsed.childNodes.length !== 1 || !row || !('tagName' in row) || row.tagName !== 'tr')\n throw new Error('COMPILE_UNSAFE_RAW');\n const cell = row.childNodes[0];\n if (\n row.attrs.length ||\n row.childNodes.length !== 1 ||\n !cell ||\n !('tagName' in cell) ||\n cell.tagName !== 'td'\n )\n throw new Error('COMPILE_UNSAFE_RAW');\n for (const attribute of cell.attrs)\n if (\n !(attribute.name === 'class' && RAW_CELL_CLASS.test(attribute.value)) &&\n !(attribute.name === 'style' && RAW_CELL_STYLE.test(attribute.value))\n )\n throw new Error('COMPILE_UNSAFE_RAW');\n const content = serialize(cell);\n if (!content) return;\n const result = this.codec.inspect({ html: content, css: '' }, 'email');\n if (!result.document || result.diagnostics.some((diagnostic) => diagnostic.severity !== 'info'))\n throw new Error('COMPILE_UNSAFE_RAW');\n }\n\n output(source: unknown): string {\n if (\n typeof source !== 'string' ||\n new TextEncoder().encode(source).length > COMPILE_LIMITS.outputBytes\n )\n throw new Error('COMPILE_OUTPUT_LIMIT');\n // Generated markup is the catalog's, not an author's: it has to be an e-mail as it is.\n // Anything the import would have to remove or rewrite makes the compilation fail.\n const result = this.codec.inspect({ html: source, css: '' }, 'email');\n if (!result.document || result.diagnostics.some((diagnostic) => diagnostic.severity !== 'info'))\n throw new Error('COMPILE_UNSAFE_OUTPUT');\n return source;\n }\n\n private rawRegion(\n node: DefaultTreeAdapterMap['element'],\n parent: string,\n source: string,\n allowed: ReadonlySet<string>,\n ): void {\n const location = node.sourceCodeLocation;\n if (parent !== 'mj-column' || !location?.startTag || !location.endTag)\n throw new Error('COMPILE_FORBIDDEN_TAG');\n const content = source.slice(location.startTag.endOffset, location.endTag.startOffset);\n if (!allowed.has(content)) throw new Error('COMPILE_FORBIDDEN_TAG');\n }\n}\n\nexport const MJML_OPTIONS = Object.freeze({\n fonts: {},\n validationLevel: 'strict' as const,\n ignoreIncludes: true,\n useMjmlConfigOptions: false,\n keepComments: true,\n minify: false,\n juiceOptions: { webResources: { images: false, scripts: false, links: false } },\n});\n","/**\n * MJML written by the block codec, with the exact raw regions (`mj-raw`) it emitted. A raw\n * region is accepted by the compilation only through this type, only inside `mj-column`, and\n * only when it is one of `fragments` and passes `CompilationGuard.rawFragment`: one table row\n * whose single cell holds markup the e-mail rules keep as it is. MJML that arrives as a string\n * (`compile`) never has a raw region.\n */\nexport class GeneratedMjml {\n readonly source: string;\n readonly fragments: readonly string[];\n\n constructor(source: string, fragments: readonly string[] = []) {\n if (typeof source !== 'string' || !fragments.every((entry) => typeof entry === 'string'))\n throw new TypeError('INVALID_GENERATED_MJML');\n this.source = source;\n this.fragments = Object.freeze([...fragments]);\n Object.freeze(this);\n }\n}\n\n/** Compilers which accept generated MJML. Both bundled compilers implement it. */\nexport interface GeneratedMjmlCompilerPort {\n compileGenerated(mjml: GeneratedMjml): Promise<string>;\n}\n\n/** What a compilation worker receives: external MJML, or generated MJML with its regions. */\nexport type CompileRequest = string | { readonly source: string; readonly fragments: string[] };\n\nexport function readCompileRequest(\n request: unknown,\n): { source: string; fragments?: readonly string[] } | undefined {\n if (typeof request === 'string') return { source: request };\n if (!request || typeof request !== 'object') return undefined;\n const source: unknown = Object.getOwnPropertyDescriptor(request, 'source')?.value;\n const fragments: unknown = Object.getOwnPropertyDescriptor(request, 'fragments')?.value;\n if (\n typeof source !== 'string' ||\n !Array.isArray(fragments) ||\n !fragments.every((entry): entry is string => typeof entry === 'string')\n )\n return undefined;\n return { source, fragments };\n}\n"],"mappings":"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"}