Skip to content

Commit 82be92c

Browse files
committed
more
1 parent 1eb484e commit 82be92c

File tree

7 files changed

+181
-124
lines changed

7 files changed

+181
-124
lines changed

packages/svelte/src/compiler/phases/3-transform/server/transform-server.js

Lines changed: 12 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,18 @@ import { Fragment } from './visitors/template/Fragment.js';
2121
import { HtmlTag } from './visitors/template/HtmlTag.js';
2222
import { IfBlock } from './visitors/template/IfBlock.js';
2323
import { KeyBlock } from './visitors/template/KeyBlock.js';
24+
import { LetDirective } from './visitors/template/LetDirective.js';
2425
import { RegularElement } from './visitors/template/RegularElement.js';
2526
import { RenderTag } from './visitors/template/RenderTag.js';
27+
import { SlotElement } from './visitors/template/SlotElement.js';
2628
import { SnippetBlock } from './visitors/template/SnippetBlock.js';
29+
import { SpreadAttribute } from './visitors/template/SpreadAttribute.js';
2730
import { SvelteComponent } from './visitors/template/SvelteComponent.js';
2831
import { SvelteElement } from './visitors/template/SvelteElement.js';
32+
import { SvelteFragment } from './visitors/template/SvelteFragment.js';
33+
import { SvelteHead } from './visitors/template/SvelteHead.js';
2934
import { SvelteSelf } from './visitors/template/SvelteSelf.js';
30-
import {
31-
empty_comment,
32-
process_children,
33-
serialize_attribute_value,
34-
serialize_template
35-
} from './visitors/template/shared/utils.js';
35+
import { TitleElement } from './visitors/template/TitleElement.js';
3636

3737
/**
3838
* @param {VariableDeclarator} declarator
@@ -616,124 +616,12 @@ const template_visitors = {
616616
Component,
617617
SvelteSelf,
618618
SvelteComponent,
619-
LetDirective(node, { state }) {
620-
if (node.expression === null || node.expression.type === 'Identifier') {
621-
const name = node.expression === null ? node.name : node.expression.name;
622-
return b.const(name, b.member(b.id('$$slotProps'), b.id(node.name)));
623-
}
624-
625-
const name = state.scope.generate(node.name);
626-
const bindings = state.scope.get_bindings(node);
627-
628-
for (const binding of bindings) {
629-
state.getters[binding.node.name] = b.member(b.id(name), b.id(binding.node.name));
630-
}
631-
632-
return b.const(
633-
name,
634-
b.call(
635-
b.thunk(
636-
b.block([
637-
b.let(
638-
node.expression.type === 'ObjectExpression'
639-
? // @ts-expect-error types don't match, but it can't contain spread elements and the structure is otherwise fine
640-
b.object_pattern(node.expression.properties)
641-
: // @ts-expect-error types don't match, but it can't contain spread elements and the structure is otherwise fine
642-
b.array_pattern(node.expression.elements),
643-
b.member(b.id('$$slotProps'), b.id(node.name))
644-
),
645-
b.return(b.object(bindings.map((binding) => b.init(binding.node.name, binding.node))))
646-
])
647-
)
648-
)
649-
);
650-
},
651-
SpreadAttribute(node, { visit }) {
652-
return visit(node.expression);
653-
},
654-
SvelteFragment(node, context) {
655-
const child_state = {
656-
...context.state,
657-
getters: { ...context.state.getters }
658-
};
659-
660-
for (const attribute of node.attributes) {
661-
if (attribute.type === 'LetDirective') {
662-
context.state.template.push(
663-
/** @type {ExpressionStatement} */ (context.visit(attribute, child_state))
664-
);
665-
}
666-
}
667-
668-
const block = /** @type {BlockStatement} */ (context.visit(node.fragment, child_state));
669-
670-
context.state.template.push(block);
671-
},
672-
TitleElement(node, context) {
673-
// title is guaranteed to contain only text/expression tag children
674-
const template = [b.literal('<title>')];
675-
process_children(node.fragment.nodes, { ...context, state: { ...context.state, template } });
676-
template.push(b.literal('</title>'));
677-
678-
context.state.init.push(...serialize_template(template, b.id('$$payload.title'), '='));
679-
},
680-
SlotElement(node, context) {
681-
/** @type {Property[]} */
682-
const props = [];
683-
684-
/** @type {Expression[]} */
685-
const spreads = [];
686-
687-
/** @type {ExpressionStatement[]} */
688-
const lets = [];
689-
690-
/** @type {Expression} */
691-
let expression = b.call('$.default_slot', b.id('$$props'));
692-
693-
for (const attribute of node.attributes) {
694-
if (attribute.type === 'SpreadAttribute') {
695-
spreads.push(/** @type {Expression} */ (context.visit(attribute)));
696-
} else if (attribute.type === 'Attribute') {
697-
const value = serialize_attribute_value(attribute.value, context, false, true);
698-
699-
if (attribute.name === 'name') {
700-
expression = b.member(b.member_id('$$props.$$slots'), value, true, true);
701-
} else if (attribute.name !== 'slot') {
702-
if (attribute.metadata.dynamic) {
703-
props.push(b.get(attribute.name, [b.return(value)]));
704-
} else {
705-
props.push(b.init(attribute.name, value));
706-
}
707-
}
708-
} else if (attribute.type === 'LetDirective') {
709-
lets.push(/** @type {ExpressionStatement} */ (context.visit(attribute)));
710-
}
711-
}
712-
713-
// Let bindings first, they can be used on attributes
714-
context.state.init.push(...lets);
715-
716-
const props_expression =
717-
spreads.length === 0
718-
? b.object(props)
719-
: b.call('$.spread_props', b.array([b.object(props), ...spreads]));
720-
721-
const fallback =
722-
node.fragment.nodes.length === 0
723-
? b.literal(null)
724-
: b.thunk(/** @type {BlockStatement} */ (context.visit(node.fragment)));
725-
726-
const slot = b.call('$.slot', b.id('$$payload'), expression, props_expression, fallback);
727-
728-
context.state.template.push(empty_comment, b.stmt(slot), empty_comment);
729-
},
730-
SvelteHead(node, context) {
731-
const block = /** @type {BlockStatement} */ (context.visit(node.fragment));
732-
733-
context.state.template.push(
734-
b.stmt(b.call('$.head', b.id('$$payload'), b.arrow([b.id('$$payload')], block)))
735-
);
736-
}
619+
LetDirective,
620+
SpreadAttribute,
621+
SvelteFragment,
622+
TitleElement,
623+
SlotElement,
624+
SvelteHead
737625
};
738626

739627
/**
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/** @import { LetDirective } from '#compiler' */
2+
/** @import { ComponentContext } from '../../types' */
3+
import * as b from '../../../../../utils/builders.js';
4+
5+
/**
6+
* @param {LetDirective} node
7+
* @param {ComponentContext} context
8+
*/
9+
export function LetDirective(node, context) {
10+
if (node.expression === null || node.expression.type === 'Identifier') {
11+
const name = node.expression === null ? node.name : node.expression.name;
12+
return b.const(name, b.member(b.id('$$slotProps'), b.id(node.name)));
13+
}
14+
15+
const name = context.state.scope.generate(node.name);
16+
const bindings = context.state.scope.get_bindings(node);
17+
18+
for (const binding of bindings) {
19+
context.state.getters[binding.node.name] = b.member(b.id(name), b.id(binding.node.name));
20+
}
21+
22+
return b.const(
23+
name,
24+
b.call(
25+
b.thunk(
26+
b.block([
27+
b.let(
28+
node.expression.type === 'ObjectExpression'
29+
? // @ts-expect-error types don't match, but it can't contain spread elements and the structure is otherwise fine
30+
b.object_pattern(node.expression.properties)
31+
: // @ts-expect-error types don't match, but it can't contain spread elements and the structure is otherwise fine
32+
b.array_pattern(node.expression.elements),
33+
b.member(b.id('$$slotProps'), b.id(node.name))
34+
),
35+
b.return(b.object(bindings.map((binding) => b.init(binding.node.name, binding.node))))
36+
])
37+
)
38+
)
39+
);
40+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/** @import { BlockStatement, Expression, ExpressionStatement, Property } from 'estree' */
2+
/** @import { SlotElement } from '#compiler' */
3+
/** @import { ComponentContext } from '../../types' */
4+
import * as b from '../../../../../utils/builders.js';
5+
import { empty_comment, serialize_attribute_value } from './shared/utils.js';
6+
7+
/**
8+
* @param {SlotElement} node
9+
* @param {ComponentContext} context
10+
*/
11+
export function SlotElement(node, context) {
12+
/** @type {Property[]} */
13+
const props = [];
14+
15+
/** @type {Expression[]} */
16+
const spreads = [];
17+
18+
/** @type {ExpressionStatement[]} */
19+
const lets = [];
20+
21+
/** @type {Expression} */
22+
let expression = b.call('$.default_slot', b.id('$$props'));
23+
24+
for (const attribute of node.attributes) {
25+
if (attribute.type === 'SpreadAttribute') {
26+
spreads.push(/** @type {Expression} */ (context.visit(attribute)));
27+
} else if (attribute.type === 'Attribute') {
28+
const value = serialize_attribute_value(attribute.value, context, false, true);
29+
30+
if (attribute.name === 'name') {
31+
expression = b.member(b.member_id('$$props.$$slots'), value, true, true);
32+
} else if (attribute.name !== 'slot') {
33+
if (attribute.metadata.dynamic) {
34+
props.push(b.get(attribute.name, [b.return(value)]));
35+
} else {
36+
props.push(b.init(attribute.name, value));
37+
}
38+
}
39+
} else if (attribute.type === 'LetDirective') {
40+
lets.push(/** @type {ExpressionStatement} */ (context.visit(attribute)));
41+
}
42+
}
43+
44+
// Let bindings first, they can be used on attributes
45+
context.state.init.push(...lets);
46+
47+
const props_expression =
48+
spreads.length === 0
49+
? b.object(props)
50+
: b.call('$.spread_props', b.array([b.object(props), ...spreads]));
51+
52+
const fallback =
53+
node.fragment.nodes.length === 0
54+
? b.literal(null)
55+
: b.thunk(/** @type {BlockStatement} */ (context.visit(node.fragment)));
56+
57+
const slot = b.call('$.slot', b.id('$$payload'), expression, props_expression, fallback);
58+
59+
context.state.template.push(empty_comment, b.stmt(slot), empty_comment);
60+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/** @import { SpreadAttribute } from '#compiler' */
2+
/** @import { ComponentContext } from '../../types' */
3+
4+
/**
5+
* @param {SpreadAttribute} node
6+
* @param {ComponentContext} context
7+
*/
8+
export function SpreadAttribute(node, context) {
9+
return context.visit(node.expression);
10+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/** @import { BlockStatement, ExpressionStatement } from 'estree' */
2+
/** @import { SvelteFragment } from '#compiler' */
3+
/** @import { ComponentContext } from '../../types' */
4+
5+
/**
6+
* @param {SvelteFragment} node
7+
* @param {ComponentContext} context
8+
*/
9+
export function SvelteFragment(node, context) {
10+
const child_state = {
11+
...context.state,
12+
getters: { ...context.state.getters }
13+
};
14+
15+
for (const attribute of node.attributes) {
16+
if (attribute.type === 'LetDirective') {
17+
context.state.template.push(
18+
/** @type {ExpressionStatement} */ (context.visit(attribute, child_state))
19+
);
20+
}
21+
}
22+
23+
const block = /** @type {BlockStatement} */ (context.visit(node.fragment, child_state));
24+
25+
context.state.template.push(block);
26+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/** @import { BlockStatement } from 'estree' */
2+
/** @import { SvelteHead } from '#compiler' */
3+
/** @import { ComponentContext } from '../../types' */
4+
import * as b from '../../../../../utils/builders.js';
5+
6+
/**
7+
* @param {SvelteHead} node
8+
* @param {ComponentContext} context
9+
*/
10+
export function SvelteHead(node, context) {
11+
const block = /** @type {BlockStatement} */ (context.visit(node.fragment));
12+
13+
context.state.template.push(
14+
b.stmt(b.call('$.head', b.id('$$payload'), b.arrow([b.id('$$payload')], block)))
15+
);
16+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/** @import { TitleElement } from '#compiler' */
2+
/** @import { ComponentContext } from '../../types' */
3+
import * as b from '../../../../../utils/builders.js';
4+
import { process_children, serialize_template } from './shared/utils.js';
5+
6+
/**
7+
* @param {TitleElement} node
8+
* @param {ComponentContext} context
9+
*/
10+
export function TitleElement(node, context) {
11+
// title is guaranteed to contain only text/expression tag children
12+
const template = [b.literal('<title>')];
13+
process_children(node.fragment.nodes, { ...context, state: { ...context.state, template } });
14+
template.push(b.literal('</title>'));
15+
16+
context.state.init.push(...serialize_template(template, b.id('$$payload.title'), '='));
17+
}

0 commit comments

Comments
 (0)