(input, visitors, options)
| 7299 | * @param {HtmlProcessOptions} options process options |
| 7300 | */ |
| 7301 | const grammar = (input, visitors, options) => { |
| 7302 | // Babel's `path.skip()`, children-only. Reset per `enter` dispatch. |
| 7303 | let skipFlag = false; |
| 7304 | const visitorCtx = { |
| 7305 | skipChildren() { |
| 7306 | skipFlag = true; |
| 7307 | } |
| 7308 | }; |
| 7309 | |
| 7310 | /** |
| 7311 | * Fetches the node's visitor bucket once (reused for enter + exit) and uses |
| 7312 | * index loops — `for…of` would allocate an iterator per node on this hot path. |
| 7313 | * @param {HtmlVisitableNode} node subtree root |
| 7314 | * @param {HtmlVisitableNode | null} parent enclosing node |
| 7315 | */ |
| 7316 | const walk = (node, parent) => { |
| 7317 | const b = visitors[node.type]; |
| 7318 | let skip = false; |
| 7319 | if (b !== undefined && b.enter.length !== 0) { |
| 7320 | skipFlag = false; |
| 7321 | const e = b.enter; |
| 7322 | for (let i = 0; i < e.length; i++) e[i](node, parent, visitorCtx); |
| 7323 | skip = skipFlag; |
| 7324 | skipFlag = false; |
| 7325 | } |
| 7326 | if (!skip) { |
| 7327 | if (node.type === NodeType.Element) { |
| 7328 | // `<template>` children live in a separate content fragment, not in |
| 7329 | // `children` — walk it first so template content is not skipped. |
| 7330 | const tc = node.templateContent; |
| 7331 | if (tc !== undefined) walk(tc, node); |
| 7332 | const c = node.children; |
| 7333 | for (let i = 0; i < c.length; i++) walk(c[i], node); |
| 7334 | } else if ( |
| 7335 | node.type === NodeType.Document || |
| 7336 | node.type === NodeType.DocumentFragment |
| 7337 | ) { |
| 7338 | const c = node.children; |
| 7339 | for (let i = 0; i < c.length; i++) walk(c[i], node); |
| 7340 | } |
| 7341 | // All other types are leaves. |
| 7342 | } |
| 7343 | if (b !== undefined) { |
| 7344 | const x = b.exit; |
| 7345 | for (let i = 0; i < x.length; i++) x[i](node, parent, visitorCtx); |
| 7346 | } |
| 7347 | }; |
| 7348 | |
| 7349 | walk(options.ast || buildHtmlAst(input, options.fragmentContext), null); |
| 7350 | }; |
| 7351 | |
| 7352 | /** |
| 7353 | * The generic visitor coordinator (`util/SourceProcessor`) bound to the HTML |
nothing calls this directly
no test coverage detected