Convert src/compiler/compile/render_ssr/handlers/utils/remove_whitespace_children.ts to JavaScript

pull/8569/head
Simon Holthausen 3 years ago
parent eec1af14a8
commit 24ac040c66

@ -1,75 +1,83 @@
import { INode } from '../../../nodes/interfaces'; import { trim_end, trim_start } from '../../../../utils/trim.js';
import { trim_end, trim_start } from '../../../../utils/trim';
import { link } from '../../../../utils/link'; import { link } from '../../../../utils/link';
import { regex_starts_with_whitespace } from '../../../../utils/patterns'; import { regex_starts_with_whitespace } from '../../../../utils/patterns';
// similar logic from `compile/render_dom/wrappers/Fragment` // similar logic from `compile/render_dom/wrappers/Fragment`
// We want to remove trailing whitespace inside an element/component/block, // We want to remove trailing whitespace inside an element/component/block,
// *unless* there is no whitespace between this node and its next sibling // *unless* there is no whitespace between this node and its next sibling
export default function remove_whitespace_children(children: INode[], next?: INode): INode[] {
const nodes: INode[] = []; /**
let last_child: INode; * @param {INode[]} children
* @param {import('../../../nodes/interfaces.js').INode} [next]
* @returns {INode[]}
*/
export default function remove_whitespace_children(children, next) {
/** @type {INode[]} */
const nodes = [];
/** @type {import('../../../nodes/interfaces.js').INode} */
let last_child;
let i = children.length; let i = children.length;
while (i--) { while (i--) {
const child = children[i]; const child = children[i];
if (child.type === 'Text') { if (child.type === 'Text') {
if (child.should_skip()) { if (child.should_skip()) {
continue; continue;
} }
let { data } = child; let { data } = child;
if (nodes.length === 0) { if (nodes.length === 0) {
const should_trim = next const should_trim = next
? next.type === 'Text' && ? next.type === 'Text' &&
regex_starts_with_whitespace.test(next.data) && regex_starts_with_whitespace.test(next.data) &&
trimmable_at(child, next) trimmable_at(child, next)
: !child.has_ancestor('EachBlock'); : !child.has_ancestor('EachBlock');
if (should_trim && !child.keep_space()) { if (should_trim && !child.keep_space()) {
data = trim_end(data); data = trim_end(data);
if (!data) continue; if (!data)
continue;
} }
} }
// glue text nodes (which could e.g. be separated by comments) together // glue text nodes (which could e.g. be separated by comments) together
if (last_child && last_child.type === 'Text') { if (last_child && last_child.type === 'Text') {
last_child.data = data + last_child.data; last_child.data = data + last_child.data;
continue; continue;
} }
child.data = data; child.data = data;
nodes.unshift(child); nodes.unshift(child);
link(last_child, (last_child = child)); link(last_child, (last_child = child));
} else { }
else {
nodes.unshift(child); nodes.unshift(child);
link(last_child, (last_child = child)); link(last_child, (last_child = child));
} }
} }
const first = nodes[0]; const first = nodes[0];
if (first && first.type === 'Text' && !first.keep_space()) { if (first && first.type === 'Text' && !first.keep_space()) {
first.data = trim_start(first.data); first.data = trim_start(first.data);
if (!first.data) { if (!first.data) {
first.var = null; first.var = null;
nodes.shift(); nodes.shift();
if (nodes[0]) { if (nodes[0]) {
nodes[0].prev = null; nodes[0].prev = null;
} }
} }
} }
return nodes; return nodes;
} }
function trimmable_at(child: INode, next_sibling: INode): boolean { /**
* @param {import('../../../nodes/interfaces.js').INode} child
* @param {import('../../../nodes/interfaces.js').INode} next_sibling
* @returns {boolean}
*/
function trimmable_at(child, next_sibling) {
// Whitespace is trimmable if one of the following is true: // Whitespace is trimmable if one of the following is true:
// The child and its sibling share a common nearest each block (not at an each block boundary) // The child and its sibling share a common nearest each block (not at an each block boundary)
// The next sibling's previous node is an each block // The next sibling's previous node is an each block
return ( return (next_sibling.find_nearest(/EachBlock/) === child.find_nearest(/EachBlock/) ||
next_sibling.find_nearest(/EachBlock/) === child.find_nearest(/EachBlock/) || next_sibling.prev.type === 'EachBlock');
next_sibling.prev.type === 'EachBlock'
);
} }

Loading…
Cancel
Save