From 9cfa1747036607debd8502018681fa5697f1d5bf Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 10 Jan 2018 21:31:03 -0500 Subject: [PATCH 01/39] -> v1.51.1 --- CHANGELOG.md | 4 ++++ package.json | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 995184c017..d7f1f2b976 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Svelte changelog +## 1.51.1 + +* Only escape <, > and & characters ([#1082](https://github.com/sveltejs/svelte/issues/1082)) + ## 1.51.0 * Lock `scroll` bindings ([#1071](https://github.com/sveltejs/svelte/issues/1071)) diff --git a/package.json b/package.json index fd97fce5b3..a2d4890cd7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "svelte", - "version": "1.51.0", + "version": "1.51.1", "description": "The magical disappearing UI framework", "main": "compiler/svelte.js", "files": [ From 728d2fa9fb870be4fa70bc5e5401e78c87ee668a Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 10 Jan 2018 21:48:03 -0500 Subject: [PATCH 02/39] deconflict referenced globals - fixes #1079 --- package.json | 3 + src/generators/Generator.ts | 9 +- src/generators/dom/index.ts | 2 +- src/utils/annotateWithScopes.ts | 10 +- .../deconflict-globals/expected-bundle.js | 221 ++++++++++++++++++ .../js/samples/deconflict-globals/expected.js | 52 +++++ test/js/samples/deconflict-globals/input.html | 11 + yarn.lock | 10 + 8 files changed, 313 insertions(+), 5 deletions(-) create mode 100644 test/js/samples/deconflict-globals/expected-bundle.js create mode 100644 test/js/samples/deconflict-globals/expected.js create mode 100644 test/js/samples/deconflict-globals/input.html diff --git a/package.json b/package.json index a2d4890cd7..07a1e9e103 100644 --- a/package.json +++ b/package.json @@ -87,5 +87,8 @@ ], "sourceMap": true, "instrument": true + }, + "dependencies": { + "is-reference": "^1.1.0" } } diff --git a/src/generators/Generator.ts b/src/generators/Generator.ts index f0c36f8062..ab74b40c0d 100644 --- a/src/generators/Generator.ts +++ b/src/generators/Generator.ts @@ -410,11 +410,16 @@ export default class Generator { const indentationLevel = getIndentationLevel(source, js.content.body[0].start); const indentExclusionRanges = getIndentExclusionRanges(js.content); - const scope = annotateWithScopes(js.content); + const { scope, globals } = annotateWithScopes(js.content); + scope.declarations.forEach(name => { this.userVars.add(name); }); + globals.forEach(name => { + this.userVars.add(name); + }); + const body = js.content.body.slice(); // slice, because we're going to be mutating the original // imports need to be hoisted out of the IIFE @@ -666,7 +671,7 @@ export default class Generator { isEventHandler: boolean ) => { this.addSourcemapLocations(node); // TODO this involves an additional walk — can we roll it in somewhere else? - let scope = annotateWithScopes(node); + let { scope } = annotateWithScopes(node); const dependencies: Set = new Set(); diff --git a/src/generators/dom/index.ts b/src/generators/dom/index.ts index 3a21e356f5..c124f05bb5 100644 --- a/src/generators/dom/index.ts +++ b/src/generators/dom/index.ts @@ -407,7 +407,7 @@ export default function dom( const code = new MagicString(str); const expression = parseExpressionAt(str, 0); - let scope = annotateWithScopes(expression); + let { scope } = annotateWithScopes(expression); walk(expression, { enter(node: Node, parent: Node) { diff --git a/src/utils/annotateWithScopes.ts b/src/utils/annotateWithScopes.ts index 9b5c9d5e88..41e734b6e9 100644 --- a/src/utils/annotateWithScopes.ts +++ b/src/utils/annotateWithScopes.ts @@ -1,11 +1,13 @@ import { walk } from 'estree-walker'; +import isReference from 'is-reference'; import { Node } from '../interfaces'; export default function annotateWithScopes(expression: Node) { + const globals = new Set(); let scope = new Scope(null, false); walk(expression, { - enter(node: Node) { + enter(node: Node, parent: Node) { if (/Function/.test(node.type)) { if (node.type === 'FunctionDeclaration') { scope.declarations.add(node.id.name); @@ -25,6 +27,10 @@ export default function annotateWithScopes(expression: Node) { node._scope = scope = new Scope(scope, true); } else if (/(Function|Class|Variable)Declaration/.test(node.type)) { scope.addDeclaration(node); + } else if (isReference(node, parent)) { + if (!scope.has(node.name)) { + globals.add(node.name); + } } }, @@ -35,7 +41,7 @@ export default function annotateWithScopes(expression: Node) { }, }); - return scope; + return { scope, globals }; } export class Scope { diff --git a/test/js/samples/deconflict-globals/expected-bundle.js b/test/js/samples/deconflict-globals/expected-bundle.js new file mode 100644 index 0000000000..ea55a11851 --- /dev/null +++ b/test/js/samples/deconflict-globals/expected-bundle.js @@ -0,0 +1,221 @@ +function noop() {} + +function assign(target) { + var k, + source, + i = 1, + len = arguments.length; + for (; i < len; i++) { + source = arguments[i]; + for (k in source) target[k] = source[k]; + } + + return target; +} + +function blankObject() { + return Object.create(null); +} + +function destroy(detach) { + this.destroy = noop; + this.fire('destroy'); + this.set = this.get = noop; + + if (detach !== false) this._fragment.u(); + this._fragment.d(); + this._fragment = this._state = null; +} + +function differs(a, b) { + return a !== b || ((a && typeof a === 'object') || typeof a === 'function'); +} + +function dispatchObservers(component, group, changed, newState, oldState) { + for (var key in group) { + if (!changed[key]) continue; + + var newValue = newState[key]; + var oldValue = oldState[key]; + + var callbacks = group[key]; + if (!callbacks) continue; + + for (var i = 0; i < callbacks.length; i += 1) { + var callback = callbacks[i]; + if (callback.__calling) continue; + + callback.__calling = true; + callback.call(component, newValue, oldValue); + callback.__calling = false; + } + } +} + +function fire(eventName, data) { + var handlers = + eventName in this._handlers && this._handlers[eventName].slice(); + if (!handlers) return; + + for (var i = 0; i < handlers.length; i += 1) { + handlers[i].call(this, data); + } +} + +function get(key) { + return key ? this._state[key] : this._state; +} + +function init(component, options) { + component._observers = { pre: blankObject(), post: blankObject() }; + component._handlers = blankObject(); + component._bind = options._bind; + + component.options = options; + component.root = options.root || component; + component.store = component.root.store || options.store; +} + +function observe(key, callback, options) { + var group = options && options.defer + ? this._observers.post + : this._observers.pre; + + (group[key] || (group[key] = [])).push(callback); + + if (!options || options.init !== false) { + callback.__calling = true; + callback.call(this, this._state[key]); + callback.__calling = false; + } + + return { + cancel: function() { + var index = group[key].indexOf(callback); + if (~index) group[key].splice(index, 1); + } + }; +} + +function on(eventName, handler) { + if (eventName === 'teardown') return this.on('destroy', handler); + + var handlers = this._handlers[eventName] || (this._handlers[eventName] = []); + handlers.push(handler); + + return { + cancel: function() { + var index = handlers.indexOf(handler); + if (~index) handlers.splice(index, 1); + } + }; +} + +function set(newState) { + this._set(assign({}, newState)); + if (this.root._lock) return; + this.root._lock = true; + callAll(this.root._beforecreate); + callAll(this.root._oncreate); + callAll(this.root._aftercreate); + this.root._lock = false; +} + +function _set(newState) { + var oldState = this._state, + changed = {}, + dirty = false; + + for (var key in newState) { + if (differs(newState[key], oldState[key])) changed[key] = dirty = true; + } + if (!dirty) return; + + this._state = assign({}, oldState, newState); + this._recompute(changed, this._state); + if (this._bind) this._bind(changed, this._state); + + if (this._fragment) { + dispatchObservers(this, this._observers.pre, changed, this._state, oldState); + this._fragment.p(changed, this._state); + dispatchObservers(this, this._observers.post, changed, this._state, oldState); + } +} + +function callAll(fns) { + while (fns && fns.length) fns.pop()(); +} + +function _mount(target, anchor) { + this._fragment.m(target, anchor); +} + +function _unmount() { + if (this._fragment) this._fragment.u(); +} + +var proto = { + destroy: destroy, + get: get, + fire: fire, + observe: observe, + on: on, + set: set, + teardown: destroy, + _recompute: noop, + _set: _set, + _mount: _mount, + _unmount: _unmount +}; + +/* generated by Svelte vX.Y.Z */ +function data_1() { + return { + foo: 'bar' +}; +} + +function oncreate() { + alert(JSON.stringify(data())); +} + +function create_main_fragment(state, component) { + + return { + c: noop, + + m: noop, + + p: noop, + + u: noop, + + d: noop + }; +} + +function SvelteComponent(options) { + init(this, options); + this._state = assign(data_1(), options.data); + + var _oncreate = oncreate.bind(this); + + if (!options.root) { + this._oncreate = [_oncreate]; + } else { + this.root._oncreate.push(_oncreate); + } + + this._fragment = create_main_fragment(this._state, this); + + if (options.target) { + this._fragment.c(); + this._fragment.m(options.target, options.anchor || null); + + callAll(this._oncreate); + } +} + +assign(SvelteComponent.prototype, proto); + +export default SvelteComponent; diff --git a/test/js/samples/deconflict-globals/expected.js b/test/js/samples/deconflict-globals/expected.js new file mode 100644 index 0000000000..d08d3dc9a1 --- /dev/null +++ b/test/js/samples/deconflict-globals/expected.js @@ -0,0 +1,52 @@ +/* generated by Svelte vX.Y.Z */ +import { assign, callAll, init, noop, proto } from "svelte/shared.js"; + +function data_1() { + return { + foo: 'bar' +}; +} + +function oncreate() { + alert(JSON.stringify(data())); +}; + +function create_main_fragment(state, component) { + + return { + c: noop, + + m: noop, + + p: noop, + + u: noop, + + d: noop + }; +} + +function SvelteComponent(options) { + init(this, options); + this._state = assign(data_1(), options.data); + + var _oncreate = oncreate.bind(this); + + if (!options.root) { + this._oncreate = [_oncreate]; + } else { + this.root._oncreate.push(_oncreate); + } + + this._fragment = create_main_fragment(this._state, this); + + if (options.target) { + this._fragment.c(); + this._fragment.m(options.target, options.anchor || null); + + callAll(this._oncreate); + } +} + +assign(SvelteComponent.prototype, proto); +export default SvelteComponent; \ No newline at end of file diff --git a/test/js/samples/deconflict-globals/input.html b/test/js/samples/deconflict-globals/input.html new file mode 100644 index 0000000000..6c3dc88e87 --- /dev/null +++ b/test/js/samples/deconflict-globals/input.html @@ -0,0 +1,11 @@ + \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index bf6229baef..1ea0b19b77 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,10 @@ # yarn lockfile v1 +"@types/estree@0.0.38": + version "0.0.38" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.38.tgz#c1be40aa933723c608820a99a373a16d215a1ca2" + "@types/mocha@^2.2.41": version "2.2.44" resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-2.2.44.tgz#1d4a798e53f35212fd5ad4d04050620171cd5b5e" @@ -1635,6 +1639,12 @@ is-property@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" +is-reference@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-1.1.0.tgz#50e6ef3f64c361e2c53c0416cdc9420037f2685b" + dependencies: + "@types/estree" "0.0.38" + is-resolvable@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62" From 5fea63a5de5cd522d45cfb0ff11f0922584ea66a Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 10 Jan 2018 22:04:49 -0500 Subject: [PATCH 03/39] validate contents of await blocks (#1061) --- src/validate/html/index.ts | 6 ++++++ .../samples/await-component-is-used/input.html | 17 +++++++++++++++++ .../await-component-is-used/warnings.json | 1 + 3 files changed, 24 insertions(+) create mode 100644 test/validator/samples/await-component-is-used/input.html create mode 100644 test/validator/samples/await-component-is-used/warnings.json diff --git a/src/validate/html/index.ts b/src/validate/html/index.ts index bf94b63c52..88609d174f 100644 --- a/src/validate/html/index.ts +++ b/src/validate/html/index.ts @@ -54,6 +54,12 @@ export default function validateHtml(validator: Validator, html: Node) { if (node.else) { visit(node.else); } + + if (node.type === 'AwaitBlock') { + visit(node.pending); + visit(node.then); + visit(node.catch); + } } html.children.forEach(visit); diff --git a/test/validator/samples/await-component-is-used/input.html b/test/validator/samples/await-component-is-used/input.html new file mode 100644 index 0000000000..f27202d6dd --- /dev/null +++ b/test/validator/samples/await-component-is-used/input.html @@ -0,0 +1,17 @@ +{{#await promise}} +

Loading

+{{then data}} + +{{catch err}} +

Error: {{err}}

+{{/await}} + + diff --git a/test/validator/samples/await-component-is-used/warnings.json b/test/validator/samples/await-component-is-used/warnings.json new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/test/validator/samples/await-component-is-used/warnings.json @@ -0,0 +1 @@ +[] \ No newline at end of file From c1b5bed6d205fb7521d0f7ec6a64efe340dd94ad Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 10 Jan 2018 22:17:01 -0500 Subject: [PATCH 04/39] fire oncreate handlers for components inside await blocks (#1061) --- src/generators/nodes/AwaitBlock.ts | 6 ++++++ .../samples/await-component-oncreate/Foo.html | 14 ++++++++++++++ .../samples/await-component-oncreate/_config.js | 16 ++++++++++++++++ .../samples/await-component-oncreate/main.html | 13 +++++++++++++ 4 files changed, 49 insertions(+) create mode 100644 test/runtime/samples/await-component-oncreate/Foo.html create mode 100644 test/runtime/samples/await-component-oncreate/_config.js create mode 100644 test/runtime/samples/await-component-oncreate/main.html diff --git a/src/generators/nodes/AwaitBlock.ts b/src/generators/nodes/AwaitBlock.ts index abc9d2c75a..3b928f7804 100644 --- a/src/generators/nodes/AwaitBlock.ts +++ b/src/generators/nodes/AwaitBlock.ts @@ -101,6 +101,10 @@ export default class AwaitBlock extends Node { block.addVariable(promise); block.addVariable(resolved); + // the `#component.root.set({})` below is just a cheap way to flush + // any oncreate handlers. We could have a dedicated `flush()` method + // but it's probably not worth it + block.builders.init.addBlock(deindent` function ${replace_await_block}(${token}, type, ${value}, ${params}) { if (${token} !== ${await_token}) return; @@ -113,6 +117,8 @@ export default class AwaitBlock extends Node { ${old_block}.d(); ${await_block}.c(); ${await_block}.m(${updateMountNode}, ${anchor}); + + #component.root.set({}); } } diff --git a/test/runtime/samples/await-component-oncreate/Foo.html b/test/runtime/samples/await-component-oncreate/Foo.html new file mode 100644 index 0000000000..61362eee09 --- /dev/null +++ b/test/runtime/samples/await-component-oncreate/Foo.html @@ -0,0 +1,14 @@ +

{{value}}

+

{{called}}

+ + \ No newline at end of file diff --git a/test/runtime/samples/await-component-oncreate/_config.js b/test/runtime/samples/await-component-oncreate/_config.js new file mode 100644 index 0000000000..417cbb8b14 --- /dev/null +++ b/test/runtime/samples/await-component-oncreate/_config.js @@ -0,0 +1,16 @@ +const promise = Promise.resolve(42); + +export default { + data: { + promise + }, + + test(assert, component, target) { + return promise.then(() => { + assert.htmlEqual(target.innerHTML, ` +

42

+

true

+ `); + }); + } +}; \ No newline at end of file diff --git a/test/runtime/samples/await-component-oncreate/main.html b/test/runtime/samples/await-component-oncreate/main.html new file mode 100644 index 0000000000..579f19f199 --- /dev/null +++ b/test/runtime/samples/await-component-oncreate/main.html @@ -0,0 +1,13 @@ +{{#await promise then value}} + +{{/await}} + + \ No newline at end of file From 2781968e43a00a89f9256308756c8ddcc686a091 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 10 Jan 2018 22:32:58 -0500 Subject: [PATCH 05/39] be more relaxed about attribute casing - fixes #1062 --- src/generators/nodes/Attribute.ts | 13 ++++++++++++- .../runtime/samples/attribute-casing/_config.js | 17 +++++++++++++++++ test/runtime/samples/attribute-casing/main.html | 5 +++++ 3 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 test/runtime/samples/attribute-casing/_config.js create mode 100644 test/runtime/samples/attribute-casing/main.html diff --git a/src/generators/nodes/Attribute.ts b/src/generators/nodes/Attribute.ts index 639870536c..fe36ac7718 100644 --- a/src/generators/nodes/Attribute.ts +++ b/src/generators/nodes/Attribute.ts @@ -43,7 +43,7 @@ export default class Attribute { render(block: Block) { const node = this.parent; - const name = this.name; + const name = fixCasing(this.name); if (name === 'style') { const styleProps = optimizeStyle(this.value); @@ -662,4 +662,15 @@ function getStyleValue(chunks: Node[]) { function isDynamic(value: Node[]) { return value.length > 1 || value[0].type !== 'Text'; +} + +const svgAttributes = 'accent-height accumulate additive alignment-baseline allowReorder alphabetic amplitude arabic-form ascent attributeName attributeType autoReverse azimuth baseFrequency baseline-shift baseProfile bbox begin bias by calcMode cap-height class clip clipPathUnits clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering contentScriptType contentStyleType cursor cx cy d decelerate descent diffuseConstant direction display divisor dominant-baseline dur dx dy edgeMode elevation enable-background end exponent externalResourcesRequired fill fill-opacity fill-rule filter filterRes filterUnits flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight format from fr fx fy g1 g2 glyph-name glyph-orientation-horizontal glyph-orientation-vertical glyphRef gradientTransform gradientUnits hanging height href horiz-adv-x horiz-origin-x id ideographic image-rendering in in2 intercept k k1 k2 k3 k4 kernelMatrix kernelUnitLength kerning keyPoints keySplines keyTimes lang lengthAdjust letter-spacing lighting-color limitingConeAngle local marker-end marker-mid marker-start markerHeight markerUnits markerWidth mask maskContentUnits maskUnits mathematical max media method min mode name numOctaves offset onabort onactivate onbegin onclick onend onerror onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup onrepeat onresize onscroll onunload opacity operator order orient orientation origin overflow overline-position overline-thickness panose-1 paint-order pathLength patternContentUnits patternTransform patternUnits pointer-events points pointsAtX pointsAtY pointsAtZ preserveAlpha preserveAspectRatio primitiveUnits r radius refX refY rendering-intent repeatCount repeatDur requiredExtensions requiredFeatures restart result rotate rx ry scale seed shape-rendering slope spacing specularConstant specularExponent speed spreadMethod startOffset stdDeviation stemh stemv stitchTiles stop-color stop-opacity strikethrough-position strikethrough-thickness string stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style surfaceScale systemLanguage tabindex tableValues target targetX targetY text-anchor text-decoration text-rendering textLength to transform type u1 u2 underline-position underline-thickness unicode unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical values version vert-adv-y vert-origin-x vert-origin-y viewBox viewTarget visibility width widths word-spacing writing-mode x x-height x1 x2 xChannelSelector xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space y y1 y2 yChannelSelector z zoomAndPan'.split(' '); +const svgAttributeLookup = new Map(); +svgAttributes.forEach(name => { + svgAttributeLookup.set(name.toLowerCase(), name); +}); + +function fixCasing(name) { + if (svgAttributeLookup.has(name)) return svgAttributeLookup.get(name); + return name.toLowerCase(); } \ No newline at end of file diff --git a/test/runtime/samples/attribute-casing/_config.js b/test/runtime/samples/attribute-casing/_config.js new file mode 100644 index 0000000000..cdab7b0a18 --- /dev/null +++ b/test/runtime/samples/attribute-casing/_config.js @@ -0,0 +1,17 @@ +export default { + html: ` +
YELL
+ + + hellooooo + + `, + + test(assert, component, target) { + const attr = sel => target.querySelector(sel).attributes[0].name; + + assert.equal(attr('div'), 'class'); + assert.equal(attr('svg'), 'viewBox'); + assert.equal(attr('text'), 'textLength'); + } +}; \ No newline at end of file diff --git a/test/runtime/samples/attribute-casing/main.html b/test/runtime/samples/attribute-casing/main.html new file mode 100644 index 0000000000..5f630c633b --- /dev/null +++ b/test/runtime/samples/attribute-casing/main.html @@ -0,0 +1,5 @@ +
YELL
+ + + hellooooo + \ No newline at end of file From 4f1bba3be13e36c897905cb5609ed7bc0970e108 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 10 Jan 2018 22:49:29 -0500 Subject: [PATCH 06/39] make is-reference a devDependency --- package.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/package.json b/package.json index 07a1e9e103..eec5d34b01 100644 --- a/package.json +++ b/package.json @@ -56,6 +56,7 @@ "eslint-plugin-import": "^2.2.0", "estree-walker": "^0.5.1", "glob": "^7.1.1", + "is-reference": "^1.1.0", "jsdom": "^11.1.0", "locate-character": "^2.0.0", "magic-string": "^0.22.3", @@ -87,8 +88,5 @@ ], "sourceMap": true, "instrument": true - }, - "dependencies": { - "is-reference": "^1.1.0" } } From 7ee44af6b573970e125314b408220cd64d45ae8c Mon Sep 17 00:00:00 2001 From: Conduitry Date: Thu, 11 Jan 2018 15:04:17 -0500 Subject: [PATCH 07/39] fix escaping of sigils in SSR non-top-level From f9fc7c9e91c273eab4becdf1d00c6479fa15ccba Mon Sep 17 00:00:00 2001 From: Emil Ajdyna Date: Sat, 13 Jan 2018 18:05:01 +0100 Subject: [PATCH 09/39] Base scoping hashes on CSS content rather than entire file --- src/parse/index.ts | 10 ++++++++-- .../collapses-text-around-comments/expected-bundle.js | 8 ++++---- .../samples/collapses-text-around-comments/expected.js | 10 +++++----- test/js/samples/css-media-query/expected-bundle.js | 8 ++++---- test/js/samples/css-media-query/expected.js | 10 +++++----- .../samples/styles-nested/_actual.css | 4 ++-- .../samples/styles-nested/_actual.html | 6 +++--- .../samples/styles-nested/_expected.css | 4 ++-- .../samples/styles-nested/_expected.html | 6 +++--- test/server-side-rendering/samples/styles/_actual.css | 2 +- test/server-side-rendering/samples/styles/_actual.html | 2 +- .../server-side-rendering/samples/styles/_expected.css | 2 +- .../samples/styles/_expected.html | 2 +- test/sourcemaps/samples/css-cascade-false/output.css | 2 +- test/sourcemaps/samples/css/output.css | 2 +- 15 files changed, 42 insertions(+), 36 deletions(-) diff --git a/src/parse/index.ts b/src/parse/index.ts index 6711e9929f..863237d174 100644 --- a/src/parse/index.ts +++ b/src/parse/index.ts @@ -185,14 +185,20 @@ export class Parser { } } +function getHashSource (parser: Parser, options: ParserOptions) { + if (options.css === false || !parser.css) { + return parser.template; + } + return parser.css.content.styles; +} + export default function parse( template: string, options: ParserOptions = {} ): Parsed { const parser = new Parser(template, options); - return { - hash: hash(parser.template), + hash: hash(getHashSource(parser, options)), html: parser.html, css: parser.css, js: parser.js, diff --git a/test/js/samples/collapses-text-around-comments/expected-bundle.js b/test/js/samples/collapses-text-around-comments/expected-bundle.js index 487665fe9d..fd2c6d9b03 100644 --- a/test/js/samples/collapses-text-around-comments/expected-bundle.js +++ b/test/js/samples/collapses-text-around-comments/expected-bundle.js @@ -198,13 +198,13 @@ function data() { } function encapsulateStyles(node) { - setAttribute(node, "svelte-3590263702", ""); + setAttribute(node, "svelte-2794052100", ""); } function add_css() { var style = createElement("style"); - style.id = 'svelte-3590263702-style'; - style.textContent = "p[svelte-3590263702],[svelte-3590263702] p{color:red}"; + style.id = 'svelte-2794052100-style'; + style.textContent = "p[svelte-2794052100],[svelte-2794052100] p{color:red}"; appendNode(style, document.head); } @@ -245,7 +245,7 @@ function SvelteComponent(options) { init(this, options); this._state = assign(data(), options.data); - if (!document.getElementById("svelte-3590263702-style")) add_css(); + if (!document.getElementById("svelte-2794052100-style")) add_css(); this._fragment = create_main_fragment(this._state, this); diff --git a/test/js/samples/collapses-text-around-comments/expected.js b/test/js/samples/collapses-text-around-comments/expected.js index 0ad2ccd29e..babc926f91 100644 --- a/test/js/samples/collapses-text-around-comments/expected.js +++ b/test/js/samples/collapses-text-around-comments/expected.js @@ -6,13 +6,13 @@ function data() { }; function encapsulateStyles(node) { - setAttribute(node, "svelte-3590263702", ""); + setAttribute(node, "svelte-2794052100", ""); } function add_css() { var style = createElement("style"); - style.id = 'svelte-3590263702-style'; - style.textContent = "p[svelte-3590263702],[svelte-3590263702] p{color:red}"; + style.id = 'svelte-2794052100-style'; + style.textContent = "p[svelte-2794052100],[svelte-2794052100] p{color:red}"; appendNode(style, document.head); } @@ -53,7 +53,7 @@ function SvelteComponent(options) { init(this, options); this._state = assign(data(), options.data); - if (!document.getElementById("svelte-3590263702-style")) add_css(); + if (!document.getElementById("svelte-2794052100-style")) add_css(); this._fragment = create_main_fragment(this._state, this); @@ -64,4 +64,4 @@ function SvelteComponent(options) { } assign(SvelteComponent.prototype, proto); -export default SvelteComponent; \ No newline at end of file +export default SvelteComponent; diff --git a/test/js/samples/css-media-query/expected-bundle.js b/test/js/samples/css-media-query/expected-bundle.js index 0d653764f2..e5502c0a31 100644 --- a/test/js/samples/css-media-query/expected-bundle.js +++ b/test/js/samples/css-media-query/expected-bundle.js @@ -190,13 +190,13 @@ var proto = { /* generated by Svelte vX.Y.Z */ function encapsulateStyles(node) { - setAttribute(node, "svelte-2363328337", ""); + setAttribute(node, "svelte-3905933315", ""); } function add_css() { var style = createElement("style"); - style.id = 'svelte-2363328337-style'; - style.textContent = "@media(min-width: 1px){div[svelte-2363328337],[svelte-2363328337] div{color:red}}"; + style.id = 'svelte-3905933315-style'; + style.textContent = "@media(min-width: 1px){div[svelte-3905933315],[svelte-3905933315] div{color:red}}"; appendNode(style, document.head); } @@ -231,7 +231,7 @@ function SvelteComponent(options) { init(this, options); this._state = assign({}, options.data); - if (!document.getElementById("svelte-2363328337-style")) add_css(); + if (!document.getElementById("svelte-3905933315-style")) add_css(); this._fragment = create_main_fragment(this._state, this); diff --git a/test/js/samples/css-media-query/expected.js b/test/js/samples/css-media-query/expected.js index 3c36f9c6ce..567ae27255 100644 --- a/test/js/samples/css-media-query/expected.js +++ b/test/js/samples/css-media-query/expected.js @@ -2,13 +2,13 @@ import { appendNode, assign, createElement, detachNode, init, insertNode, noop, proto, setAttribute } from "svelte/shared.js"; function encapsulateStyles(node) { - setAttribute(node, "svelte-2363328337", ""); + setAttribute(node, "svelte-3905933315", ""); } function add_css() { var style = createElement("style"); - style.id = 'svelte-2363328337-style'; - style.textContent = "@media(min-width: 1px){div[svelte-2363328337],[svelte-2363328337] div{color:red}}"; + style.id = 'svelte-3905933315-style'; + style.textContent = "@media(min-width: 1px){div[svelte-3905933315],[svelte-3905933315] div{color:red}}"; appendNode(style, document.head); } @@ -43,7 +43,7 @@ function SvelteComponent(options) { init(this, options); this._state = assign({}, options.data); - if (!document.getElementById("svelte-2363328337-style")) add_css(); + if (!document.getElementById("svelte-3905933315-style")) add_css(); this._fragment = create_main_fragment(this._state, this); @@ -54,4 +54,4 @@ function SvelteComponent(options) { } assign(SvelteComponent.prototype, proto); -export default SvelteComponent; \ No newline at end of file +export default SvelteComponent; diff --git a/test/server-side-rendering/samples/styles-nested/_actual.css b/test/server-side-rendering/samples/styles-nested/_actual.css index 5888415ac1..e0b5eb0a7c 100644 --- a/test/server-side-rendering/samples/styles-nested/_actual.css +++ b/test/server-side-rendering/samples/styles-nested/_actual.css @@ -1,2 +1,2 @@ -div[svelte-1408461649],[svelte-1408461649] div{color:red} -div[svelte-1580141456],[svelte-1580141456] div{color:green} \ No newline at end of file +div[svelte-724714405],[svelte-724714405] div{color:red} +div[svelte-300476157],[svelte-300476157] div{color:green} \ No newline at end of file diff --git a/test/server-side-rendering/samples/styles-nested/_actual.html b/test/server-side-rendering/samples/styles-nested/_actual.html index 25b7d5c4f3..39dc0d55a4 100644 --- a/test/server-side-rendering/samples/styles-nested/_actual.html +++ b/test/server-side-rendering/samples/styles-nested/_actual.html @@ -1,8 +1,8 @@ -
red
-
green: foo
+
red
+
green: foo
-
green: bar
+
green: bar
diff --git a/test/server-side-rendering/samples/styles-nested/_expected.css b/test/server-side-rendering/samples/styles-nested/_expected.css index 5888415ac1..e0b5eb0a7c 100644 --- a/test/server-side-rendering/samples/styles-nested/_expected.css +++ b/test/server-side-rendering/samples/styles-nested/_expected.css @@ -1,2 +1,2 @@ -div[svelte-1408461649],[svelte-1408461649] div{color:red} -div[svelte-1580141456],[svelte-1580141456] div{color:green} \ No newline at end of file +div[svelte-724714405],[svelte-724714405] div{color:red} +div[svelte-300476157],[svelte-300476157] div{color:green} \ No newline at end of file diff --git a/test/server-side-rendering/samples/styles-nested/_expected.html b/test/server-side-rendering/samples/styles-nested/_expected.html index 25b7d5c4f3..39dc0d55a4 100644 --- a/test/server-side-rendering/samples/styles-nested/_expected.html +++ b/test/server-side-rendering/samples/styles-nested/_expected.html @@ -1,8 +1,8 @@ -
red
-
green: foo
+
red
+
green: foo
-
green: bar
+
green: bar
diff --git a/test/server-side-rendering/samples/styles/_actual.css b/test/server-side-rendering/samples/styles/_actual.css index 50a7e3a77c..dec1fe76dc 100644 --- a/test/server-side-rendering/samples/styles/_actual.css +++ b/test/server-side-rendering/samples/styles/_actual.css @@ -1 +1 @@ -div[svelte-2278551596],[svelte-2278551596] div{color:red} \ No newline at end of file +div[svelte-724714405],[svelte-724714405] div{color:red} \ No newline at end of file diff --git a/test/server-side-rendering/samples/styles/_actual.html b/test/server-side-rendering/samples/styles/_actual.html index e0ab016f48..ce71341c2f 100644 --- a/test/server-side-rendering/samples/styles/_actual.html +++ b/test/server-side-rendering/samples/styles/_actual.html @@ -1 +1 @@ -
red
\ No newline at end of file +
red
\ No newline at end of file diff --git a/test/server-side-rendering/samples/styles/_expected.css b/test/server-side-rendering/samples/styles/_expected.css index 50a7e3a77c..dec1fe76dc 100644 --- a/test/server-side-rendering/samples/styles/_expected.css +++ b/test/server-side-rendering/samples/styles/_expected.css @@ -1 +1 @@ -div[svelte-2278551596],[svelte-2278551596] div{color:red} \ No newline at end of file +div[svelte-724714405],[svelte-724714405] div{color:red} \ No newline at end of file diff --git a/test/server-side-rendering/samples/styles/_expected.html b/test/server-side-rendering/samples/styles/_expected.html index e0ab016f48..ce71341c2f 100644 --- a/test/server-side-rendering/samples/styles/_expected.html +++ b/test/server-side-rendering/samples/styles/_expected.html @@ -1 +1 @@ -
red
\ No newline at end of file +
red
\ No newline at end of file diff --git a/test/sourcemaps/samples/css-cascade-false/output.css b/test/sourcemaps/samples/css-cascade-false/output.css index a153ecb86c..754b2e7aa2 100644 --- a/test/sourcemaps/samples/css-cascade-false/output.css +++ b/test/sourcemaps/samples/css-cascade-false/output.css @@ -1,2 +1,2 @@ -.foo[svelte-2772200924]{color:red} +.foo[svelte-1719932608]{color:red} /*# sourceMappingURL=output.css.map */ \ No newline at end of file diff --git a/test/sourcemaps/samples/css/output.css b/test/sourcemaps/samples/css/output.css index b49fddc28d..acc01832b4 100644 --- a/test/sourcemaps/samples/css/output.css +++ b/test/sourcemaps/samples/css/output.css @@ -1,2 +1,2 @@ -[svelte-2772200924].foo,[svelte-2772200924] .foo{color:red} +[svelte-1719932608].foo,[svelte-1719932608] .foo{color:red} /*# sourceMappingURL=output.css.map */ \ No newline at end of file From cfdc8902ab2f2f850832045a7266a48fdcbe3885 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sat, 13 Jan 2018 20:05:27 -0500 Subject: [PATCH 10/39] run prettier (spaces -> tabs) --- src/validate/js/propValidators/computed.ts | 2 +- .../js/utils/checkForValidIdentifiers.ts | 22 ++++++++++------- .../input.html | 24 +++++++++---------- 3 files changed, 26 insertions(+), 22 deletions(-) diff --git a/src/validate/js/propValidators/computed.ts b/src/validate/js/propValidators/computed.ts index 1bf3144c31..9ee4ed5ebe 100644 --- a/src/validate/js/propValidators/computed.ts +++ b/src/validate/js/propValidators/computed.ts @@ -21,7 +21,7 @@ export default function computed(validator: Validator, prop: Node) { checkForDupes(validator, prop.value.properties); checkForComputedKeys(validator, prop.value.properties); - checkForValidIdentifiers(validator, prop.value.properties); + checkForValidIdentifiers(validator, prop.value.properties); prop.value.properties.forEach((computation: Node) => { if (!isFunctionExpression.has(computation.value.type)) { diff --git a/src/validate/js/utils/checkForValidIdentifiers.ts b/src/validate/js/utils/checkForValidIdentifiers.ts index 2e5bdd08d6..3b9968f902 100644 --- a/src/validate/js/utils/checkForValidIdentifiers.ts +++ b/src/validate/js/utils/checkForValidIdentifiers.ts @@ -8,14 +8,18 @@ export default function checkForValidIdentifiers( properties: Node[] ) { properties.forEach(prop => { - const name = getName(prop.key); - const functionDefinitionString = `function ${name}() {}`; - try { - parse(functionDefinitionString); - } catch(exception) { - const invalidCharacter = functionDefinitionString[exception.pos] - validator.error(`Computed property name "${name}" is invalid. Character '${invalidCharacter}' at position ${exception.pos} is illegal in function identifiers`, prop.start); - } - + const name = getName(prop.key); + const functionDefinitionString = `function ${name}() {}`; + try { + parse(functionDefinitionString); + } catch (exception) { + const invalidCharacter = functionDefinitionString[exception.pos]; + validator.error( + `Computed property name "${name}" is invalid. Character '${ + invalidCharacter + }' at position ${exception.pos} is illegal in function identifiers`, + prop.start + ); + } }); } diff --git a/test/validator/samples/properties-computed-must-be-valid-function-names/input.html b/test/validator/samples/properties-computed-must-be-valid-function-names/input.html index 74ddb45b96..92da829133 100644 --- a/test/validator/samples/properties-computed-must-be-valid-function-names/input.html +++ b/test/validator/samples/properties-computed-must-be-valid-function-names/input.html @@ -1,17 +1,17 @@

- The hour is - {{hours}} + The hour is + {{hours}}

From 146327e87f89c49788644f4380c16c68ad4a745c Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sat, 13 Jan 2018 20:06:16 -0500 Subject: [PATCH 11/39] fix expected error position, tweak expected message to include suggested alternative --- .../errors.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/validator/samples/properties-computed-must-be-valid-function-names/errors.json b/test/validator/samples/properties-computed-must-be-valid-function-names/errors.json index c5ad38b51d..2b6a36ecd1 100644 --- a/test/validator/samples/properties-computed-must-be-valid-function-names/errors.json +++ b/test/validator/samples/properties-computed-must-be-valid-function-names/errors.json @@ -1,8 +1,8 @@ [{ - "message": "Computed property name \"hours-hyphen\" is invalid. Character '-' at position 14 is illegal in function identifiers", + "message": "Computed property name 'hours-hyphen' is invalid — must be a valid identifier such as hours_hyphen", "loc": { "line": 14, - "column": 6 + "column": 3 }, - "pos": 172 + "pos": 150 }] From b19303679d803ea4166182ba1dbfa68365c5c6e1 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sat, 13 Jan 2018 22:44:45 -0500 Subject: [PATCH 12/39] simplify test slightly, add test for reserved words --- .../errors.json | 9 +++++++++ .../input.html | 12 ++++++++++++ .../errors.json | 6 +++--- .../input.html | 9 ++------- 4 files changed, 26 insertions(+), 10 deletions(-) create mode 100644 test/validator/samples/properties-computed-cannot-be-reserved/errors.json create mode 100644 test/validator/samples/properties-computed-cannot-be-reserved/input.html diff --git a/test/validator/samples/properties-computed-cannot-be-reserved/errors.json b/test/validator/samples/properties-computed-cannot-be-reserved/errors.json new file mode 100644 index 0000000000..39c4039743 --- /dev/null +++ b/test/validator/samples/properties-computed-cannot-be-reserved/errors.json @@ -0,0 +1,9 @@ +[{ + "message": + "Computed property name 'new' is invalid — cannot be a JavaScript reserved word", + "loc": { + "line": 9, + "column": 3 + }, + "pos": 87 +}] diff --git a/test/validator/samples/properties-computed-cannot-be-reserved/input.html b/test/validator/samples/properties-computed-cannot-be-reserved/input.html new file mode 100644 index 0000000000..06bd2bf694 --- /dev/null +++ b/test/validator/samples/properties-computed-cannot-be-reserved/input.html @@ -0,0 +1,12 @@ + diff --git a/test/validator/samples/properties-computed-must-be-valid-function-names/errors.json b/test/validator/samples/properties-computed-must-be-valid-function-names/errors.json index 2b6a36ecd1..ebaac56a8f 100644 --- a/test/validator/samples/properties-computed-must-be-valid-function-names/errors.json +++ b/test/validator/samples/properties-computed-must-be-valid-function-names/errors.json @@ -1,8 +1,8 @@ [{ - "message": "Computed property name 'hours-hyphen' is invalid — must be a valid identifier such as hours_hyphen", + "message": "Computed property name 'with-hyphen' is invalid — must be a valid identifier such as with_hyphen", "loc": { - "line": 14, + "line": 9, "column": 3 }, - "pos": 150 + "pos": 87 }] diff --git a/test/validator/samples/properties-computed-must-be-valid-function-names/input.html b/test/validator/samples/properties-computed-must-be-valid-function-names/input.html index 92da829133..1c9173f523 100644 --- a/test/validator/samples/properties-computed-must-be-valid-function-names/input.html +++ b/test/validator/samples/properties-computed-must-be-valid-function-names/input.html @@ -1,17 +1,12 @@ -

- The hour is - {{hours}} -

- From 1833bc194f24b956a076ab37cd4d7d9388ec1e68 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sat, 13 Jan 2018 22:45:15 -0500 Subject: [PATCH 13/39] use acorn.isIdentifierStart and isIdentifierChar to determine validity --- src/utils/isValidIdentifier.ts | 11 ++++++++ src/validate/js/propValidators/computed.ts | 22 ++++++++++++++-- .../js/utils/checkForValidIdentifiers.ts | 25 ------------------- 3 files changed, 31 insertions(+), 27 deletions(-) create mode 100644 src/utils/isValidIdentifier.ts delete mode 100644 src/validate/js/utils/checkForValidIdentifiers.ts diff --git a/src/utils/isValidIdentifier.ts b/src/utils/isValidIdentifier.ts new file mode 100644 index 0000000000..d129e1bd9b --- /dev/null +++ b/src/utils/isValidIdentifier.ts @@ -0,0 +1,11 @@ +import { isIdentifierStart, isIdentifierChar } from 'acorn'; + +export default function isValidIdentifier(str) { + if (!isIdentifierStart(str.charCodeAt(0), true)) return false; + + for (let i = 0; i < str.length; i += 1) { + if (!isIdentifierChar(str.charCodeAt(i), true)) return false; + } + + return true; +} \ No newline at end of file diff --git a/src/validate/js/propValidators/computed.ts b/src/validate/js/propValidators/computed.ts index 9ee4ed5ebe..94a7212881 100644 --- a/src/validate/js/propValidators/computed.ts +++ b/src/validate/js/propValidators/computed.ts @@ -1,6 +1,8 @@ import checkForDupes from '../utils/checkForDupes'; import checkForComputedKeys from '../utils/checkForComputedKeys'; -import checkForValidIdentifiers from '../utils/checkForValidIdentifiers'; +import getName from '../../../utils/getName'; +import isValidIdentifier from '../../../utils/isValidIdentifier'; +import reservedNames from '../../../utils/reservedNames'; import { Validator } from '../../'; import { Node } from '../../../interfaces'; import walkThroughTopFunctionScope from '../../../utils/walkThroughTopFunctionScope'; @@ -21,9 +23,25 @@ export default function computed(validator: Validator, prop: Node) { checkForDupes(validator, prop.value.properties); checkForComputedKeys(validator, prop.value.properties); - checkForValidIdentifiers(validator, prop.value.properties); prop.value.properties.forEach((computation: Node) => { + const name = getName(computation.key); + + if (!isValidIdentifier(name)) { + const suggestion = name.replace(/[^_$a-z0-9]/ig, '_').replace(/^\d/, '_$&'); + validator.error( + `Computed property name '${name}' is invalid — must be a valid identifier such as ${suggestion}`, + computation.start + ); + } + + if (reservedNames.has(name)) { + validator.error( + `Computed property name '${name}' is invalid — cannot be a JavaScript reserved word`, + computation.start + ); + } + if (!isFunctionExpression.has(computation.value.type)) { validator.error( `Computed properties can be function expressions or arrow function expressions`, diff --git a/src/validate/js/utils/checkForValidIdentifiers.ts b/src/validate/js/utils/checkForValidIdentifiers.ts deleted file mode 100644 index 3b9968f902..0000000000 --- a/src/validate/js/utils/checkForValidIdentifiers.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { Validator } from '../../'; -import { Node } from '../../../interfaces'; -import getName from '../../../utils/getName'; -import { parse } from 'acorn'; - -export default function checkForValidIdentifiers( - validator: Validator, - properties: Node[] -) { - properties.forEach(prop => { - const name = getName(prop.key); - const functionDefinitionString = `function ${name}() {}`; - try { - parse(functionDefinitionString); - } catch (exception) { - const invalidCharacter = functionDefinitionString[exception.pos]; - validator.error( - `Computed property name "${name}" is invalid. Character '${ - invalidCharacter - }' at position ${exception.pos} is illegal in function identifiers`, - prop.start - ); - } - }); -} From 49135161bc6c57e2caabaf87a9975d2b33de92b9 Mon Sep 17 00:00:00 2001 From: Conduitry Date: Tue, 16 Jan 2018 14:39:56 -0500 Subject: [PATCH 14/39] do not run a11y validation on child component elements (#1110) --- src/validate/html/index.ts | 21 ++++++++++++++++--- src/validate/html/validateElement.ts | 6 ++---- src/validate/html/validateHead.ts | 2 +- .../samples/a11y-not-on-components/input.html | 9 ++++++++ .../a11y-not-on-components/warnings.json | 10 +++++++++ 5 files changed, 40 insertions(+), 8 deletions(-) create mode 100644 test/validator/samples/a11y-not-on-components/input.html create mode 100644 test/validator/samples/a11y-not-on-components/warnings.json diff --git a/src/validate/html/index.ts b/src/validate/html/index.ts index 88609d174f..b2a190696f 100644 --- a/src/validate/html/index.ts +++ b/src/validate/html/index.ts @@ -19,14 +19,29 @@ export default function validateHtml(validator: Validator, html: Node) { const elementStack: Node[] = []; function visit(node: Node) { - a11y(validator, node, elementStack); - if (node.type === 'Element') { if (meta.has(node.name)) { return meta.get(node.name)(validator, node, refs, refCallees); } - validateElement(validator, node, refs, refCallees, stack, elementStack); + const isComponent = + node.name === ':Self' || + node.name === ':Component' || + validator.components.has(node.name); + + validateElement( + validator, + node, + refs, + refCallees, + stack, + elementStack, + isComponent + ); + + if (!isComponent) { + a11y(validator, node, elementStack); + } } else if (node.type === 'EachBlock') { if (validator.helpers.has(node.context)) { let c = node.expression.end; diff --git a/src/validate/html/validateElement.ts b/src/validate/html/validateElement.ts index 2572fd29d4..1156ebcea7 100644 --- a/src/validate/html/validateElement.ts +++ b/src/validate/html/validateElement.ts @@ -11,11 +11,9 @@ export default function validateElement( refs: Map, refCallees: Node[], stack: Node[], - elementStack: Node[] + elementStack: Node[], + isComponent: Boolean ) { - const isComponent = - node.name === ':Self' || node.name === ':Component' || validator.components.has(node.name); - if (isComponent) { validator.used.components.add(node.name); } diff --git a/src/validate/html/validateHead.ts b/src/validate/html/validateHead.ts index 73d100a450..bac56474b2 100644 --- a/src/validate/html/validateHead.ts +++ b/src/validate/html/validateHead.ts @@ -11,6 +11,6 @@ export default function validateHead(validator: Validator, node: Node, refs: Map node.children.forEach(node => { if (node.type !== 'Element') return; // TODO handle {{#if}} and friends? - validateElement(validator, node, refs, refCallees, [], []); + validateElement(validator, node, refs, refCallees, [], [], false); }); } diff --git a/test/validator/samples/a11y-not-on-components/input.html b/test/validator/samples/a11y-not-on-components/input.html new file mode 100644 index 0000000000..e6073bb742 --- /dev/null +++ b/test/validator/samples/a11y-not-on-components/input.html @@ -0,0 +1,9 @@ + + + + + diff --git a/test/validator/samples/a11y-not-on-components/warnings.json b/test/validator/samples/a11y-not-on-components/warnings.json new file mode 100644 index 0000000000..319a2aef81 --- /dev/null +++ b/test/validator/samples/a11y-not-on-components/warnings.json @@ -0,0 +1,10 @@ +[ + { + "message": "A11y: Avoid using autofocus", + "loc": { + "column": 8, + "line": 2 + }, + "pos": 29 + } +] From 6596913da359c427133e0002c78578fee67df2e3 Mon Sep 17 00:00:00 2001 From: James Birtles Date: Wed, 17 Jan 2018 18:04:47 +0000 Subject: [PATCH 15/39] addd failing nested store test --- test/runtime/samples/store-nested/Nested.html | 13 +++++++++++++ test/runtime/samples/store-nested/_config.js | 7 +++++++ test/runtime/samples/store-nested/main.html | 11 +++++++++++ 3 files changed, 31 insertions(+) create mode 100644 test/runtime/samples/store-nested/Nested.html create mode 100644 test/runtime/samples/store-nested/_config.js create mode 100644 test/runtime/samples/store-nested/main.html diff --git a/test/runtime/samples/store-nested/Nested.html b/test/runtime/samples/store-nested/Nested.html new file mode 100644 index 0000000000..01662eceac --- /dev/null +++ b/test/runtime/samples/store-nested/Nested.html @@ -0,0 +1,13 @@ +

Hello, {{$name}}!

+ + diff --git a/test/runtime/samples/store-nested/_config.js b/test/runtime/samples/store-nested/_config.js new file mode 100644 index 0000000000..bad5ddeffb --- /dev/null +++ b/test/runtime/samples/store-nested/_config.js @@ -0,0 +1,7 @@ +export default { + store: true, // TODO remove this in v2 + + html: ` +

Hello, world!

+ `, +}; diff --git a/test/runtime/samples/store-nested/main.html b/test/runtime/samples/store-nested/main.html new file mode 100644 index 0000000000..a1e069b2a1 --- /dev/null +++ b/test/runtime/samples/store-nested/main.html @@ -0,0 +1,11 @@ + + + From b180f8a67b0bdf716dbc17f53f1b4abcefe117c9 Mon Sep 17 00:00:00 2001 From: James Birtles Date: Wed, 17 Jan 2018 18:07:08 +0000 Subject: [PATCH 16/39] create store in _render, fixes #1107 --- src/generators/server-side-rendering/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/generators/server-side-rendering/index.ts b/src/generators/server-side-rendering/index.ts index 37bf859da7..c998cb894b 100644 --- a/src/generators/server-side-rendering/index.ts +++ b/src/generators/server-side-rendering/index.ts @@ -114,7 +114,6 @@ export default function ssr( } var result = { head: '', addComponent }; - ${templateProperties.store && `options.store = %store();`} var html = ${name}._render(result, state, options); var cssCode = Array.from(components).map(c => c.css && c.css.code).filter(Boolean).join('\\n'); @@ -130,6 +129,7 @@ export default function ssr( } ${name}._render = function(__result, state, options) { + ${templateProperties.store && `options.store = %store();`} __result.addComponent(${name}); state = Object.assign(${initialState.join(', ')}); From 66b64e254d077668c095cd98a47a7b4b929b23e2 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Thu, 18 Jan 2018 08:20:14 -0500 Subject: [PATCH 17/39] types --- src/utils/isValidIdentifier.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/isValidIdentifier.ts b/src/utils/isValidIdentifier.ts index d129e1bd9b..6c86967b0a 100644 --- a/src/utils/isValidIdentifier.ts +++ b/src/utils/isValidIdentifier.ts @@ -1,6 +1,6 @@ import { isIdentifierStart, isIdentifierChar } from 'acorn'; -export default function isValidIdentifier(str) { +export default function isValidIdentifier(str: string): boolean { if (!isIdentifierStart(str.charCodeAt(0), true)) return false; for (let i = 0; i < str.length; i += 1) { From a85b09ea97cf0b250a26bba2d6d1d9f5c654a704 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Thu, 18 Jan 2018 09:25:50 -0500 Subject: [PATCH 18/39] handle wacky identifier names in templates --- src/parse/index.ts | 19 ++++++++- src/utils/fullCharCodeAt.ts | 10 +++++ src/utils/isValidIdentifier.ts | 10 +++-- .../samples/unusual-identifier/input.html | 3 ++ .../samples/unusual-identifier/output.json | 41 +++++++++++++++++++ 5 files changed, 79 insertions(+), 4 deletions(-) create mode 100644 src/utils/fullCharCodeAt.ts create mode 100644 test/parser/samples/unusual-identifier/input.html create mode 100644 test/parser/samples/unusual-identifier/output.json diff --git a/src/parse/index.ts b/src/parse/index.ts index 6711e9929f..03c7cb95e5 100644 --- a/src/parse/index.ts +++ b/src/parse/index.ts @@ -1,9 +1,11 @@ +import { isIdentifierStart, isIdentifierChar } from 'acorn'; import { locate, Location } from 'locate-character'; import fragment from './state/fragment'; import { whitespace } from '../utils/patterns'; import { trimStart, trimEnd } from '../utils/trim'; import getCodeFrame from '../utils/getCodeFrame'; import reservedNames from '../utils/reservedNames'; +import fullCharCodeAt from '../utils/fullCharCodeAt'; import hash from './utils/hash'; import { Node, Parsed } from '../interfaces'; import CompileError from '../utils/CompileError'; @@ -147,7 +149,22 @@ export class Parser { readIdentifier() { const start = this.index; - const identifier = this.read(/[a-zA-Z_$][a-zA-Z0-9_$]*/); + + let i = this.index; + + const code = fullCharCodeAt(this.template, i); + if (!isIdentifierStart(code, true)) return null; + + i += code <= 0xffff ? 1 : 2; + + while (i < this.template.length) { + const code = fullCharCodeAt(this.template, i); + + if (!isIdentifierChar(code, true)) break; + i += code <= 0xffff ? 1 : 2; + } + + const identifier = this.template.slice(this.index, this.index = i); if (reservedNames.has(identifier)) { this.error(`'${identifier}' is a reserved word in JavaScript and cannot be used here`, start); diff --git a/src/utils/fullCharCodeAt.ts b/src/utils/fullCharCodeAt.ts new file mode 100644 index 0000000000..034da9258b --- /dev/null +++ b/src/utils/fullCharCodeAt.ts @@ -0,0 +1,10 @@ +// Adapted from https://github.com/acornjs/acorn/blob/6584815dca7440e00de841d1dad152302fdd7ca5/src/tokenize.js +// Reproduced under MIT License https://github.com/acornjs/acorn/blob/master/LICENSE + +export default function fullCharCodeAt(str: string, i: number): number { + let code = str.charCodeAt(i) + if (code <= 0xd7ff || code >= 0xe000) return code; + + let next = str.charCodeAt(i + 1); + return (code << 10) + next - 0x35fdc00; +} \ No newline at end of file diff --git a/src/utils/isValidIdentifier.ts b/src/utils/isValidIdentifier.ts index 6c86967b0a..20ceeb4bbf 100644 --- a/src/utils/isValidIdentifier.ts +++ b/src/utils/isValidIdentifier.ts @@ -1,10 +1,14 @@ import { isIdentifierStart, isIdentifierChar } from 'acorn'; +import fullCharCodeAt from './fullCharCodeAt'; export default function isValidIdentifier(str: string): boolean { - if (!isIdentifierStart(str.charCodeAt(0), true)) return false; + let i = 0; - for (let i = 0; i < str.length; i += 1) { - if (!isIdentifierChar(str.charCodeAt(i), true)) return false; + while (i < str.length) { + const code = fullCharCodeAt(str, i); + if (!(i === 0 ? isIdentifierStart : isIdentifierChar)(code, true)) return false; + + i += code <= 0xffff ? 1 : 2; } return true; diff --git a/test/parser/samples/unusual-identifier/input.html b/test/parser/samples/unusual-identifier/input.html new file mode 100644 index 0000000000..b7da53a800 --- /dev/null +++ b/test/parser/samples/unusual-identifier/input.html @@ -0,0 +1,3 @@ +{{#each things as 𐊧}} +

𐊧

+{{/each}} \ No newline at end of file diff --git a/test/parser/samples/unusual-identifier/output.json b/test/parser/samples/unusual-identifier/output.json new file mode 100644 index 0000000000..72f576c84d --- /dev/null +++ b/test/parser/samples/unusual-identifier/output.json @@ -0,0 +1,41 @@ +{ + "hash": 2991613308, + "html": { + "start": 0, + "end": 43, + "type": "Fragment", + "children": [ + { + "start": 0, + "end": 43, + "type": "EachBlock", + "expression": { + "type": "Identifier", + "start": 8, + "end": 14, + "name": "things" + }, + "children": [ + { + "start": 24, + "end": 33, + "type": "Element", + "name": "p", + "attributes": [], + "children": [ + { + "start": 27, + "end": 29, + "type": "Text", + "data": "𐊧" + } + ] + } + ], + "context": "𐊧" + } + ] + }, + "css": null, + "js": null +} \ No newline at end of file From 80c55b1e51a99dd0bb3242aca8cb2e919b58692b Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Thu, 18 Jan 2018 10:35:25 -0500 Subject: [PATCH 19/39] oops --- .../samples/unusual-identifier/input.html | 2 +- .../samples/unusual-identifier/output.json | 19 ++++++++++++------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/test/parser/samples/unusual-identifier/input.html b/test/parser/samples/unusual-identifier/input.html index b7da53a800..71c3f4a12f 100644 --- a/test/parser/samples/unusual-identifier/input.html +++ b/test/parser/samples/unusual-identifier/input.html @@ -1,3 +1,3 @@ {{#each things as 𐊧}} -

𐊧

+

{{𐊧}}

{{/each}} \ No newline at end of file diff --git a/test/parser/samples/unusual-identifier/output.json b/test/parser/samples/unusual-identifier/output.json index 72f576c84d..6434526df5 100644 --- a/test/parser/samples/unusual-identifier/output.json +++ b/test/parser/samples/unusual-identifier/output.json @@ -1,13 +1,13 @@ { - "hash": 2991613308, + "hash": 795130236, "html": { "start": 0, - "end": 43, + "end": 47, "type": "Fragment", "children": [ { "start": 0, - "end": 43, + "end": 47, "type": "EachBlock", "expression": { "type": "Identifier", @@ -18,16 +18,21 @@ "children": [ { "start": 24, - "end": 33, + "end": 37, "type": "Element", "name": "p", "attributes": [], "children": [ { "start": 27, - "end": 29, - "type": "Text", - "data": "𐊧" + "end": 33, + "type": "MustacheTag", + "expression": { + "type": "Identifier", + "start": 29, + "end": 31, + "name": "𐊧" + } } ] } From 9fbcddf33873f0d0adf18744748bc39f13b9021b Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Thu, 18 Jan 2018 20:49:40 -0500 Subject: [PATCH 20/39] base stylesheet.hash on css content, and revert parsed.hash --- src/css/Stylesheet.ts | 5 +++-- src/parse/index.ts | 11 ++--------- src/{parse => }/utils/hash.ts | 0 3 files changed, 5 insertions(+), 11 deletions(-) rename src/{parse => }/utils/hash.ts (100%) diff --git a/src/css/Stylesheet.ts b/src/css/Stylesheet.ts index e94dce6a62..6254795697 100644 --- a/src/css/Stylesheet.ts +++ b/src/css/Stylesheet.ts @@ -3,6 +3,7 @@ import { walk } from 'estree-walker'; import { getLocator } from 'locate-character'; import Selector from './Selector'; import getCodeFrame from '../utils/getCodeFrame'; +import hash from '../utils/hash'; import Element from '../generators/nodes/Element'; import { Validator } from '../validate/index'; import { Node, Parsed, Warning } from '../interfaces'; @@ -269,12 +270,12 @@ export default class Stylesheet { this.cascade = cascade; this.filename = filename; - this.id = `svelte-${parsed.hash}`; - this.children = []; this.keyframes = new Map(); if (parsed.css && parsed.css.children.length) { + this.id = `svelte-${hash(parsed.css.content.styles)}`; + this.hasStyles = true; const stack: (Rule | Atrule)[] = []; diff --git a/src/parse/index.ts b/src/parse/index.ts index e9341fa720..c81d2f61b0 100644 --- a/src/parse/index.ts +++ b/src/parse/index.ts @@ -6,7 +6,7 @@ import { trimStart, trimEnd } from '../utils/trim'; import getCodeFrame from '../utils/getCodeFrame'; import reservedNames from '../utils/reservedNames'; import fullCharCodeAt from '../utils/fullCharCodeAt'; -import hash from './utils/hash'; +import hash from '../utils/hash'; import { Node, Parsed } from '../interfaces'; import CompileError from '../utils/CompileError'; @@ -202,20 +202,13 @@ export class Parser { } } -function getHashSource (parser: Parser, options: ParserOptions) { - if (options.css === false || !parser.css) { - return parser.template; - } - return parser.css.content.styles; -} - export default function parse( template: string, options: ParserOptions = {} ): Parsed { const parser = new Parser(template, options); return { - hash: hash(getHashSource(parser, options)), + hash: hash(parser.template), html: parser.html, css: parser.css, js: parser.js, diff --git a/src/parse/utils/hash.ts b/src/utils/hash.ts similarity index 100% rename from src/parse/utils/hash.ts rename to src/utils/hash.ts From f61acd06c605d8936197cc1aee78edb1201738c4 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Thu, 18 Jan 2018 21:31:38 -0500 Subject: [PATCH 21/39] fix test failure --- test/css/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/css/index.js b/test/css/index.js index 1e91e770c8..b2e989d571 100644 --- a/test/css/index.js +++ b/test/css/index.js @@ -117,6 +117,8 @@ describe('css', () => { normalizeHtml(window, html.replace(/svelte-\d+/g, 'svelte-xyz')), normalizeHtml(window, expected.html) ); + + window.document.head.innerHTML = ''; // remove added styles } catch (err) { console.log(dom.code); throw err; From 6b32e448192942fd856ebac03fd9de7ed063844f Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Thu, 18 Jan 2018 21:50:29 -0500 Subject: [PATCH 22/39] -> v1.52.0 --- CHANGELOG.md | 11 +++++++++++ package.json | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d7f1f2b976..ef608c5c5d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # Svelte changelog +## 1.52.0 + +* Deconflict referenced globals ([#1079](https://github.com/sveltejs/svelte/issues/1079)) +* Validate contents of `await` blocks ([#1061](https://github.com/sveltejs/svelte/issues/1061)) +* Fire `oncreate` for components in `await` blocks ([#1061](https://github.com/sveltejs/svelte/issues/1061)) +* Automatically fix attribute casing ([#1062](https://github.com/sveltejs/svelte/issues/1062)) +* Fix escaping in ` \ No newline at end of file diff --git a/test/runtime/samples/oncreate-sibling-order/_config.js b/test/runtime/samples/oncreate-sibling-order/_config.js new file mode 100644 index 0000000000..4e28940b74 --- /dev/null +++ b/test/runtime/samples/oncreate-sibling-order/_config.js @@ -0,0 +1,13 @@ +import result from './result.js'; + +export default { + test(assert) { + assert.deepEqual(result, [ + 'oncreate foo', + 'oncreate bar' + ]); + + result.pop(); + result.pop(); + } +}; diff --git a/test/runtime/samples/oncreate-sibling-order/main.html b/test/runtime/samples/oncreate-sibling-order/main.html new file mode 100644 index 0000000000..ba594477f0 --- /dev/null +++ b/test/runtime/samples/oncreate-sibling-order/main.html @@ -0,0 +1,12 @@ + + + + \ No newline at end of file diff --git a/test/runtime/samples/oncreate-sibling-order/result.js b/test/runtime/samples/oncreate-sibling-order/result.js new file mode 100644 index 0000000000..109fa8b38c --- /dev/null +++ b/test/runtime/samples/oncreate-sibling-order/result.js @@ -0,0 +1 @@ +export default []; \ No newline at end of file From d411a82a323d12ab12b955e988a3e9cf80967a8c Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 26 Jan 2018 13:29:21 -0500 Subject: [PATCH 30/39] update snapshot tests --- .../collapses-text-around-comments/expected-bundle.js | 2 +- .../samples/collapses-text-around-comments/expected.js | 2 +- test/js/samples/component-static/expected-bundle.js | 2 +- .../samples/computed-collapsed-if/expected-bundle.js | 2 +- test/js/samples/css-media-query/expected-bundle.js | 2 +- test/js/samples/css-media-query/expected.js | 2 +- .../css-shadow-dom-keyframes/expected-bundle.js | 2 +- test/js/samples/deconflict-globals/expected-bundle.js | 10 +++++----- test/js/samples/deconflict-globals/expected.js | 8 ++++---- test/js/samples/do-use-dataset/expected-bundle.js | 2 +- .../dont-use-dataset-in-legacy/expected-bundle.js | 2 +- .../samples/dont-use-dataset-in-svg/expected-bundle.js | 2 +- .../each-block-changed-check/expected-bundle.js | 2 +- .../samples/event-handlers-custom/expected-bundle.js | 2 +- test/js/samples/head-no-whitespace/expected-bundle.js | 2 +- test/js/samples/if-block-no-update/expected-bundle.js | 2 +- test/js/samples/if-block-simple/expected-bundle.js | 2 +- .../inline-style-optimized-multiple/expected-bundle.js | 2 +- .../inline-style-optimized-url/expected-bundle.js | 2 +- .../samples/inline-style-optimized/expected-bundle.js | 2 +- .../inline-style-unoptimized/expected-bundle.js | 2 +- .../input-without-blowback-guard/expected-bundle.js | 2 +- test/js/samples/legacy-input-type/expected-bundle.js | 2 +- test/js/samples/legacy-quote-class/expected-bundle.js | 2 +- test/js/samples/media-bindings/expected-bundle.js | 2 +- .../samples/non-imported-component/expected-bundle.js | 2 +- .../onrender-onteardown-rewritten/expected-bundle.js | 10 +++++----- .../samples/onrender-onteardown-rewritten/expected.js | 8 ++++---- test/js/samples/setup-method/expected-bundle.js | 2 +- test/js/samples/svg-title/expected-bundle.js | 2 +- test/js/samples/title/expected-bundle.js | 2 +- .../samples/use-elements-as-anchors/expected-bundle.js | 2 +- .../samples/window-binding-scroll/expected-bundle.js | 2 +- 33 files changed, 47 insertions(+), 47 deletions(-) diff --git a/test/js/samples/collapses-text-around-comments/expected-bundle.js b/test/js/samples/collapses-text-around-comments/expected-bundle.js index fd2c6d9b03..59cd2de125 100644 --- a/test/js/samples/collapses-text-around-comments/expected-bundle.js +++ b/test/js/samples/collapses-text-around-comments/expected-bundle.js @@ -167,7 +167,7 @@ function _set(newState) { } function callAll(fns) { - while (fns && fns.length) fns.pop()(); + while (fns && fns.length) fns.shift()(); } function _mount(target, anchor) { diff --git a/test/js/samples/collapses-text-around-comments/expected.js b/test/js/samples/collapses-text-around-comments/expected.js index babc926f91..aea4721e36 100644 --- a/test/js/samples/collapses-text-around-comments/expected.js +++ b/test/js/samples/collapses-text-around-comments/expected.js @@ -64,4 +64,4 @@ function SvelteComponent(options) { } assign(SvelteComponent.prototype, proto); -export default SvelteComponent; +export default SvelteComponent; \ No newline at end of file diff --git a/test/js/samples/component-static/expected-bundle.js b/test/js/samples/component-static/expected-bundle.js index d304821c98..708ef5be95 100644 --- a/test/js/samples/component-static/expected-bundle.js +++ b/test/js/samples/component-static/expected-bundle.js @@ -143,7 +143,7 @@ function _set(newState) { } function callAll(fns) { - while (fns && fns.length) fns.pop()(); + while (fns && fns.length) fns.shift()(); } function _mount(target, anchor) { diff --git a/test/js/samples/computed-collapsed-if/expected-bundle.js b/test/js/samples/computed-collapsed-if/expected-bundle.js index 1732dcf323..b39f95a77b 100644 --- a/test/js/samples/computed-collapsed-if/expected-bundle.js +++ b/test/js/samples/computed-collapsed-if/expected-bundle.js @@ -143,7 +143,7 @@ function _set(newState) { } function callAll(fns) { - while (fns && fns.length) fns.pop()(); + while (fns && fns.length) fns.shift()(); } function _mount(target, anchor) { diff --git a/test/js/samples/css-media-query/expected-bundle.js b/test/js/samples/css-media-query/expected-bundle.js index e5502c0a31..91662053a4 100644 --- a/test/js/samples/css-media-query/expected-bundle.js +++ b/test/js/samples/css-media-query/expected-bundle.js @@ -163,7 +163,7 @@ function _set(newState) { } function callAll(fns) { - while (fns && fns.length) fns.pop()(); + while (fns && fns.length) fns.shift()(); } function _mount(target, anchor) { diff --git a/test/js/samples/css-media-query/expected.js b/test/js/samples/css-media-query/expected.js index 567ae27255..37afa6b42a 100644 --- a/test/js/samples/css-media-query/expected.js +++ b/test/js/samples/css-media-query/expected.js @@ -54,4 +54,4 @@ function SvelteComponent(options) { } assign(SvelteComponent.prototype, proto); -export default SvelteComponent; +export default SvelteComponent; \ No newline at end of file diff --git a/test/js/samples/css-shadow-dom-keyframes/expected-bundle.js b/test/js/samples/css-shadow-dom-keyframes/expected-bundle.js index 3edee605c1..03e5cef1e2 100644 --- a/test/js/samples/css-shadow-dom-keyframes/expected-bundle.js +++ b/test/js/samples/css-shadow-dom-keyframes/expected-bundle.js @@ -155,7 +155,7 @@ function _set(newState) { } function callAll(fns) { - while (fns && fns.length) fns.pop()(); + while (fns && fns.length) fns.shift()(); } function _mount(target, anchor) { diff --git a/test/js/samples/deconflict-globals/expected-bundle.js b/test/js/samples/deconflict-globals/expected-bundle.js index ea55a11851..ba22542c4b 100644 --- a/test/js/samples/deconflict-globals/expected-bundle.js +++ b/test/js/samples/deconflict-globals/expected-bundle.js @@ -143,7 +143,7 @@ function _set(newState) { } function callAll(fns) { - while (fns && fns.length) fns.pop()(); + while (fns && fns.length) fns.shift()(); } function _mount(target, anchor) { @@ -201,13 +201,13 @@ function SvelteComponent(options) { var _oncreate = oncreate.bind(this); if (!options.root) { - this._oncreate = [_oncreate]; - } else { - this.root._oncreate.push(_oncreate); - } + this._oncreate = []; + } this._fragment = create_main_fragment(this._state, this); + this.root._oncreate.push(_oncreate); + if (options.target) { this._fragment.c(); this._fragment.m(options.target, options.anchor || null); diff --git a/test/js/samples/deconflict-globals/expected.js b/test/js/samples/deconflict-globals/expected.js index d08d3dc9a1..8730f4e3c3 100644 --- a/test/js/samples/deconflict-globals/expected.js +++ b/test/js/samples/deconflict-globals/expected.js @@ -33,13 +33,13 @@ function SvelteComponent(options) { var _oncreate = oncreate.bind(this); if (!options.root) { - this._oncreate = [_oncreate]; - } else { - this.root._oncreate.push(_oncreate); - } + this._oncreate = []; + } this._fragment = create_main_fragment(this._state, this); + this.root._oncreate.push(_oncreate); + if (options.target) { this._fragment.c(); this._fragment.m(options.target, options.anchor || null); diff --git a/test/js/samples/do-use-dataset/expected-bundle.js b/test/js/samples/do-use-dataset/expected-bundle.js index b768840f2e..2079e6607c 100644 --- a/test/js/samples/do-use-dataset/expected-bundle.js +++ b/test/js/samples/do-use-dataset/expected-bundle.js @@ -159,7 +159,7 @@ function _set(newState) { } function callAll(fns) { - while (fns && fns.length) fns.pop()(); + while (fns && fns.length) fns.shift()(); } function _mount(target, anchor) { diff --git a/test/js/samples/dont-use-dataset-in-legacy/expected-bundle.js b/test/js/samples/dont-use-dataset-in-legacy/expected-bundle.js index da13568e97..efcfcc8f30 100644 --- a/test/js/samples/dont-use-dataset-in-legacy/expected-bundle.js +++ b/test/js/samples/dont-use-dataset-in-legacy/expected-bundle.js @@ -163,7 +163,7 @@ function _set(newState) { } function callAll(fns) { - while (fns && fns.length) fns.pop()(); + while (fns && fns.length) fns.shift()(); } function _mount(target, anchor) { diff --git a/test/js/samples/dont-use-dataset-in-svg/expected-bundle.js b/test/js/samples/dont-use-dataset-in-svg/expected-bundle.js index ad53e6a274..cf43bbd130 100644 --- a/test/js/samples/dont-use-dataset-in-svg/expected-bundle.js +++ b/test/js/samples/dont-use-dataset-in-svg/expected-bundle.js @@ -163,7 +163,7 @@ function _set(newState) { } function callAll(fns) { - while (fns && fns.length) fns.pop()(); + while (fns && fns.length) fns.shift()(); } function _mount(target, anchor) { diff --git a/test/js/samples/each-block-changed-check/expected-bundle.js b/test/js/samples/each-block-changed-check/expected-bundle.js index 90f3eeadef..e35826e354 100644 --- a/test/js/samples/each-block-changed-check/expected-bundle.js +++ b/test/js/samples/each-block-changed-check/expected-bundle.js @@ -175,7 +175,7 @@ function _set(newState) { } function callAll(fns) { - while (fns && fns.length) fns.pop()(); + while (fns && fns.length) fns.shift()(); } function _mount(target, anchor) { diff --git a/test/js/samples/event-handlers-custom/expected-bundle.js b/test/js/samples/event-handlers-custom/expected-bundle.js index 17943516aa..43db3035a3 100644 --- a/test/js/samples/event-handlers-custom/expected-bundle.js +++ b/test/js/samples/event-handlers-custom/expected-bundle.js @@ -155,7 +155,7 @@ function _set(newState) { } function callAll(fns) { - while (fns && fns.length) fns.pop()(); + while (fns && fns.length) fns.shift()(); } function _mount(target, anchor) { diff --git a/test/js/samples/head-no-whitespace/expected-bundle.js b/test/js/samples/head-no-whitespace/expected-bundle.js index f6e4968c9e..91f894bc30 100644 --- a/test/js/samples/head-no-whitespace/expected-bundle.js +++ b/test/js/samples/head-no-whitespace/expected-bundle.js @@ -155,7 +155,7 @@ function _set(newState) { } function callAll(fns) { - while (fns && fns.length) fns.pop()(); + while (fns && fns.length) fns.shift()(); } function _mount(target, anchor) { diff --git a/test/js/samples/if-block-no-update/expected-bundle.js b/test/js/samples/if-block-no-update/expected-bundle.js index 966081e9ed..b309a25e96 100644 --- a/test/js/samples/if-block-no-update/expected-bundle.js +++ b/test/js/samples/if-block-no-update/expected-bundle.js @@ -159,7 +159,7 @@ function _set(newState) { } function callAll(fns) { - while (fns && fns.length) fns.pop()(); + while (fns && fns.length) fns.shift()(); } function _mount(target, anchor) { diff --git a/test/js/samples/if-block-simple/expected-bundle.js b/test/js/samples/if-block-simple/expected-bundle.js index 63fed6f4cf..5084639f4b 100644 --- a/test/js/samples/if-block-simple/expected-bundle.js +++ b/test/js/samples/if-block-simple/expected-bundle.js @@ -159,7 +159,7 @@ function _set(newState) { } function callAll(fns) { - while (fns && fns.length) fns.pop()(); + while (fns && fns.length) fns.shift()(); } function _mount(target, anchor) { diff --git a/test/js/samples/inline-style-optimized-multiple/expected-bundle.js b/test/js/samples/inline-style-optimized-multiple/expected-bundle.js index 53526770d7..753d61db71 100644 --- a/test/js/samples/inline-style-optimized-multiple/expected-bundle.js +++ b/test/js/samples/inline-style-optimized-multiple/expected-bundle.js @@ -159,7 +159,7 @@ function _set(newState) { } function callAll(fns) { - while (fns && fns.length) fns.pop()(); + while (fns && fns.length) fns.shift()(); } function _mount(target, anchor) { diff --git a/test/js/samples/inline-style-optimized-url/expected-bundle.js b/test/js/samples/inline-style-optimized-url/expected-bundle.js index 45848aad35..cf360881b1 100644 --- a/test/js/samples/inline-style-optimized-url/expected-bundle.js +++ b/test/js/samples/inline-style-optimized-url/expected-bundle.js @@ -159,7 +159,7 @@ function _set(newState) { } function callAll(fns) { - while (fns && fns.length) fns.pop()(); + while (fns && fns.length) fns.shift()(); } function _mount(target, anchor) { diff --git a/test/js/samples/inline-style-optimized/expected-bundle.js b/test/js/samples/inline-style-optimized/expected-bundle.js index 84e4f81567..38024df4ff 100644 --- a/test/js/samples/inline-style-optimized/expected-bundle.js +++ b/test/js/samples/inline-style-optimized/expected-bundle.js @@ -159,7 +159,7 @@ function _set(newState) { } function callAll(fns) { - while (fns && fns.length) fns.pop()(); + while (fns && fns.length) fns.shift()(); } function _mount(target, anchor) { diff --git a/test/js/samples/inline-style-unoptimized/expected-bundle.js b/test/js/samples/inline-style-unoptimized/expected-bundle.js index 5d04406716..320c733a43 100644 --- a/test/js/samples/inline-style-unoptimized/expected-bundle.js +++ b/test/js/samples/inline-style-unoptimized/expected-bundle.js @@ -159,7 +159,7 @@ function _set(newState) { } function callAll(fns) { - while (fns && fns.length) fns.pop()(); + while (fns && fns.length) fns.shift()(); } function _mount(target, anchor) { diff --git a/test/js/samples/input-without-blowback-guard/expected-bundle.js b/test/js/samples/input-without-blowback-guard/expected-bundle.js index 22778e66cf..eacaca85a6 100644 --- a/test/js/samples/input-without-blowback-guard/expected-bundle.js +++ b/test/js/samples/input-without-blowback-guard/expected-bundle.js @@ -163,7 +163,7 @@ function _set(newState) { } function callAll(fns) { - while (fns && fns.length) fns.pop()(); + while (fns && fns.length) fns.shift()(); } function _mount(target, anchor) { diff --git a/test/js/samples/legacy-input-type/expected-bundle.js b/test/js/samples/legacy-input-type/expected-bundle.js index 802dbfc100..7b730f08d9 100644 --- a/test/js/samples/legacy-input-type/expected-bundle.js +++ b/test/js/samples/legacy-input-type/expected-bundle.js @@ -161,7 +161,7 @@ function _set(newState) { } function callAll(fns) { - while (fns && fns.length) fns.pop()(); + while (fns && fns.length) fns.shift()(); } function _mount(target, anchor) { diff --git a/test/js/samples/legacy-quote-class/expected-bundle.js b/test/js/samples/legacy-quote-class/expected-bundle.js index 09b00d11ea..499a82c46e 100644 --- a/test/js/samples/legacy-quote-class/expected-bundle.js +++ b/test/js/samples/legacy-quote-class/expected-bundle.js @@ -178,7 +178,7 @@ function _set(newState) { } function callAll(fns) { - while (fns && fns.length) fns.pop()(); + while (fns && fns.length) fns.shift()(); } function _mount(target, anchor) { diff --git a/test/js/samples/media-bindings/expected-bundle.js b/test/js/samples/media-bindings/expected-bundle.js index 9394167dca..fdf8a4f755 100644 --- a/test/js/samples/media-bindings/expected-bundle.js +++ b/test/js/samples/media-bindings/expected-bundle.js @@ -171,7 +171,7 @@ function _set(newState) { } function callAll(fns) { - while (fns && fns.length) fns.pop()(); + while (fns && fns.length) fns.shift()(); } function _mount(target, anchor) { diff --git a/test/js/samples/non-imported-component/expected-bundle.js b/test/js/samples/non-imported-component/expected-bundle.js index 9c14fc4a20..f8e0722db7 100644 --- a/test/js/samples/non-imported-component/expected-bundle.js +++ b/test/js/samples/non-imported-component/expected-bundle.js @@ -157,7 +157,7 @@ function _set(newState) { } function callAll(fns) { - while (fns && fns.length) fns.pop()(); + while (fns && fns.length) fns.shift()(); } function _mount(target, anchor) { diff --git a/test/js/samples/onrender-onteardown-rewritten/expected-bundle.js b/test/js/samples/onrender-onteardown-rewritten/expected-bundle.js index c1af671858..e53dd0de5e 100644 --- a/test/js/samples/onrender-onteardown-rewritten/expected-bundle.js +++ b/test/js/samples/onrender-onteardown-rewritten/expected-bundle.js @@ -143,7 +143,7 @@ function _set(newState) { } function callAll(fns) { - while (fns && fns.length) fns.pop()(); + while (fns && fns.length) fns.shift()(); } function _mount(target, anchor) { @@ -197,13 +197,13 @@ function SvelteComponent(options) { var _oncreate = oncreate.bind(this); if (!options.root) { - this._oncreate = [_oncreate]; - } else { - this.root._oncreate.push(_oncreate); - } + this._oncreate = []; + } this._fragment = create_main_fragment(this._state, this); + this.root._oncreate.push(_oncreate); + if (options.target) { this._fragment.c(); this._fragment.m(options.target, options.anchor || null); diff --git a/test/js/samples/onrender-onteardown-rewritten/expected.js b/test/js/samples/onrender-onteardown-rewritten/expected.js index 4cb3ad1f6f..51763c0b00 100644 --- a/test/js/samples/onrender-onteardown-rewritten/expected.js +++ b/test/js/samples/onrender-onteardown-rewritten/expected.js @@ -29,13 +29,13 @@ function SvelteComponent(options) { var _oncreate = oncreate.bind(this); if (!options.root) { - this._oncreate = [_oncreate]; - } else { - this.root._oncreate.push(_oncreate); - } + this._oncreate = []; + } this._fragment = create_main_fragment(this._state, this); + this.root._oncreate.push(_oncreate); + if (options.target) { this._fragment.c(); this._fragment.m(options.target, options.anchor || null); diff --git a/test/js/samples/setup-method/expected-bundle.js b/test/js/samples/setup-method/expected-bundle.js index 5e7b3ffc8b..58ee3a67a0 100644 --- a/test/js/samples/setup-method/expected-bundle.js +++ b/test/js/samples/setup-method/expected-bundle.js @@ -143,7 +143,7 @@ function _set(newState) { } function callAll(fns) { - while (fns && fns.length) fns.pop()(); + while (fns && fns.length) fns.shift()(); } function _mount(target, anchor) { diff --git a/test/js/samples/svg-title/expected-bundle.js b/test/js/samples/svg-title/expected-bundle.js index 7a56846bc1..12f06bcf92 100644 --- a/test/js/samples/svg-title/expected-bundle.js +++ b/test/js/samples/svg-title/expected-bundle.js @@ -163,7 +163,7 @@ function _set(newState) { } function callAll(fns) { - while (fns && fns.length) fns.pop()(); + while (fns && fns.length) fns.shift()(); } function _mount(target, anchor) { diff --git a/test/js/samples/title/expected-bundle.js b/test/js/samples/title/expected-bundle.js index a243c637f1..6eb3471b5b 100644 --- a/test/js/samples/title/expected-bundle.js +++ b/test/js/samples/title/expected-bundle.js @@ -143,7 +143,7 @@ function _set(newState) { } function callAll(fns) { - while (fns && fns.length) fns.pop()(); + while (fns && fns.length) fns.shift()(); } function _mount(target, anchor) { diff --git a/test/js/samples/use-elements-as-anchors/expected-bundle.js b/test/js/samples/use-elements-as-anchors/expected-bundle.js index 837a7e4275..e2ee1e61fb 100644 --- a/test/js/samples/use-elements-as-anchors/expected-bundle.js +++ b/test/js/samples/use-elements-as-anchors/expected-bundle.js @@ -167,7 +167,7 @@ function _set(newState) { } function callAll(fns) { - while (fns && fns.length) fns.pop()(); + while (fns && fns.length) fns.shift()(); } function _mount(target, anchor) { diff --git a/test/js/samples/window-binding-scroll/expected-bundle.js b/test/js/samples/window-binding-scroll/expected-bundle.js index 43760c21f0..a8a932c8b7 100644 --- a/test/js/samples/window-binding-scroll/expected-bundle.js +++ b/test/js/samples/window-binding-scroll/expected-bundle.js @@ -163,7 +163,7 @@ function _set(newState) { } function callAll(fns) { - while (fns && fns.length) fns.pop()(); + while (fns && fns.length) fns.shift()(); } function _mount(target, anchor) { From 2d0f01e49d51ecb8ead4149fec37f64a8b05b798 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 26 Jan 2018 13:30:59 -0500 Subject: [PATCH 31/39] change test outcome for uninitialised component bindings inside conditionals --- .../samples/component-binding-conditional/_config.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/runtime/samples/component-binding-conditional/_config.js b/test/runtime/samples/component-binding-conditional/_config.js index 89512afa7a..a4295d8c16 100644 --- a/test/runtime/samples/component-binding-conditional/_config.js +++ b/test/runtime/samples/component-binding-conditional/_config.js @@ -2,16 +2,16 @@ export default { 'skip-ssr': true, // TODO delete this line, once binding works html: ` -

y: foo

-

y: foo

+

y: bar

+

y: bar

`, test ( assert, component, target ) { component.set({ x: false }); assert.htmlEqual( target.innerHTML, ` -

y: foo

-

y: foo

+

y: bar

+

y: bar

` ); } }; From 7d9b89b033f9ef99facf99c5b018b997d8fb185f Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 26 Jan 2018 14:00:38 -0500 Subject: [PATCH 32/39] -> v1.54.0 --- CHANGELOG.md | 8 ++++++++ package.json | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index db888b5c30..4994b42c93 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Svelte changelog +## 1.54.0 + +* Run `oncreate` hooks depth-first, top-to-bottom ([#1135](https://github.com/sveltejs/svelte/issues/1135)) +* Render boolean attributes correctly in SSR mode ([#1109](https://github.com/sveltejs/svelte/issues/1109)) +* Add `feed` aria role to expected roles when doing a11y checks ([#1124](https://github.com/sveltejs/svelte/pull/1124)) +* More complete fix for case sensitive attributes ([#1062](https://github.com/sveltejs/svelte/issues/1062)) +* Handle CLRF line endings in await block comments ([#1132](https://github.com/sveltejs/svelte/issues/1132)) + ## 1.53.0 * Base scoping selectors on `' + ); + parser.read(/<\/style>/); + element.end = parser.index; } else { parser.stack.push(element); } diff --git a/test/runtime/samples/non-root-style-interpolation/_config.js b/test/runtime/samples/non-root-style-interpolation/_config.js new file mode 100644 index 0000000000..326d17e3b1 --- /dev/null +++ b/test/runtime/samples/non-root-style-interpolation/_config.js @@ -0,0 +1,15 @@ +export default { + data: { + color: 'red', + }, + + html: ` +
+ + foo +
`, +}; diff --git a/test/runtime/samples/non-root-style-interpolation/main.html b/test/runtime/samples/non-root-style-interpolation/main.html new file mode 100644 index 0000000000..b49fc101a7 --- /dev/null +++ b/test/runtime/samples/non-root-style-interpolation/main.html @@ -0,0 +1,8 @@ +
+ + foo +