Skip to content

Commit 6b1582c

Browse files
committed
remove create_block
1 parent c861477 commit 6b1582c

File tree

1 file changed

+178
-185
lines changed
  • packages/svelte/src/compiler/phases/3-transform/client/visitors

1 file changed

+178
-185
lines changed

packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js

Lines changed: 178 additions & 185 deletions
Original file line numberDiff line numberDiff line change
@@ -1028,190 +1028,6 @@ function serialize_locations(locations) {
10281028
);
10291029
}
10301030

1031-
/**
1032-
* Creates a new block which looks roughly like this:
1033-
* ```js
1034-
* // hoisted:
1035-
* const block_name = $.template(`...`);
1036-
*
1037-
* // for the main block:
1038-
* const id = block_name();
1039-
* // init stuff and possibly render effect
1040-
* $.append($$anchor, id);
1041-
* ```
1042-
* Adds the hoisted parts to `context.state.hoisted` and returns the statements of the main block.
1043-
* @param {import('#compiler').SvelteNode} parent
1044-
* @param {import('#compiler').Fragment} fragment
1045-
* @param {string} name
1046-
* @param {import('#compiler').SvelteNode[]} nodes
1047-
* @param {import('../types.js').ComponentContext} context
1048-
* @returns {import('estree').Statement[]}
1049-
*/
1050-
function create_block(parent, fragment, name, nodes, context) {
1051-
const namespace = infer_namespace(context.state.metadata.namespace, parent, nodes);
1052-
1053-
const { hoisted, trimmed } = clean_nodes(
1054-
parent,
1055-
nodes,
1056-
context.path,
1057-
namespace,
1058-
context.state,
1059-
context.state.preserve_whitespace,
1060-
context.state.options.preserveComments
1061-
);
1062-
1063-
if (hoisted.length === 0 && trimmed.length === 0) {
1064-
return [];
1065-
}
1066-
1067-
const is_single_element = trimmed.length === 1 && trimmed[0].type === 'RegularElement';
1068-
const is_single_child_not_needing_template =
1069-
trimmed.length === 1 &&
1070-
(trimmed[0].type === 'SvelteFragment' || trimmed[0].type === 'TitleElement');
1071-
1072-
const template_name = context.state.scope.root.unique(name);
1073-
1074-
/** @type {import('estree').Statement[]} */
1075-
const body = [];
1076-
1077-
/** @type {import('estree').Statement | undefined} */
1078-
let close = undefined;
1079-
1080-
/** @type {import('../types').ComponentClientTransformState} */
1081-
const state = {
1082-
...context.state,
1083-
scope: context.state.scopes.get(fragment) ?? context.state.scope,
1084-
before_init: [],
1085-
init: [],
1086-
update: [],
1087-
after_update: [],
1088-
template: [],
1089-
locations: [],
1090-
metadata: {
1091-
context: {
1092-
template_needs_import_node: false,
1093-
template_contains_script_tag: false
1094-
},
1095-
namespace,
1096-
bound_contenteditable: context.state.metadata.bound_contenteditable
1097-
}
1098-
};
1099-
1100-
for (const node of hoisted) {
1101-
context.visit(node, state);
1102-
}
1103-
1104-
/**
1105-
* @param {import('estree').Identifier} template_name
1106-
* @param {import('estree').Expression[]} args
1107-
*/
1108-
const add_template = (template_name, args) => {
1109-
let call = b.call(get_template_function(namespace, state), ...args);
1110-
if (context.state.options.dev) {
1111-
call = b.call(
1112-
'$.add_locations',
1113-
call,
1114-
b.member(b.id(context.state.analysis.name), b.id('filename')),
1115-
serialize_locations(state.locations)
1116-
);
1117-
}
1118-
1119-
context.state.hoisted.push(b.var(template_name, call));
1120-
};
1121-
1122-
if (is_single_element) {
1123-
const element = /** @type {import('#compiler').RegularElement} */ (trimmed[0]);
1124-
1125-
const id = b.id(context.state.scope.generate(element.name));
1126-
1127-
context.visit(element, {
1128-
...state,
1129-
node: id
1130-
});
1131-
1132-
/** @type {import('estree').Expression[]} */
1133-
const args = [b.template([b.quasi(state.template.join(''), true)], [])];
1134-
1135-
if (state.metadata.context.template_needs_import_node) {
1136-
args.push(b.literal(TEMPLATE_USE_IMPORT_NODE));
1137-
}
1138-
1139-
add_template(template_name, args);
1140-
1141-
body.push(b.var(id, b.call(template_name)), ...state.before_init, ...state.init);
1142-
close = b.stmt(b.call('$.append', b.id('$$anchor'), id));
1143-
} else if (is_single_child_not_needing_template) {
1144-
context.visit(trimmed[0], state);
1145-
body.push(...state.before_init, ...state.init);
1146-
} else if (trimmed.length > 0) {
1147-
const id = b.id(context.state.scope.generate('fragment'));
1148-
1149-
const use_space_template =
1150-
trimmed.some((node) => node.type === 'ExpressionTag') &&
1151-
trimmed.every((node) => node.type === 'Text' || node.type === 'ExpressionTag');
1152-
1153-
if (use_space_template) {
1154-
// special case — we can use `$.text` instead of creating a unique template
1155-
const id = b.id(context.state.scope.generate('text'));
1156-
1157-
process_children(trimmed, () => id, false, {
1158-
...context,
1159-
state
1160-
});
1161-
1162-
body.push(b.var(id, b.call('$.text', b.id('$$anchor'))), ...state.before_init, ...state.init);
1163-
close = b.stmt(b.call('$.append', b.id('$$anchor'), id));
1164-
} else {
1165-
/** @type {(is_text: boolean) => import('estree').Expression} */
1166-
const expression = (is_text) =>
1167-
is_text ? b.call('$.first_child', id, b.true) : b.call('$.first_child', id);
1168-
1169-
process_children(trimmed, expression, false, { ...context, state });
1170-
1171-
const use_comment_template = state.template.length === 1 && state.template[0] === '<!>';
1172-
1173-
if (use_comment_template) {
1174-
// special case — we can use `$.comment` instead of creating a unique template
1175-
body.push(b.var(id, b.call('$.comment')));
1176-
} else {
1177-
let flags = TEMPLATE_FRAGMENT;
1178-
1179-
if (state.metadata.context.template_needs_import_node) {
1180-
flags |= TEMPLATE_USE_IMPORT_NODE;
1181-
}
1182-
1183-
add_template(template_name, [
1184-
b.template([b.quasi(state.template.join(''), true)], []),
1185-
b.literal(flags)
1186-
]);
1187-
1188-
body.push(b.var(id, b.call(template_name)));
1189-
}
1190-
1191-
body.push(...state.before_init, ...state.init);
1192-
1193-
close = b.stmt(b.call('$.append', b.id('$$anchor'), id));
1194-
}
1195-
} else {
1196-
body.push(...state.before_init, ...state.init);
1197-
}
1198-
1199-
if (state.update.length > 0) {
1200-
body.push(serialize_render_stmt(state));
1201-
}
1202-
1203-
body.push(...state.after_update);
1204-
1205-
if (close !== undefined) {
1206-
// It's important that close is the last statement in the block, as any previous statements
1207-
// could contain element insertions into the template, which the close statement needs to
1208-
// know of when constructing the list of current inner elements.
1209-
body.push(close);
1210-
}
1211-
1212-
return body;
1213-
}
1214-
12151031
/**
12161032
*
12171033
* @param {import('#compiler').Namespace} namespace
@@ -1701,7 +1517,184 @@ function serialize_template_literal(values, visit, state) {
17011517
/** @type {import('../types').ComponentVisitors} */
17021518
export const template_visitors = {
17031519
Fragment(node, context) {
1704-
const body = create_block(context.path.at(-1) ?? node, node, 'root', node.nodes, context);
1520+
// Creates a new block which looks roughly like this:
1521+
// ```js
1522+
// // hoisted:
1523+
// const block_name = $.template(`...`);
1524+
//
1525+
// // for the main block:
1526+
// const id = block_name();
1527+
// // init stuff and possibly render effect
1528+
// $.append($$anchor, id);
1529+
// ```
1530+
// Adds the hoisted parts to `context.state.hoisted` and returns the statements of the main block.
1531+
1532+
const parent = context.path.at(-1) ?? node;
1533+
1534+
const namespace = infer_namespace(context.state.metadata.namespace, parent, node.nodes);
1535+
1536+
const { hoisted, trimmed } = clean_nodes(
1537+
parent,
1538+
node.nodes,
1539+
context.path,
1540+
namespace,
1541+
context.state,
1542+
context.state.preserve_whitespace,
1543+
context.state.options.preserveComments
1544+
);
1545+
1546+
if (hoisted.length === 0 && trimmed.length === 0) {
1547+
return b.block([]);
1548+
}
1549+
1550+
const is_single_element = trimmed.length === 1 && trimmed[0].type === 'RegularElement';
1551+
const is_single_child_not_needing_template =
1552+
trimmed.length === 1 &&
1553+
(trimmed[0].type === 'SvelteFragment' || trimmed[0].type === 'TitleElement');
1554+
1555+
const template_name = context.state.scope.root.unique('root'); // TODO infer name from parent
1556+
1557+
/** @type {import('estree').Statement[]} */
1558+
const body = [];
1559+
1560+
/** @type {import('estree').Statement | undefined} */
1561+
let close = undefined;
1562+
1563+
/** @type {import('../types').ComponentClientTransformState} */
1564+
const state = {
1565+
...context.state,
1566+
before_init: [],
1567+
init: [],
1568+
update: [],
1569+
after_update: [],
1570+
template: [],
1571+
locations: [],
1572+
metadata: {
1573+
context: {
1574+
template_needs_import_node: false,
1575+
template_contains_script_tag: false
1576+
},
1577+
namespace,
1578+
bound_contenteditable: context.state.metadata.bound_contenteditable
1579+
}
1580+
};
1581+
1582+
for (const node of hoisted) {
1583+
context.visit(node, state);
1584+
}
1585+
1586+
/**
1587+
* @param {import('estree').Identifier} template_name
1588+
* @param {import('estree').Expression[]} args
1589+
*/
1590+
const add_template = (template_name, args) => {
1591+
let call = b.call(get_template_function(namespace, state), ...args);
1592+
if (context.state.options.dev) {
1593+
call = b.call(
1594+
'$.add_locations',
1595+
call,
1596+
b.member(b.id(context.state.analysis.name), b.id('filename')),
1597+
serialize_locations(state.locations)
1598+
);
1599+
}
1600+
1601+
context.state.hoisted.push(b.var(template_name, call));
1602+
};
1603+
1604+
if (is_single_element) {
1605+
const element = /** @type {import('#compiler').RegularElement} */ (trimmed[0]);
1606+
1607+
const id = b.id(context.state.scope.generate(element.name));
1608+
1609+
context.visit(element, {
1610+
...state,
1611+
node: id
1612+
});
1613+
1614+
/** @type {import('estree').Expression[]} */
1615+
const args = [b.template([b.quasi(state.template.join(''), true)], [])];
1616+
1617+
if (state.metadata.context.template_needs_import_node) {
1618+
args.push(b.literal(TEMPLATE_USE_IMPORT_NODE));
1619+
}
1620+
1621+
add_template(template_name, args);
1622+
1623+
body.push(b.var(id, b.call(template_name)), ...state.before_init, ...state.init);
1624+
close = b.stmt(b.call('$.append', b.id('$$anchor'), id));
1625+
} else if (is_single_child_not_needing_template) {
1626+
context.visit(trimmed[0], state);
1627+
body.push(...state.before_init, ...state.init);
1628+
} else if (trimmed.length > 0) {
1629+
const id = b.id(context.state.scope.generate('fragment'));
1630+
1631+
const use_space_template =
1632+
trimmed.some((node) => node.type === 'ExpressionTag') &&
1633+
trimmed.every((node) => node.type === 'Text' || node.type === 'ExpressionTag');
1634+
1635+
if (use_space_template) {
1636+
// special case — we can use `$.text` instead of creating a unique template
1637+
const id = b.id(context.state.scope.generate('text'));
1638+
1639+
process_children(trimmed, () => id, false, {
1640+
...context,
1641+
state
1642+
});
1643+
1644+
body.push(
1645+
b.var(id, b.call('$.text', b.id('$$anchor'))),
1646+
...state.before_init,
1647+
...state.init
1648+
);
1649+
close = b.stmt(b.call('$.append', b.id('$$anchor'), id));
1650+
} else {
1651+
/** @type {(is_text: boolean) => import('estree').Expression} */
1652+
const expression = (is_text) =>
1653+
is_text ? b.call('$.first_child', id, b.true) : b.call('$.first_child', id);
1654+
1655+
process_children(trimmed, expression, false, { ...context, state });
1656+
1657+
const use_comment_template = state.template.length === 1 && state.template[0] === '<!>';
1658+
1659+
if (use_comment_template) {
1660+
// special case — we can use `$.comment` instead of creating a unique template
1661+
body.push(b.var(id, b.call('$.comment')));
1662+
} else {
1663+
let flags = TEMPLATE_FRAGMENT;
1664+
1665+
if (state.metadata.context.template_needs_import_node) {
1666+
flags |= TEMPLATE_USE_IMPORT_NODE;
1667+
}
1668+
1669+
add_template(template_name, [
1670+
b.template([b.quasi(state.template.join(''), true)], []),
1671+
b.literal(flags)
1672+
]);
1673+
1674+
body.push(b.var(id, b.call(template_name)));
1675+
}
1676+
1677+
body.push(...state.before_init, ...state.init);
1678+
1679+
close = b.stmt(b.call('$.append', b.id('$$anchor'), id));
1680+
}
1681+
} else {
1682+
body.push(...state.before_init, ...state.init);
1683+
}
1684+
1685+
if (state.update.length > 0) {
1686+
body.push(serialize_render_stmt(state));
1687+
}
1688+
1689+
body.push(...state.after_update);
1690+
1691+
if (close !== undefined) {
1692+
// It's important that close is the last statement in the block, as any previous statements
1693+
// could contain element insertions into the template, which the close statement needs to
1694+
// know of when constructing the list of current inner elements.
1695+
body.push(close);
1696+
}
1697+
17051698
return b.block(body);
17061699
},
17071700
Comment(node, context) {

0 commit comments

Comments
 (0)