diff --git a/.gitignore b/.gitignore index 329472f106..d134f6249c 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ coverage coverage.lcov test/sourcemaps/*/output.js test/sourcemaps/*/output.js.map +_actual.json \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e3c588804..2afff4d708 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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)) diff --git a/package.json b/package.json index fd06f7cd40..f9b53c0f27 100644 --- a/package.json +++ b/package.json @@ -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": [ diff --git a/src/generators/shared/processCss.js b/src/generators/shared/processCss.js index bb0012e990..91ca055d31 100644 --- a/src/generators/shared/processCss.js +++ b/src/generators/shared/processCss.js @@ -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; @@ -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 ) { @@ -53,4 +91,4 @@ export default function processCss ( parsed, code ) { } return code.slice( parsed.css.content.start, parsed.css.content.end ); -} \ No newline at end of file +} diff --git a/src/parse/state/tag.js b/src/parse/state/tag.js index 72f73f0651..3b79ad8406 100644 --- a/src/parse/state/tag.js +++ b/src/parse/state/tag.js @@ -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( '-->' ); @@ -40,8 +77,6 @@ export default function tag ( parser ) { const isClosingTag = parser.eat( '/' ); - // TODO handle cases like