(root: AstNode, schema: Schema, settings: DomParserSettings, args: ParserArgs)
| 174 | // |
| 175 | // Returns [ preprocess, postprocess ] |
| 176 | const whitespaceCleaner = (root: AstNode, schema: Schema, settings: DomParserSettings, args: ParserArgs): [WalkerCallback, WalkerCallback] => { |
| 177 | const validate = settings.validate; |
| 178 | const nonEmptyElements = schema.getNonEmptyElements(); |
| 179 | const whitespaceElements = schema.getWhitespaceElements(); |
| 180 | const blockElements: Record<string, string> = extend(makeMap(extraBlockLikeElements), schema.getBlockElements()); |
| 181 | const textRootBlockElements = getTextRootBlockElements(schema); |
| 182 | const allWhiteSpaceRegExp = /[ \t\r\n]+/g; |
| 183 | const startWhiteSpaceRegExp = /^[ \t\r\n]+/; |
| 184 | const endWhiteSpaceRegExp = /[ \t\r\n]+$/; |
| 185 | |
| 186 | const hasWhitespaceParent = (node: AstNode) => { |
| 187 | let tempNode = node.parent; |
| 188 | while (Type.isNonNullable(tempNode)) { |
| 189 | if (tempNode.name in whitespaceElements) { |
| 190 | return true; |
| 191 | } else { |
| 192 | tempNode = tempNode.parent; |
| 193 | } |
| 194 | } |
| 195 | return false; |
| 196 | }; |
| 197 | |
| 198 | const isTextRootBlockEmpty = (node: AstNode) => { |
| 199 | let tempNode: AstNode | null | undefined = node; |
| 200 | while (Type.isNonNullable(tempNode)) { |
| 201 | if (tempNode.name in textRootBlockElements) { |
| 202 | return isEmpty(schema, nonEmptyElements, whitespaceElements, tempNode); |
| 203 | } else { |
| 204 | tempNode = tempNode.parent; |
| 205 | } |
| 206 | } |
| 207 | return false; |
| 208 | }; |
| 209 | |
| 210 | const isBlock = (node: AstNode) => |
| 211 | node.name in blockElements || TransparentElements.isTransparentAstBlock(schema, node) || (Namespace.isNonHtmlElementRootName(node.name) && node.parent === root); |
| 212 | |
| 213 | const isAtEdgeOfBlock = (node: AstNode, start: boolean): boolean => { |
| 214 | const neighbour = start ? node.prev : node.next; |
| 215 | if (Type.isNonNullable(neighbour) || Type.isNullable(node.parent)) { |
| 216 | return false; |
| 217 | } |
| 218 | |
| 219 | // Make sure our parent is actually a block, and also make sure it isn't a temporary "context" element |
| 220 | // that we're probably going to unwrap as soon as we insert this content into the editor |
| 221 | return isBlock(node.parent) && (node.parent !== root || args.isRootContent === true); |
| 222 | }; |
| 223 | |
| 224 | const preprocess = (node: AstNode) => { |
| 225 | if (node.type === 3) { |
| 226 | // Remove leading whitespace here, so that all whitespace in nodes to the left of us has already been fixed |
| 227 | if (!hasWhitespaceParent(node)) { |
| 228 | let text = node.value ?? ''; |
| 229 | text = text.replace(allWhiteSpaceRegExp, ' '); |
| 230 | |
| 231 | if (isLineBreakNode(node.prev, isBlock) || isAtEdgeOfBlock(node, true)) { |
| 232 | text = text.replace(startWhiteSpaceRegExp, ''); |
| 233 | } |
no test coverage detected
searching dependent graphs…