Skip to content

Commit

Permalink
Merge branch 'master' into gh-40
Browse files Browse the repository at this point in the history
  • Loading branch information
Rich-Harris committed Mar 1, 2017
2 parents d6962b3 + c2275f3 commit 357af90
Show file tree
Hide file tree
Showing 8 changed files with 176 additions and 21 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ coverage
coverage.lcov
test/sourcemaps/*/output.js
test/sourcemaps/*/output.js.map
_actual.json
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Svelte changelog

## 1.8.0

* Prevent duplicate imports ([#308](https://github.com/sveltejs/svelte/issues/308))
* Use `input` events (not `change`) for all input elements other than `checkbox` and `radio`, and textareas ([#309](https://github.com/sveltejs/svelte/pull/309))
* Encapsulate keyframe declarations ([#245](https://github.com/sveltejs/svelte/issues/245))

## 1.7.1

* Deconflict imports and shared helpers ([#222](https://github.com/sveltejs/svelte/issues/222))
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "svelte",
"version": "1.7.1",
"version": "1.8.0",
"description": "The magical disappearing UI framework",
"main": "compiler/svelte.js",
"files": [
Expand Down
40 changes: 39 additions & 1 deletion src/generators/shared/processCss.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,26 @@ export default function processCss ( parsed, code ) {

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

const keyframes = new Map();

function walkKeyframes ( node ) {
if ( node.type === 'Atrule' && node.name.toLowerCase() === 'keyframes' ) {
node.expression.children.forEach( expression => {
if ( expression.type === 'Identifier' ) {
const newName = `svelte-${parsed.hash}-${expression.name}`;
code.overwrite( expression.start, expression.end, newName );
keyframes.set( expression.name, newName );
}
});
} else if ( node.children ) {
node.children.forEach( walkKeyframes );
} else if ( node.block ) {
walkKeyframes( node.block );
}
}

parsed.css.children.forEach( walkKeyframes );

function transform ( rule ) {
rule.selector.children.forEach( selector => {
const start = selector.start - offset;
Expand All @@ -29,11 +49,29 @@ export default function processCss ( parsed, code ) {

code.overwrite( start + offset, end + offset, transformed );
});

rule.block.children.forEach( block => {
if ( block.type === 'Declaration' ) {
const property = block.property.toLowerCase();
if ( property === 'animation' || property === 'animation-name' ) {
block.value.children.forEach( block => {
if ( block.type === 'Identifier' ) {
const name = block.name;
if ( keyframes.has( name ) ) {
code.overwrite( block.start, block.end, keyframes.get( name ) );
}
}
});
}
}
});
}

function walk ( node ) {
if ( node.type === 'Rule' ) {
transform( node );
} else if ( node.type === 'Atrule' && node.name.toLowerCase() === 'keyframes' ) {
// these have already been processed
} else if ( node.children ) {
node.children.forEach( walk );
} else if ( node.block ) {
Expand All @@ -53,4 +91,4 @@ export default function processCss ( parsed, code ) {
}

return code.slice( parsed.css.content.start, parsed.css.content.end );
}
}
74 changes: 56 additions & 18 deletions src/parse/state/tag.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,46 @@ const specials = {
}
};

// based on http://developers.whatwg.org/syntax.html#syntax-tag-omission
const disallowedContents = {
li: [ 'li' ],
dt: [ 'dt', 'dd' ],
dd: [ 'dt', 'dd' ],
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( ' ' ),
rt: [ 'rt', 'rp' ],
rp: [ 'rt', 'rp' ],
optgroup: [ 'optgroup' ],
option: [ 'option', 'optgroup' ],
thead: [ 'tbody', 'tfoot' ],
tbody: [ 'tbody', 'tfoot' ],
tfoot: [ 'tbody' ],
tr: [ 'tr', 'tbody' ],
td: [ 'td', 'th', 'tr' ],
th: [ 'td', 'th', 'tr' ]
};

function stripWhitespace ( element ) {
if ( element.children.length ) {
const firstChild = element.children[0];
const lastChild = element.children[ element.children.length - 1 ];

if ( firstChild.type === 'Text' ) {
firstChild.data = trimStart( firstChild.data );
if ( !firstChild.data ) element.children.shift();
}

if ( lastChild.type === 'Text' ) {
lastChild.data = trimEnd( lastChild.data );
if ( !lastChild.data ) element.children.pop();
}
}
}

export default function tag ( parser ) {
const start = parser.index++;

let parent = parser.current();

if ( parser.eat( '!--' ) ) {
const data = parser.readUntil( /-->/ );
parser.eat( '-->' );
Expand All @@ -40,8 +77,6 @@ export default function tag ( parser ) {

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

// TODO handle cases like <li>one<li>two

const name = readTagName( parser );

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

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

const element = parser.current();

// strip leading/trailing whitespace as necessary
if ( element.children.length ) {
const firstChild = element.children[0];
const lastChild = element.children[ element.children.length - 1 ];

if ( firstChild.type === 'Text' ) {
firstChild.data = trimStart( firstChild.data );
if ( !firstChild.data ) element.children.shift();
}
// close any elements that don't have their own closing tags, e.g. <div><p></div>
while ( parent.name !== name ) {
parent.end = start;
parser.stack.pop();

if ( lastChild.type === 'Text' ) {
lastChild.data = trimEnd( lastChild.data );
if ( !lastChild.data ) element.children.pop();
}
parent = parser.current();
}

element.end = parser.index;
// strip leading/trailing whitespace as necessary
stripWhitespace( parent );

parent.end = parser.index;
parser.stack.pop();

return null;
} else if ( parent.name in disallowedContents ) {
// can this be a child of the parent element, or does it implicitly
// close it, like `<li>one<li>two`?
const disallowed = disallowedContents[ parent.name ];
if ( ~disallowed.indexOf( name ) ) {
stripWhitespace( parent );

parent.end = start;
parser.stack.pop();
}
}

const attributes = [];
Expand Down
3 changes: 2 additions & 1 deletion test/parse.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ describe( 'parse', () => {
const input = fs.readFileSync( `test/parser/${dir}/input.html`, 'utf-8' ).replace( /\s+$/, '' );

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

assert.deepEqual( actual.html, expected.html );
Expand Down
5 changes: 5 additions & 0 deletions test/parser/implicitly-closed-li/input.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<ul>
<li>a
<li>b
<li>c
</ul>
66 changes: 66 additions & 0 deletions test/parser/implicitly-closed-li/output.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
{
"hash": 3806276940,
"html": {
"start": 0,
"end": 31,
"type": "Fragment",
"children": [
{
"start": 0,
"end": 31,
"type": "Element",
"name": "ul",
"attributes": [],
"children": [
{
"start": 6,
"end": 13,
"type": "Element",
"name": "li",
"attributes": [],
"children": [
{
"start": 10,
"end": 13,
"type": "Text",
"data": "a"
}
]
},
{
"start": 13,
"end": 20,
"type": "Element",
"name": "li",
"attributes": [],
"children": [
{
"start": 17,
"end": 20,
"type": "Text",
"data": "b"
}
]
},
{
"start": 20,
"end": 26,
"type": "Element",
"name": "li",
"attributes": [],
"children": [
{
"start": 24,
"end": 26,
"type": "Text",
"data": "c\n"
}
]
}
]
}
]
},
"css": null,
"js": null
}

0 comments on commit 357af90

Please sign in to comment.