( input: string, options?: RehtmlOptions, )
| 48 | * 3. Split into stable blocks + live tail for incremental rendering |
| 49 | */ |
| 50 | export function rehtml( |
| 51 | input: string, |
| 52 | options?: RehtmlOptions, |
| 53 | ): RehtmlResult { |
| 54 | const opts = { ...defaultOptions, ...options }; |
| 55 | |
| 56 | if (!input || typeof input !== "string") { |
| 57 | return { |
| 58 | html: "", |
| 59 | stable: [], |
| 60 | live: "", |
| 61 | hadIncompleteTag: false, |
| 62 | }; |
| 63 | } |
| 64 | |
| 65 | let html = input; |
| 66 | let hadIncompleteTag = false; |
| 67 | |
| 68 | if (opts.stripIncomplete) { |
| 69 | const stripped = stripIncompleteTag(html); |
| 70 | hadIncompleteTag = stripped.length !== html.length; |
| 71 | html = stripped; |
| 72 | } |
| 73 | |
| 74 | // Split before auto-closing — only genuinely closed blocks become stable |
| 75 | const { stable, live } = opts.splitBlocks |
| 76 | ? splitHtmlIntoBlocks(html) |
| 77 | : { stable: [] as string[], live: html }; |
| 78 | |
| 79 | const close = (chunk: string) => |
| 80 | opts.closeTags ? closeOpenTags(chunk) : chunk; |
| 81 | |
| 82 | return { |
| 83 | html: close(html), |
| 84 | stable: stable.map(close), |
| 85 | live: close(live), |
| 86 | hadIncompleteTag, |
| 87 | }; |
| 88 | } |
| 89 | |
| 90 | /** Re-export DOMPurify config type for convenience */ |
| 91 | export type SanitizeConfig = Config; |
no test coverage detected