Skip to content

Commit 357af90

Browse files
committed
Merge branch 'master' into gh-40
2 parents d6962b3 + c2275f3 commit 357af90

File tree

8 files changed

+176
-21
lines changed

8 files changed

+176
-21
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ coverage
1111
coverage.lcov
1212
test/sourcemaps/*/output.js
1313
test/sourcemaps/*/output.js.map
14+
_actual.json

CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Svelte changelog
22

3+
## 1.8.0
4+
5+
* Prevent duplicate imports ([#308](https://github.com/sveltejs/svelte/issues/308))
6+
* Use `input` events (not `change`) for all input elements other than `checkbox` and `radio`, and textareas ([#309](https://github.com/sveltejs/svelte/pull/309))
7+
* Encapsulate keyframe declarations ([#245](https://github.com/sveltejs/svelte/issues/245))
8+
39
## 1.7.1
410

511
* Deconflict imports and shared helpers ([#222](https://github.com/sveltejs/svelte/issues/222))

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "svelte",
3-
"version": "1.7.1",
3+
"version": "1.8.0",
44
"description": "The magical disappearing UI framework",
55
"main": "compiler/svelte.js",
66
"files": [

src/generators/shared/processCss.js

+39-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,26 @@ export default function processCss ( parsed, code ) {
66

77
const attr = `[svelte-${parsed.hash}]`;
88

9+
const keyframes = new Map();
10+
11+
function walkKeyframes ( node ) {
12+
if ( node.type === 'Atrule' && node.name.toLowerCase() === 'keyframes' ) {
13+
node.expression.children.forEach( expression => {
14+
if ( expression.type === 'Identifier' ) {
15+
const newName = `svelte-${parsed.hash}-${expression.name}`;
16+
code.overwrite( expression.start, expression.end, newName );
17+
keyframes.set( expression.name, newName );
18+
}
19+
});
20+
} else if ( node.children ) {
21+
node.children.forEach( walkKeyframes );
22+
} else if ( node.block ) {
23+
walkKeyframes( node.block );
24+
}
25+
}
26+
27+
parsed.css.children.forEach( walkKeyframes );
28+
929
function transform ( rule ) {
1030
rule.selector.children.forEach( selector => {
1131
const start = selector.start - offset;
@@ -29,11 +49,29 @@ export default function processCss ( parsed, code ) {
2949

3050
code.overwrite( start + offset, end + offset, transformed );
3151
});
52+
53+
rule.block.children.forEach( block => {
54+
if ( block.type === 'Declaration' ) {
55+
const property = block.property.toLowerCase();
56+
if ( property === 'animation' || property === 'animation-name' ) {
57+
block.value.children.forEach( block => {
58+
if ( block.type === 'Identifier' ) {
59+
const name = block.name;
60+
if ( keyframes.has( name ) ) {
61+
code.overwrite( block.start, block.end, keyframes.get( name ) );
62+
}
63+
}
64+
});
65+
}
66+
}
67+
});
3268
}
3369

3470
function walk ( node ) {
3571
if ( node.type === 'Rule' ) {
3672
transform( node );
73+
} else if ( node.type === 'Atrule' && node.name.toLowerCase() === 'keyframes' ) {
74+
// these have already been processed
3775
} else if ( node.children ) {
3876
node.children.forEach( walk );
3977
} else if ( node.block ) {
@@ -53,4 +91,4 @@ export default function processCss ( parsed, code ) {
5391
}
5492

5593
return code.slice( parsed.css.content.start, parsed.css.content.end );
56-
}
94+
}

src/parse/state/tag.js

+56-18
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,46 @@ const specials = {
2121
}
2222
};
2323

24+
// based on http://developers.whatwg.org/syntax.html#syntax-tag-omission
25+
const disallowedContents = {
26+
li: [ 'li' ],
27+
dt: [ 'dt', 'dd' ],
28+
dd: [ 'dt', 'dd' ],
29+
p: 'address article aside blockquote div dl fieldset footer form h1 h2 h3 h4 h5 h6 header hgroup hr main menu nav ol p pre section table ul'.split( ' ' ),
30+
rt: [ 'rt', 'rp' ],
31+
rp: [ 'rt', 'rp' ],
32+
optgroup: [ 'optgroup' ],
33+
option: [ 'option', 'optgroup' ],
34+
thead: [ 'tbody', 'tfoot' ],
35+
tbody: [ 'tbody', 'tfoot' ],
36+
tfoot: [ 'tbody' ],
37+
tr: [ 'tr', 'tbody' ],
38+
td: [ 'td', 'th', 'tr' ],
39+
th: [ 'td', 'th', 'tr' ]
40+
};
41+
42+
function stripWhitespace ( element ) {
43+
if ( element.children.length ) {
44+
const firstChild = element.children[0];
45+
const lastChild = element.children[ element.children.length - 1 ];
46+
47+
if ( firstChild.type === 'Text' ) {
48+
firstChild.data = trimStart( firstChild.data );
49+
if ( !firstChild.data ) element.children.shift();
50+
}
51+
52+
if ( lastChild.type === 'Text' ) {
53+
lastChild.data = trimEnd( lastChild.data );
54+
if ( !lastChild.data ) element.children.pop();
55+
}
56+
}
57+
}
58+
2459
export default function tag ( parser ) {
2560
const start = parser.index++;
2661

62+
let parent = parser.current();
63+
2764
if ( parser.eat( '!--' ) ) {
2865
const data = parser.readUntil( /-->/ );
2966
parser.eat( '-->' );
@@ -40,8 +77,6 @@ export default function tag ( parser ) {
4077

4178
const isClosingTag = parser.eat( '/' );
4279

43-
// TODO handle cases like <li>one<li>two
44-
4580
const name = readTagName( parser );
4681

4782
parser.allowWhitespace();
@@ -53,28 +88,31 @@ export default function tag ( parser ) {
5388

5489
if ( !parser.eat( '>' ) ) parser.error( `Expected '>'` );
5590

56-
const element = parser.current();
57-
58-
// strip leading/trailing whitespace as necessary
59-
if ( element.children.length ) {
60-
const firstChild = element.children[0];
61-
const lastChild = element.children[ element.children.length - 1 ];
62-
63-
if ( firstChild.type === 'Text' ) {
64-
firstChild.data = trimStart( firstChild.data );
65-
if ( !firstChild.data ) element.children.shift();
66-
}
91+
// close any elements that don't have their own closing tags, e.g. <div><p></div>
92+
while ( parent.name !== name ) {
93+
parent.end = start;
94+
parser.stack.pop();
6795

68-
if ( lastChild.type === 'Text' ) {
69-
lastChild.data = trimEnd( lastChild.data );
70-
if ( !lastChild.data ) element.children.pop();
71-
}
96+
parent = parser.current();
7297
}
7398

74-
element.end = parser.index;
99+
// strip leading/trailing whitespace as necessary
100+
stripWhitespace( parent );
101+
102+
parent.end = parser.index;
75103
parser.stack.pop();
76104

77105
return null;
106+
} else if ( parent.name in disallowedContents ) {
107+
// can this be a child of the parent element, or does it implicitly
108+
// close it, like `<li>one<li>two`?
109+
const disallowed = disallowedContents[ parent.name ];
110+
if ( ~disallowed.indexOf( name ) ) {
111+
stripWhitespace( parent );
112+
113+
parent.end = start;
114+
parser.stack.pop();
115+
}
78116
}
79117

80118
const attributes = [];

test/parse.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ describe( 'parse', () => {
1616
const input = fs.readFileSync( `test/parser/${dir}/input.html`, 'utf-8' ).replace( /\s+$/, '' );
1717

1818
try {
19-
const actual = JSON.parse( JSON.stringify( svelte.parse( input ) ) );
19+
const actual = svelte.parse( input );
20+
fs.writeFileSync( `test/parser/${dir}/_actual.json`, JSON.stringify( actual, null, '\t' ) );
2021
const expected = require( `./parser/${dir}/output.json` );
2122

2223
assert.deepEqual( actual.html, expected.html );
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<ul>
2+
<li>a
3+
<li>b
4+
<li>c
5+
</ul>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
{
2+
"hash": 3806276940,
3+
"html": {
4+
"start": 0,
5+
"end": 31,
6+
"type": "Fragment",
7+
"children": [
8+
{
9+
"start": 0,
10+
"end": 31,
11+
"type": "Element",
12+
"name": "ul",
13+
"attributes": [],
14+
"children": [
15+
{
16+
"start": 6,
17+
"end": 13,
18+
"type": "Element",
19+
"name": "li",
20+
"attributes": [],
21+
"children": [
22+
{
23+
"start": 10,
24+
"end": 13,
25+
"type": "Text",
26+
"data": "a"
27+
}
28+
]
29+
},
30+
{
31+
"start": 13,
32+
"end": 20,
33+
"type": "Element",
34+
"name": "li",
35+
"attributes": [],
36+
"children": [
37+
{
38+
"start": 17,
39+
"end": 20,
40+
"type": "Text",
41+
"data": "b"
42+
}
43+
]
44+
},
45+
{
46+
"start": 20,
47+
"end": 26,
48+
"type": "Element",
49+
"name": "li",
50+
"attributes": [],
51+
"children": [
52+
{
53+
"start": 24,
54+
"end": 26,
55+
"type": "Text",
56+
"data": "c\n"
57+
}
58+
]
59+
}
60+
]
61+
}
62+
]
63+
},
64+
"css": null,
65+
"js": null
66+
}

0 commit comments

Comments
 (0)