Skip to content

Commit b42ef49

Browse files
authored
Merge pull request #512 from sveltejs/gh-3
Anchor-less if and each blocks
2 parents 09b1635 + 4fe20fb commit b42ef49

File tree

17 files changed

+464
-128
lines changed

17 files changed

+464
-128
lines changed

src/generators/dom/Block.js

-5
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,6 @@ export default class Block {
8787
return this.generator.contextualise( this, expression, context, isEventHandler );
8888
}
8989

90-
createAnchor ( name, parentNode ) {
91-
const renderStatement = `${this.generator.helper( 'createComment' )}()`;
92-
this.addElement( name, renderStatement, parentNode, true );
93-
}
94-
9590
findDependencies ( expression ) {
9691
return this.generator.findDependencies( this.contextDependencies, this.indexes, expression );
9792
}

src/generators/dom/index.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,14 @@ export default function dom ( parsed, source, options ) {
4343

4444
const { computations, hasJs, templateProperties, namespace } = generator.parseJs();
4545

46-
const block = preprocess( generator, parsed.html );
47-
4846
const state = {
4947
namespace,
5048
parentNode: null,
5149
isTopLevel: true
5250
};
5351

52+
const block = preprocess( generator, state, parsed.html );
53+
5454
parsed.html.children.forEach( node => {
5555
visit( generator, block, state, node );
5656
});

src/generators/dom/preprocess.js

+115-32
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,62 @@
11
import Block from './Block.js';
22
import { trimStart, trimEnd } from '../../utils/trim.js';
3+
import { assign } from '../../shared/index.js';
34

45
function isElseIf ( node ) {
56
return node && node.children.length === 1 && node.children[0].type === 'IfBlock';
67
}
78

9+
function getChildState ( parent, child ) {
10+
return assign( {}, parent, { name: null, parentNode: null }, child || {} );
11+
}
12+
13+
// Whitespace inside one of these elements will not result in
14+
// a whitespace node being created in any circumstances. (This
15+
// list is almost certainly very incomplete)
16+
const elementsWithoutText = new Set([
17+
'audio',
18+
'datalist',
19+
'dl',
20+
'ol',
21+
'optgroup',
22+
'select',
23+
'ul',
24+
'video'
25+
]);
26+
827
const preprocessors = {
9-
MustacheTag: ( generator, block, node ) => {
28+
MustacheTag: ( generator, block, state, node ) => {
29+
const dependencies = block.findDependencies( node.expression );
30+
block.addDependencies( dependencies );
31+
32+
node._state = getChildState( state, {
33+
name: block.getUniqueName( 'text' )
34+
});
35+
},
36+
37+
RawMustacheTag: ( generator, block, state, node ) => {
1038
const dependencies = block.findDependencies( node.expression );
1139
block.addDependencies( dependencies );
40+
41+
const basename = block.getUniqueName( 'raw' );
42+
const name = block.getUniqueName( `${basename}_before` );
43+
44+
node._state = getChildState( state, { basename, name });
45+
},
46+
47+
Text: ( generator, block, state, node ) => {
48+
node._state = getChildState( state );
49+
50+
if ( !/\S/.test( node.data ) ) {
51+
if ( state.namespace ) return;
52+
if ( elementsWithoutText.has( state.parentNodeName ) ) return;
53+
}
54+
55+
node._state.shouldCreate = true;
56+
node._state.name = block.getUniqueName( `text` );
1257
},
1358

14-
IfBlock: ( generator, block, node ) => {
59+
IfBlock: ( generator, block, state, node ) => {
1560
const blocks = [];
1661
let dynamic = false;
1762

@@ -23,8 +68,10 @@ const preprocessors = {
2368
name: generator.getUniqueName( `create_if_block` )
2469
});
2570

71+
node._state = getChildState( state );
72+
2673
blocks.push( node._block );
27-
preprocessChildren( generator, node._block, node );
74+
preprocessChildren( generator, node._block, node._state, node );
2875

2976
if ( node._block.dependencies.size > 0 ) {
3077
dynamic = true;
@@ -38,8 +85,10 @@ const preprocessors = {
3885
name: generator.getUniqueName( `create_if_block` )
3986
});
4087

88+
node.else._state = getChildState( state );
89+
4190
blocks.push( node.else._block );
42-
preprocessChildren( generator, node.else._block, node.else );
91+
preprocessChildren( generator, node.else._block, node.else._state, node.else );
4392

4493
if ( node.else._block.dependencies.size > 0 ) {
4594
dynamic = true;
@@ -57,7 +106,7 @@ const preprocessors = {
57106
generator.blocks.push( ...blocks );
58107
},
59108

60-
EachBlock: ( generator, block, node ) => {
109+
EachBlock: ( generator, block, state, node ) => {
61110
const dependencies = block.findDependencies( node.expression );
62111
block.addDependencies( dependencies );
63112

@@ -97,8 +146,12 @@ const preprocessors = {
97146
params: block.params.concat( listName, context, indexName )
98147
});
99148

149+
node._state = getChildState( state, {
150+
inEachBlock: true
151+
});
152+
100153
generator.blocks.push( node._block );
101-
preprocessChildren( generator, node._block, node );
154+
preprocessChildren( generator, node._block, node._state, node );
102155
block.addDependencies( node._block.dependencies );
103156
node._block.hasUpdateMethod = node._block.dependencies.size > 0;
104157

@@ -107,13 +160,32 @@ const preprocessors = {
107160
name: generator.getUniqueName( `${node._block.name}_else` )
108161
});
109162

163+
node.else._state = getChildState( state );
164+
110165
generator.blocks.push( node.else._block );
111-
preprocessChildren( generator, node.else._block, node.else );
166+
preprocessChildren( generator, node.else._block, node.else._state, node.else );
112167
node.else._block.hasUpdateMethod = node.else._block.dependencies.size > 0;
113168
}
114169
},
115170

116-
Element: ( generator, block, node ) => {
171+
Element: ( generator, block, state, node ) => {
172+
const isComponent = generator.components.has( node.name ) || node.name === ':Self';
173+
174+
if ( isComponent ) {
175+
node._state = getChildState( state );
176+
} else {
177+
const name = block.getUniqueName( node.name.replace( /[^a-zA-Z0-9_$]/g, '_' ) );
178+
179+
node._state = getChildState( state, {
180+
isTopLevel: false,
181+
name,
182+
parentNode: name,
183+
parentNodeName: node.name,
184+
namespace: node.name === 'svg' ? 'http://www.w3.org/2000/svg' : state.namespace,
185+
allUsedContexts: []
186+
});
187+
}
188+
117189
node.attributes.forEach( attribute => {
118190
if ( attribute.type === 'Attribute' && attribute.value !== true ) {
119191
attribute.value.forEach( chunk => {
@@ -130,8 +202,6 @@ const preprocessors = {
130202
}
131203
});
132204

133-
const isComponent = generator.components.has( node.name ) || node.name === ':Self';
134-
135205
if ( node.children.length ) {
136206
if ( isComponent ) {
137207
const name = block.getUniqueName( ( node.name === ':Self' ? generator.name : node.name ).toLowerCase() );
@@ -141,21 +211,19 @@ const preprocessors = {
141211
});
142212

143213
generator.blocks.push( node._block );
144-
preprocessChildren( generator, node._block, node );
214+
preprocessChildren( generator, node._block, node._state, node );
145215
block.addDependencies( node._block.dependencies );
146216
node._block.hasUpdateMethod = node._block.dependencies.size > 0;
147217
}
148218

149219
else {
150-
preprocessChildren( generator, block, node );
220+
preprocessChildren( generator, block, node._state, node );
151221
}
152222
}
153223
}
154224
};
155225

156-
preprocessors.RawMustacheTag = preprocessors.MustacheTag;
157-
158-
function preprocessChildren ( generator, block, node ) {
226+
function preprocessChildren ( generator, block, state, node, isTopLevel ) {
159227
// glue text nodes together
160228
const cleaned = [];
161229
let lastChild;
@@ -173,15 +241,43 @@ function preprocessChildren ( generator, block, node ) {
173241
lastChild = child;
174242
});
175243

176-
node.children = cleaned;
244+
if ( isTopLevel ) {
245+
// trim leading and trailing whitespace from the top level
246+
const firstChild = cleaned[0];
247+
if ( firstChild && firstChild.type === 'Text' ) {
248+
firstChild.data = trimStart( firstChild.data );
249+
if ( !firstChild.data ) cleaned.shift();
250+
}
251+
252+
const lastChild = cleaned[ cleaned.length - 1 ];
253+
if ( lastChild && lastChild.type === 'Text' ) {
254+
lastChild.data = trimEnd( lastChild.data );
255+
if ( !lastChild.data ) cleaned.pop();
256+
}
257+
}
258+
259+
lastChild = null;
177260

178261
cleaned.forEach( child => {
179262
const preprocess = preprocessors[ child.type ];
180-
if ( preprocess ) preprocess( generator, block, child );
263+
if ( preprocess ) preprocess( generator, block, state, child );
264+
265+
if ( lastChild ) {
266+
lastChild.next = child;
267+
lastChild.needsAnchor = !child._state.name;
268+
}
269+
270+
lastChild = child;
181271
});
272+
273+
if ( lastChild ) {
274+
lastChild.needsAnchor = !state.parentNode;
275+
}
276+
277+
node.children = cleaned;
182278
}
183279

184-
export default function preprocess ( generator, node ) {
280+
export default function preprocess ( generator, state, node ) {
185281
const block = new Block({
186282
generator,
187283
name: generator.alias( 'create_main_fragment' ),
@@ -199,21 +295,8 @@ export default function preprocess ( generator, node ) {
199295
});
200296

201297
generator.blocks.push( block );
202-
preprocessChildren( generator, block, node );
298+
preprocessChildren( generator, block, state, node, true );
203299
block.hasUpdateMethod = block.dependencies.size > 0;
204300

205-
// trim leading and trailing whitespace from the top level
206-
const firstChild = node.children[0];
207-
if ( firstChild && firstChild.type === 'Text' ) {
208-
firstChild.data = trimStart( firstChild.data );
209-
if ( !firstChild.data ) node.children.shift();
210-
}
211-
212-
const lastChild = node.children[ node.children.length - 1 ];
213-
if ( lastChild && lastChild.type === 'Text' ) {
214-
lastChild.data = trimEnd( lastChild.data );
215-
if ( !lastChild.data ) node.children.pop();
216-
}
217-
218301
return block;
219302
}

src/generators/dom/visitors/Component/Component.js

+1-3
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,7 @@ export default function visitComponent ( generator, block, state, node ) {
3636
const hasChildren = node.children.length > 0;
3737
const name = block.getUniqueName( ( node.name === ':Self' ? generator.name : node.name ).toLowerCase() );
3838

39-
const childState = Object.assign( {}, state, {
40-
parentNode: null
41-
});
39+
const childState = node._state;
4240

4341
const local = {
4442
name,

0 commit comments

Comments
 (0)