From 8b803b7438f15a85999e4dc0b6514aff4d149703 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sun, 9 Sep 2018 16:37:56 -0400 Subject: [PATCH] a few more --- src/compile/Component.ts | 37 +++++---- src/compile/index.ts | 42 +++++----- src/compile/nodes/Animation.ts | 18 +++-- src/compile/nodes/CatchBlock.ts | 2 + src/compile/nodes/EachBlock.ts | 2 + src/compile/nodes/Element.ts | 12 ++- src/compile/nodes/ElseBlock.ts | 2 + src/compile/nodes/IfBlock.ts | 2 + src/compile/nodes/PendingBlock.ts | 2 + src/compile/nodes/ThenBlock.ts | 2 + src/compile/nodes/shared/Node.ts | 13 +++ src/validate/html/index.ts | 29 ------- src/validate/html/validateElement.ts | 115 +-------------------------- 13 files changed, 88 insertions(+), 190 deletions(-) diff --git a/src/compile/Component.ts b/src/compile/Component.ts index 9c351c503d..ff6db38b5f 100644 --- a/src/compile/Component.ts +++ b/src/compile/Component.ts @@ -26,6 +26,7 @@ import checkForComputedKeys from '../validate/js/utils/checkForComputedKeys'; import checkForDupes from '../validate/js/utils/checkForDupes'; import propValidators from '../validate/js/propValidators'; import fuzzymatch from '../validate/utils/fuzzymatch'; +import flattenReference from '../utils/flattenReference'; interface Computation { key: string; @@ -207,6 +208,7 @@ export default class Component { // styles this.stylesheet = new Stylesheet(source, ast, this.file, options.dev); + this.stylesheet.validate(this); // allow compiler to deconflict user's `import { get } from 'whatever'` and // Svelte's builtin `import { get, ... } from 'svelte/shared.ts'`; @@ -268,6 +270,25 @@ export default class Component { } }); } + + this.refCallees.forEach(callee => { + const { parts } = flattenReference(callee); + const ref = parts[1]; + + if (this.refs.has(ref)) { + // TODO check method is valid, e.g. `audio.stop()` should be `audio.pause()` + } else { + const match = fuzzymatch(ref, Array.from(this.refs.keys())); + + let message = `'refs.${ref}' does not exist`; + if (match) message += ` (did you mean 'refs.${match}'?)`; + + this.error(callee, { + code: `missing-ref`, + message + }); + } + }); } addSourcemapLocations(node: Node) { @@ -488,22 +509,6 @@ export default class Component { }; } - validate() { - const { filename } = this.options; - - try { - if (this.stylesheet) { - this.stylesheet.validate(this); - } - } catch (err) { - if (onerror) { - onerror(err); - } else { - throw err; - } - } - } - error( pos: { start: number, diff --git a/src/compile/index.ts b/src/compile/index.ts index 686ff9c724..ccf917772b 100644 --- a/src/compile/index.ts +++ b/src/compile/index.ts @@ -67,29 +67,29 @@ export default function compile(source: string, options: CompileOptions) { stats.start('parse'); ast = parse(source, options); stats.stop('parse'); + + stats.start('create component'); + const component = new Component( + ast, + source, + options.name || 'SvelteComponent', + options, + stats, + + // TODO make component generator-agnostic, to allow e.g. WebGL generator + options.generate === 'ssr' ? new SsrTarget() : new DomTarget() + ); + stats.stop('create component'); + + if (options.generate === false) { + return { ast, stats: stats.render(null), js: null, css: null }; + } + + const compiler = options.generate === 'ssr' ? generateSSR : generate; + + return compiler(component, options); } catch (err) { options.onerror(err); return; } - - stats.start('create component'); - const component = new Component( - ast, - source, - options.name || 'SvelteComponent', - options, - stats, - - // TODO make component generator-agnostic, to allow e.g. WebGL generator - options.generate === 'ssr' ? new SsrTarget() : new DomTarget() - ); - stats.stop('create component'); - - if (options.generate === false) { - return { ast, stats: stats.render(null), js: null, css: null }; - } - - const compiler = options.generate === 'ssr' ? generateSSR : generate; - - return compiler(component, options); } \ No newline at end of file diff --git a/src/compile/nodes/Animation.ts b/src/compile/nodes/Animation.ts index 4390ee0c01..e07e64e48d 100644 --- a/src/compile/nodes/Animation.ts +++ b/src/compile/nodes/Animation.ts @@ -27,8 +27,8 @@ export default class Animation extends Node { }); } - const block = parent.block; - if (!block || block.type !== 'EachBlock' || !bloc.key) { + const block = parent.parent; + if (!block || block.type !== 'EachBlock' || !block.key) { // TODO can we relax the 'immediate child' rule? component.error(this, { code: `invalid-animation`, @@ -36,12 +36,14 @@ export default class Animation extends Node { }); } - if (block.children.length > 1) { - component.error(this, { - code: `invalid-animation`, - message: `An element that use the animate directive must be the sole child of a keyed each block` - }); - } + // TODO reinstate this... it's tricky because we're + // in the process of *creating* block.children + // if (block.children.length > 1) { + // component.error(this, { + // code: `invalid-animation`, + // message: `An element that use the animate directive must be the sole child of a keyed each block` + // }); + // } this.expression = info.expression ? new Expression(component, this, scope, info.expression) diff --git a/src/compile/nodes/CatchBlock.ts b/src/compile/nodes/CatchBlock.ts index 3a9235424f..4fb9ae43f1 100644 --- a/src/compile/nodes/CatchBlock.ts +++ b/src/compile/nodes/CatchBlock.ts @@ -9,5 +9,7 @@ export default class CatchBlock extends Node { constructor(component, parent, scope, info) { super(component, parent, scope, info); this.children = mapChildren(component, parent, scope, info.children); + + this.warnIfEmptyBlock(); } } \ No newline at end of file diff --git a/src/compile/nodes/EachBlock.ts b/src/compile/nodes/EachBlock.ts index f40627c51f..bbf2e63ec7 100644 --- a/src/compile/nodes/EachBlock.ts +++ b/src/compile/nodes/EachBlock.ts @@ -52,6 +52,8 @@ export default class EachBlock extends Node { this.children = mapChildren(component, this, this.scope, info.children); + this.warnIfEmptyBlock(); // TODO would be better if EachBlock, IfBlock etc extended an abstract Block class + this.else = info.else ? new ElseBlock(component, this, this.scope, info.else) : null; diff --git a/src/compile/nodes/Element.ts b/src/compile/nodes/Element.ts index 8ca213392f..c4949e20cc 100644 --- a/src/compile/nodes/Element.ts +++ b/src/compile/nodes/Element.ts @@ -152,9 +152,17 @@ export default class Element extends Node { this.animation = null; if (this.name === 'textarea') { - // this is an egregious hack, but it's the easiest way to get