Skip to content

Commit

Permalink
Merge branch 'master' into gh-1520
Browse files Browse the repository at this point in the history
  • Loading branch information
Rich-Harris committed Aug 25, 2018
2 parents 2c24c36 + 0f171a5 commit 33ed2f5
Show file tree
Hide file tree
Showing 41 changed files with 722 additions and 25 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ node_js:

env:
global:
- BUILD_TIMEOUT=10000
- BUILD_TIMEOUT=20000

addons:
apt:
Expand Down
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
# Svelte changelog

## 2.13.1

* Coerce second argument to `toggleClass` ([#1685](https://github.com/sveltejs/svelte/issues/1685))

## 2.13.0

* Add `class` directive ([#890](https://github.com/sveltejs/svelte/issues/890))
* Remove sourcemaps from npm package ([#1690](https://github.com/sveltejs/svelte/pull/1690))

## 2.12.1

* Allow actions to take any expression ([#1676](https://github.com/sveltejs/svelte/issues/1676))
* Run transitions in component context ([#1675](https://github.com/sveltejs/svelte/issues/1675))
* Correctly set select value on mount ([#1666](https://github.com/sveltejs/svelte/issues/1666))
* Support `{@debug}` in SSR ([#1659](https://github.com/sveltejs/svelte/issues/1659))
* Don't treat ` ` as empty whitespace ([#1658](https://github.com/sveltejs/svelte/issues/1658))
* Fix outros for if blocks with no else ([#1688](https://github.com/sveltejs/svelte/pull/1688))
* Set `style.cssText` in spread attributes ([#1684](https://github.com/sveltejs/svelte/pull/1684))


## 2.12.0

* Initialise actions on mount rather than hydrate ([#1653](https://github.com/sveltejs/svelte/pull/1653))
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
{
"name": "svelte",
"version": "2.12.0",
"version": "2.13.1",
"description": "The magical disappearing UI framework",
"main": "compiler/svelte.js",
"bin": {
"svelte": "svelte"
},
"files": [
"cli",
"compiler",
"ssr",
"compiler/*.js",
"ssr/*.js",
"shared.js",
"store.js",
"store.umd.js",
Expand Down
2 changes: 1 addition & 1 deletion src/compile/nodes/Attribute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ export default class Attribute extends Node {
}
`;

block.builders.hydrate.addBlock(deindent`
block.builders.mount.addBlock(deindent`
${last} = ${value};
${updater}
`);
Expand Down
18 changes: 18 additions & 0 deletions src/compile/nodes/Class.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import Node from './shared/Node';
import Expression from './shared/Expression';

export default class Class extends Node {
type: 'Class';
name: string;
expression: Expression;

constructor(compiler, parent, scope, info) {
super(compiler, parent, scope, info);

this.name = info.name;

this.expression = info.expression
? new Expression(compiler, this, scope, info.expression)
: null;
}
}
21 changes: 20 additions & 1 deletion src/compile/nodes/DebugTag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Block from '../dom/Block';
import Expression from './shared/Expression';
import deindent from '../../utils/deindent';
import addToSet from '../../utils/addToSet';
import { stringify } from '../../utils/stringify';

export default class DebugTag extends Node {
expressions: Expression[];
Expand All @@ -25,8 +26,8 @@ export default class DebugTag extends Node {

const { code } = this.compiler;

// Debug all
if (this.expressions.length === 0) {
// Debug all
code.overwrite(this.start + 1, this.start + 7, 'debugger', {
storeName: true
});
Expand Down Expand Up @@ -67,4 +68,22 @@ export default class DebugTag extends Node {
`);
}
}

ssr() {
if (!this.compiler.options.dev) return;

const filename = this.compiler.file || null;
const { line, column } = this.compiler.locate(this.start + 1);

const obj = this.expressions.length === 0
? `ctx`
: `{ ${this.expressions
.map(e => e.node.name)
.map(name => `${name}: ctx.${name}`)
.join(', ')} }`;

const str = '${@debug(' + `${filename && stringify(filename)}, ${line}, ${column}, ${obj})}`;

this.compiler.target.append(str);
}
}
54 changes: 54 additions & 0 deletions src/compile/nodes/Element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import EventHandler from './EventHandler';
import Transition from './Transition';
import Animation from './Animation';
import Action from './Action';
import Class from './Class';
import Text from './Text';
import * as namespaces from '../../utils/namespaces';
import mapChildren from './shared/mapChildren';
Expand Down Expand Up @@ -68,6 +69,8 @@ export default class Element extends Node {
attributes: Attribute[];
actions: Action[];
bindings: Binding[];
classes: Class[];
classDependencies: string[];
handlers: EventHandler[];
intro?: Transition;
outro?: Transition;
Expand All @@ -90,6 +93,8 @@ export default class Element extends Node {
this.attributes = [];
this.actions = [];
this.bindings = [];
this.classes = [];
this.classDependencies = [];
this.handlers = [];

this.intro = null;
Expand Down Expand Up @@ -144,6 +149,10 @@ export default class Element extends Node {
this.bindings.push(new Binding(compiler, this, scope, node));
break;

case 'Class':
this.classes.push(new Class(compiler, this, scope, node));
break;

case 'EventHandler':
this.handlers.push(new EventHandler(compiler, this, scope, node));
break;
Expand Down Expand Up @@ -228,6 +237,13 @@ export default class Element extends Node {
block.addDependencies(binding.value.dependencies);
});

this.classes.forEach(classDir => {
this.parent.cannotUseInnerHTML();
if (classDir.expression) {
block.addDependencies(classDir.expression.dependencies);
}
});

this.handlers.forEach(handler => {
this.parent.cannotUseInnerHTML();
block.addDependencies(handler.dependencies);
Expand Down Expand Up @@ -403,6 +419,7 @@ export default class Element extends Node {
this.addTransitions(block);
this.addAnimation(block);
this.addActions(block);
this.addClasses(block);

if (this.initialUpdate) {
block.builders.mount.addBlock(this.initialUpdate);
Expand Down Expand Up @@ -584,6 +601,9 @@ export default class Element extends Node {
}

this.attributes.forEach((attribute: Attribute) => {
if (attribute.name === 'class' && attribute.isDynamic) {
this.classDependencies.push(...attribute.dependencies);
}
attribute.render(block);
});
}
Expand Down Expand Up @@ -867,6 +887,26 @@ export default class Element extends Node {
});
}

addClasses(block: Block) {
this.classes.forEach(classDir => {
const { expression: { snippet, dependencies}, name } = classDir;
const updater = `@toggleClass(${this.var}, "${name}", ${snippet});`;

block.builders.hydrate.addLine(updater);

if ((dependencies && dependencies.size > 0) || this.classDependencies.length) {
const allDeps = this.classDependencies.concat(...dependencies);
const deps = allDeps.map(dependency => `changed.${dependency}`).join(' || ');
const condition = allDeps.length > 1 ? `(${deps})` : deps;

block.builders.update.addConditional(
condition,
updater
);
}
});
}

getStaticAttributeValue(name: string) {
const attribute = this.attributes.find(
(attr: Attribute) => attr.type === 'Attribute' && attr.name.toLowerCase() === name
Expand Down Expand Up @@ -937,6 +977,13 @@ export default class Element extends Node {
appendTarget.slots[slotName] = '';
}

const classExpr = this.classes.map((classDir: Class) => {
const { expression: { snippet }, name } = classDir;
return `${snippet} ? "${name}" : ""`;
}).join(', ');

let addClassAttribute = classExpr ? true : false;

if (this.attributes.find(attr => attr.isSpread)) {
// TODO dry this out
const args = [];
Expand Down Expand Up @@ -977,12 +1024,19 @@ export default class Element extends Node {
) {
// a boolean attribute with one non-Text chunk
openingTag += '${' + attribute.chunks[0].snippet + ' ? " ' + attribute.name + '" : "" }';
} else if (attribute.name === 'class' && classExpr) {
addClassAttribute = false;
openingTag += ` class="\${ [\`${attribute.stringifyForSsr()}\`, ${classExpr} ].join(' ') }"`;
} else {
openingTag += ` ${attribute.name}="${attribute.stringifyForSsr()}"`;
}
});
}

if (addClassAttribute) {
openingTag += ` class="\${ [${classExpr}].join(' ') }"`;
}

openingTag += '>';

compiler.target.append(openingTag);
Expand Down
7 changes: 4 additions & 3 deletions src/compile/nodes/IfBlock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,10 @@ export default class IfBlock extends Node {
this.buildCompoundWithOutros(block, parentNode, parentNodes, branches, dynamic, vars);

if (this.compiler.options.nestedTransitions) {
block.builders.outro.addLine(
`${name}.o(#outrocallback);`
);
block.builders.outro.addBlock(deindent`
if (${name}) ${name}.o(#outrocallback);
else #outrocallback();
`);
}
} else {
this.buildCompound(block, parentNode, parentNodes, branches, dynamic, vars);
Expand Down
14 changes: 12 additions & 2 deletions src/parse/read/directives.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,19 @@ const DIRECTIVES: Record<string, {
attribute(start, end, type, name, expression) {
return { start, end, type, name, expression };
},
allowedExpressionTypes: ['Identifier', 'MemberExpression', 'ObjectExpression', 'Literal', 'CallExpression'],
allowedExpressionTypes: ['*'],
error: 'Data passed to actions must be an identifier (e.g. `foo`), a member expression ' +
'(e.g. `foo.bar` or `foo[baz]`), a method call (e.g. `foo()`), or a literal (e.g. `true` or `\'a string\'`'
},

Class: {
names: ['class'],
attribute(start, end, type, name, expression) {
return { start, end, type, name, expression };
},
allowedExpressionTypes: ['*'],
error: 'Data passed to class directives must be an expression'
},
};


Expand Down Expand Up @@ -163,7 +172,8 @@ export function readDirective(

try {
expression = readExpression(parser, expressionStart, quoteMark);
if (directive.allowedExpressionTypes.indexOf(expression.type) === -1) {
const allowed = directive.allowedExpressionTypes;
if (allowed[0] !== '*' && allowed.indexOf(expression.type) === -1) {
parser.error({
code: `invalid-directive-value`,
message: directive.error
Expand Down
10 changes: 8 additions & 2 deletions src/shared/dom.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,9 @@ export function setAttribute(node, attribute, value) {

export function setAttributes(node, attributes) {
for (var key in attributes) {
if (key in node) {
if (key === 'style') {
node.style.cssText = attributes[key];
} else if (key in node) {
node[key] = attributes[key];
} else {
if (attributes[key] === undefined) removeAttribute(node, key);
Expand Down Expand Up @@ -238,4 +240,8 @@ export function addResizeListener(element, fn) {
element.removeChild(object);
}
};
}
}

export function toggleClass(element, name, toggle) {
element.classList.toggle(name, !!toggle);
}
4 changes: 0 additions & 4 deletions src/shared/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,6 @@ export function on(eventName, handler) {
};
}

export function run(fn) {
fn();
}

export function set(newState) {
this._set(assign({}, newState));
if (this.root._lock) return;
Expand Down
6 changes: 6 additions & 0 deletions src/shared/ssr.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,10 @@ export function validateSsrComponent(component, name) {
}

return component;
}

export function debug(file, line, column, values) {
console.log(`{@debug} ${file ? file + ' ' : ''}(${line}:${column})`);
console.log(values);
return '';
}
8 changes: 3 additions & 5 deletions src/shared/transitions.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createElement } from './dom.js';
import { noop } from './utils.js';
import { noop, run } from './utils.js';

export function linear(t) {
return t;
Expand Down Expand Up @@ -27,7 +27,7 @@ export function hash(str) {
}

export function wrapTransition(component, node, fn, params, intro) {
let obj = fn(node, params);
let obj = fn.call(component, node, params);
let duration;
let ease;
let cssText;
Expand Down Expand Up @@ -137,9 +137,7 @@ export function wrapTransition(component, node, fn, params, intro) {
});

if (--program.group.remaining === 0) {
program.group.callbacks.forEach(fn => {
fn();
});
program.group.callbacks.forEach(run);
}
} else {
if (obj.css) transitionManager.deleteRule(node, program.name);
Expand Down
4 changes: 4 additions & 0 deletions src/shared/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,8 @@ export function exclude(src, prop) {
const tar = {};
for (const k in src) k === prop || (tar[k] = src[k]);
return tar;
}

export function run(fn) {
fn();
}
2 changes: 1 addition & 1 deletion src/validate/html/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ function isEmptyBlock(node: Node) {
if (!/Block$/.test(node.type) || !node.children) return false;
if (node.children.length > 1) return false;
const child = node.children[0];
return !child || (child.type === 'Text' && !/\S/.test(child.data));
return !child || (child.type === 'Text' && !/[^ \r\n\f\v\t]/.test(child.data));
}

export default function validateHtml(validator: Validator, html: Node) {
Expand Down
Loading

0 comments on commit 33ed2f5

Please sign in to comment.