Merge branch 'master' into gh-654

pull/952/head
Rich Harris 7 years ago committed by GitHub
commit 82fc0f2713
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,5 +1,6 @@
src/shared
shared.js
store.js
test/test.js
test/setup.js
**/_actual.js

@ -1,5 +1,19 @@
# Svelte changelog
## 1.43.1
* Fix parameterised transitions ([#962](https://github.com/sveltejs/svelte/issues/962))
* Prevent boolean attributes breaking estree-walker expectations ([#961](https://github.com/sveltejs/svelte/issues/961))
* Throw error on cyclical store computations ([#964](https://github.com/sveltejs/svelte/pull/964))
## 1.43.0
* Export `Store` class to manage global state ([#930](https://github.com/sveltejs/svelte/issues/930))
* Recognise `aria-current` ([#953](https://github.com/sveltejs/svelte/pull/953))
* Support SSR register options including `extensions` ([#939](https://github.com/sveltejs/svelte/issues/939))
* Friendlier error for illegal contexts ([#934](https://github.com/sveltejs/svelte/issues/934))
* Remove whitespace around `<:Window>` components ([#943](https://github.com/sveltejs/svelte/issues/943))
## 1.42.1
* Correctly append items inside a slotted `each` block ([#932](https://github.com/sveltejs/svelte/pull/932))

@ -1,12 +1,13 @@
{
"name": "svelte",
"version": "1.42.1",
"version": "1.43.1",
"description": "The magical disappearing UI framework",
"main": "compiler/svelte.js",
"files": [
"compiler",
"ssr",
"shared.js",
"store.js",
"README.md"
],
"scripts": {

@ -72,15 +72,8 @@ function removeIndentation(
// We need to tell estree-walker that it should always
// look for an `else` block, otherwise it might get
// the wrong idea about the shape of each/if blocks
childKeys.EachBlock = [
'children',
'else'
];
childKeys.IfBlock = [
'children',
'else'
];
childKeys.EachBlock = childKeys.IfBlock = ['children', 'else'];
childKeys.Attribute = ['value'];
export default class Generator {
ast: Parsed;
@ -536,6 +529,9 @@ export default class Generator {
(param: Node) =>
param.type === 'AssignmentPattern' ? param.left.name : param.name
);
deps.forEach(dep => {
this.expectedProperties.add(dep);
});
dependencies.set(key, deps);
});
@ -762,6 +758,11 @@ export default class Generator {
});
this.skip();
}
if (node.type === 'Transition' && node.expression) {
node.metadata = contextualise(node.expression, contextDependencies, indexes);
this.skip();
}
},
leave(node: Node, parent: Node) {

@ -184,15 +184,23 @@ export default function dom(
const debugName = `<${generator.customElement ? generator.tag : name}>`;
// generate initial state object
const globals = Array.from(generator.expectedProperties).filter(prop => globalWhitelist.has(prop));
const expectedProperties = Array.from(generator.expectedProperties);
const globals = expectedProperties.filter(prop => globalWhitelist.has(prop));
const storeProps = options.store ? expectedProperties.filter(prop => prop[0] === '$') : [];
const initialState = [];
if (globals.length > 0) {
initialState.push(`{ ${globals.map(prop => `${prop} : ${prop}`).join(', ')} }`);
}
if (storeProps.length > 0) {
initialState.push(`this.store._init([${storeProps.map(prop => `"${prop.slice(1)}"`)}])`);
}
if (templateProperties.data) {
initialState.push(`%data()`);
} else if (globals.length === 0) {
} else if (globals.length === 0 && storeProps.length === 0) {
initialState.push('{}');
}
@ -205,6 +213,7 @@ export default function dom(
@init(this, options);
${generator.usesRefs && `this.refs = {};`}
this._state = @assign(${initialState.join(', ')});
${storeProps.length > 0 && `this.store._add(this, [${storeProps.map(prop => `"${prop.slice(1)}"`)}]);`}
${generator.metaBindings}
${computations.length && `this._recompute({ ${Array.from(computationDeps).map(dep => `${dep}: 1`).join(', ')} }, this._state);`}
${options.dev &&
@ -215,7 +224,11 @@ export default function dom(
${generator.bindingGroups.length &&
`this._bindingGroups = [${Array(generator.bindingGroups.length).fill('[]').join(', ')}];`}
${templateProperties.ondestroy && `this._handlers.destroy = [%ondestroy]`}
${(templateProperties.ondestroy || storeProps.length) && (
`this._handlers.destroy = [${
[templateProperties.ondestroy && `%ondestroy`, storeProps.length && `@removeFromStore`].filter(Boolean).join(', ')
}];`
)}
${generator.slots.size && `this._slotted = options.slots || {};`}

@ -195,13 +195,19 @@ export default function addBindings(
const usesContext = group.bindings.some(binding => binding.handler.usesContext);
const usesState = group.bindings.some(binding => binding.handler.usesState);
const usesStore = group.bindings.some(binding => binding.handler.usesStore);
const mutations = group.bindings.map(binding => binding.handler.mutation).filter(Boolean).join('\n');
const props = new Set();
const storeProps = new Set();
group.bindings.forEach(binding => {
binding.handler.props.forEach(prop => {
props.add(prop);
});
binding.handler.storeProps.forEach(prop => {
storeProps.add(prop);
});
}); // TODO use stringifyProps here, once indenting is fixed
// media bindings — awkward special case. The native timeupdate events
@ -222,9 +228,11 @@ export default function addBindings(
}
${usesContext && `var context = ${node.var}._svelte;`}
${usesState && `var state = #component.get();`}
${usesStore && `var $ = #component.store.get();`}
${needsLock && `${lock} = true;`}
${mutations.length > 0 && mutations}
#component.set({ ${Array.from(props).join(', ')} });
${props.size > 0 && `#component.set({ ${Array.from(props).join(', ')} });`}
${storeProps.size > 0 && `#component.store.set({ ${Array.from(storeProps).join(', ')} });`}
${needsLock && `${lock} = false;`}
}
`);
@ -307,6 +315,13 @@ function getEventHandler(
dependencies: string[],
value: string,
) {
let storeDependencies = [];
if (generator.options.store) {
storeDependencies = dependencies.filter(prop => prop[0] === '$').map(prop => prop.slice(1));
dependencies = dependencies.filter(prop => prop[0] !== '$');
}
if (block.contexts.has(name)) {
const tail = attribute.value.type === 'MemberExpression'
? getTailSnippet(attribute.value)
@ -318,8 +333,10 @@ function getEventHandler(
return {
usesContext: true,
usesState: true,
usesStore: storeDependencies.length > 0,
mutation: `${list}[${index}]${tail} = ${value};`,
props: dependencies.map(prop => `${prop}: state.${prop}`)
props: dependencies.map(prop => `${prop}: state.${prop}`),
storeProps: storeDependencies.map(prop => `${prop}: $.${prop}`)
};
}
@ -336,16 +353,31 @@ function getEventHandler(
return {
usesContext: false,
usesState: true,
usesStore: storeDependencies.length > 0,
mutation: `${snippet} = ${value}`,
props: dependencies.map((prop: string) => `${prop}: state.${prop}`)
props: dependencies.map((prop: string) => `${prop}: state.${prop}`),
storeProps: storeDependencies.map(prop => `${prop}: $.${prop}`)
};
}
let props;
let storeProps;
if (generator.options.store && name[0] === '$') {
props = [];
storeProps = [`${name.slice(1)}: ${value}`];
} else {
props = [`${name}: ${value}`];
storeProps = [];
}
return {
usesContext: false,
usesState: false,
usesStore: false,
mutation: null,
props: [`${name}: ${value}`]
props,
storeProps
};
}
@ -393,4 +425,4 @@ function isComputed(node: Node) {
}
return false;
}
}

@ -21,7 +21,7 @@ export default function addTransitions(
if (intro === outro) {
const name = block.getUniqueName(`${node.var}_transition`);
const snippet = intro.expression
? intro.expression.metadata.snippet
? intro.metadata.snippet
: '{}';
block.addVariable(name);
@ -51,7 +51,7 @@ export default function addTransitions(
if (intro) {
block.addVariable(introName);
const snippet = intro.expression
? intro.expression.metadata.snippet
? intro.metadata.snippet
: '{}';
const fn = `%transitions-${intro.name}`; // TODO add built-in transitions?
@ -76,7 +76,7 @@ export default function addTransitions(
if (outro) {
block.addVariable(outroName);
const snippet = outro.expression
? intro.expression.metadata.snippet
? outro.metadata.snippet
: '{}';
const fn = `%transitions-${outro.name}`;

@ -73,16 +73,22 @@ export default function ssr(
generator.stylesheet.render(options.filename, true);
// generate initial state object
// TODO this doesn't work, because expectedProperties isn't populated
const globals = Array.from(generator.expectedProperties).filter(prop => globalWhitelist.has(prop));
const expectedProperties = Array.from(generator.expectedProperties);
const globals = expectedProperties.filter(prop => globalWhitelist.has(prop));
const storeProps = options.store ? expectedProperties.filter(prop => prop[0] === '$') : [];
const initialState = [];
if (globals.length > 0) {
initialState.push(`{ ${globals.map(prop => `${prop} : ${prop}`).join(', ')} }`);
}
if (storeProps.length > 0) {
initialState.push(`options.store._init([${storeProps.map(prop => `"${prop.slice(1)}"`)}])`);
}
if (templateProperties.data) {
initialState.push(`%data()`);
} else if (globals.length === 0) {
} else if (globals.length === 0 && storeProps.length === 0) {
initialState.push('{}');
}
@ -99,7 +105,7 @@ export default function ssr(
return ${templateProperties.data ? `%data()` : `{}`};
};
${name}.render = function(state, options) {
${name}.render = function(state, options = {}) {
state = Object.assign(${initialState.join(', ')});
${computations.map(

@ -79,6 +79,11 @@ export default function visitComponent(
let open = `\${${expression}.render({${props}}`;
const options = [];
if (generator.options.store) {
options.push(`store: options.store`);
}
if (node.children.length) {
const appendTarget: AppendTarget = {
slots: { default: '' },
@ -95,11 +100,15 @@ export default function visitComponent(
.map(name => `${name}: () => \`${appendTarget.slots[name]}\``)
.join(', ');
open += `, { slotted: { ${slotted} } }`;
options.push(`slotted: { ${slotted} }`);
generator.appendTargets.pop();
}
if (options.length) {
open += `, { ${options.join(', ')} }`;
}
generator.append(open);
generator.append(')}');
}

@ -4,7 +4,8 @@ import generate from './generators/dom/index';
import generateSSR from './generators/server-side-rendering/index';
import { assign } from './shared/index.js';
import Stylesheet from './css/Stylesheet';
import { Parsed, CompileOptions, Warning } from './interfaces';
import { Parsed, CompileOptions, Warning, PreprocessOptions, Preprocessor } from './interfaces';
import { SourceMap } from 'magic-string';
const version = '__VERSION__';
@ -34,9 +35,74 @@ function defaultOnerror(error: Error) {
throw error;
}
function parseAttributeValue(value: string) {
return /^['"]/.test(value) ?
value.slice(1, -1) :
value;
}
function parseAttributes(str: string) {
const attrs = {};
str.split(/\s+/).filter(Boolean).forEach(attr => {
const [name, value] = attr.split('=');
attrs[name] = value ? parseAttributeValue(value) : true;
});
return attrs;
}
async function replaceTagContents(source, type: 'script' | 'style', preprocessor: Preprocessor) {
const exp = new RegExp(`<${type}([\\S\\s]*?)>([\\S\\s]*?)<\\/${type}>`, 'ig');
const match = exp.exec(source);
if (match) {
const attributes: Record<string, string | boolean> = parseAttributes(match[1]);
const content: string = match[2];
const processed: { code: string, map?: SourceMap | string } = await preprocessor({
content,
attributes
});
if (processed && processed.code) {
return (
source.slice(0, match.index) +
`<${type}>${processed.code}</${type}>` +
source.slice(match.index + match[0].length)
);
}
}
return source;
}
export async function preprocess(source: string, options: PreprocessOptions) {
const { markup, style, script } = options;
if (!!markup) {
const processed: { code: string, map?: SourceMap | string } = await markup({ content: source });
source = processed.code;
}
if (!!style) {
source = await replaceTagContents(source, 'style', style);
}
if (!!script) {
source = await replaceTagContents(source, 'script', script);
}
return {
// TODO return separated output, in future version where svelte.compile supports it:
// style: { code: styleCode, map: styleMap },
// script { code: scriptCode, map: scriptMap },
// markup { code: markupCode, map: markupMap },
toString() {
return source;
}
};
}
export function compile(source: string, _options: CompileOptions) {
const options = normalizeOptions(_options);
let parsed: Parsed;
try {
@ -53,7 +119,7 @@ export function compile(source: string, _options: CompileOptions) {
const compiler = options.generate === 'ssr' ? generateSSR : generate;
return compiler(parsed, source, stylesheet, options);
}
};
export function create(source: string, _options: CompileOptions = {}) {
_options.format = 'eval';
@ -65,7 +131,7 @@ export function create(source: string, _options: CompileOptions = {}) {
}
try {
return (0,eval)(compiled.code);
return (0, eval)(compiled.code);
} catch (err) {
if (_options.onerror) {
_options.onerror(err);

@ -1,3 +1,5 @@
import {SourceMap} from 'magic-string';
export interface Node {
start: number;
end: number;
@ -56,6 +58,7 @@ export interface CompileOptions {
legacy?: boolean;
customElement?: CustomElementOptions | true;
css?: boolean;
store?: boolean;
onerror?: (error: Error) => void;
onwarn?: (warning: Warning) => void;
@ -77,4 +80,12 @@ export interface Visitor {
export interface CustomElementOptions {
tag?: string;
props?: string[];
}
}
export interface PreprocessOptions {
markup?: (options: {content: string}) => { code: string, map?: SourceMap | string };
style?: Preprocessor;
script?: Preprocessor;
}
export type Preprocessor = (options: {content: string, attributes: Record<string, string | boolean>}) => { code: string, map?: SourceMap | string };

@ -2,16 +2,22 @@ import * as fs from 'fs';
import * as path from 'path';
import { compile } from '../index.ts';
const compileOptions = {};
function capitalise(name) {
return name[0].toUpperCase() + name.slice(1);
}
export default function register(options) {
const { extensions } = options;
if (extensions) {
_deregister('.html');
extensions.forEach(_register);
}
// TODO make this the default and remove in v2
if ('store' in options) compileOptions.store = options.store;
}
function _deregister(extension) {
@ -20,13 +26,15 @@ function _deregister(extension) {
function _register(extension) {
require.extensions[extension] = function(module, filename) {
const {code} = compile(fs.readFileSync(filename, 'utf-8'), {
const options = Object.assign({}, compileOptions, {
filename,
name: capitalise(path.basename(filename)
.replace(new RegExp(`${extension.replace('.', '\\.')}$`), '')),
generate: 'ssr',
generate: 'ssr'
});
const {code} = compile(fs.readFileSync(filename, 'utf-8'), options);
return module._compile(code, filename);
};
}

@ -65,12 +65,13 @@ export function get(key) {
}
export function init(component, options) {
component.options = options;
component._observers = { pre: blankObject(), post: blankObject() };
component._handlers = blankObject();
component._root = options._root || component;
component._bind = options._bind;
component.options = options;
component.store = component._root.options.store;
}
export function observe(key, callback, options) {
@ -195,6 +196,10 @@ export var PENDING = {};
export var SUCCESS = {};
export var FAILURE = {};
export function removeFromStore() {
this.store._remove(this);
}
export var proto = {
destroy: destroy,
get: get,

@ -5,7 +5,7 @@ import validateEventHandler from './validateEventHandler';
import { Validator } from '../index';
import { Node } from '../../interfaces';
const ariaAttributes = 'activedescendant atomic autocomplete busy checked controls describedby disabled dropeffect expanded flowto grabbed haspopup hidden invalid label labelledby level live multiline multiselectable orientation owns posinset pressed readonly relevant required selected setsize sort valuemax valuemin valuenow valuetext'.split(' ');
const ariaAttributes = 'activedescendant atomic autocomplete busy checked controls current describedby disabled dropeffect expanded flowto grabbed haspopup hidden invalid label labelledby level live multiline multiselectable orientation owns posinset pressed readonly relevant required selected setsize sort valuemax valuemin valuenow valuetext'.split(' ');
const ariaAttributeSet = new Set(ariaAttributes);
const ariaRoles = 'alert alertdialog application article banner button checkbox columnheader combobox command complementary composite contentinfo definition dialog directory document form grid gridcell group heading img input landmark link list listbox listitem log main marquee math menu menubar menuitem menuitemcheckbox menuitemradio navigation note option presentation progressbar radio radiogroup range region roletype row rowgroup rowheader scrollbar search section sectionhead select separator slider spinbutton status structure tab tablist tabpanel textbox timer toolbar tooltip tree treegrid treeitem widget window'.split(' ');

@ -1,6 +1,6 @@
import flattenReference from '../../utils/flattenReference';
import list from '../../utils/list';
import { Validator } from '../index';
import validate, { Validator } from '../index';
import validCalleeObjects from '../../utils/validCalleeObjects';
import { Node } from '../../interfaces';
@ -28,6 +28,13 @@ export default function validateEventHandlerCallee(
return;
}
if (name === 'store' && attribute.expression.callee.type === 'MemberExpression') {
if (!validator.options.store) {
validator.warn('compile with `store: true` in order to call store methods', attribute.expression.start);
}
return;
}
if (
(callee.type === 'Identifier' && validBuiltins.has(callee.name)) ||
validator.methods.has(callee.name)
@ -35,6 +42,7 @@ export default function validateEventHandlerCallee(
return;
const validCallees = ['this.*', 'event.*', 'options.*', 'console.*'].concat(
validator.options.store ? 'store.*' : [],
Array.from(validBuiltins),
Array.from(validator.methods.keys())
);

@ -22,6 +22,7 @@ export class Validator {
readonly source: string;
readonly filename: string;
options: CompileOptions;
onwarn: ({}) => void;
locator?: (pos: number) => Location;
@ -37,8 +38,8 @@ export class Validator {
constructor(parsed: Parsed, source: string, options: CompileOptions) {
this.source = source;
this.filename = options.filename;
this.onwarn = options.onwarn;
this.options = options;
this.namespace = null;
this.defaultExport = null;
@ -78,7 +79,7 @@ export default function validate(
stylesheet: Stylesheet,
options: CompileOptions
) {
const { onwarn, onerror, name, filename } = options;
const { onwarn, onerror, name, filename, store } = options;
try {
if (name && !/^[a-zA-Z_$][a-zA-Z_$0-9]*$/.test(name)) {
@ -99,6 +100,7 @@ export default function validate(
onwarn,
name,
filename,
store
});
if (parsed.js) {

@ -0,0 +1,164 @@
import {
assign,
blankObject,
differs,
dispatchObservers,
get,
observe
} from './shared.js';
function Store(state) {
this._observers = { pre: blankObject(), post: blankObject() };
this._changeHandlers = [];
this._dependents = [];
this._computed = blankObject();
this._sortedComputedProperties = [];
this._state = assign({}, state);
}
assign(Store.prototype, {
_add: function(component, props) {
this._dependents.push({
component: component,
props: props
});
},
_init: function(props) {
var state = {};
for (var i = 0; i < props.length; i += 1) {
var prop = props[i];
state['$' + prop] = this._state[prop];
}
return state;
},
_remove: function(component) {
var i = this._dependents.length;
while (i--) {
if (this._dependents[i].component === component) {
this._dependents.splice(i, 1);
return;
}
}
},
_sortComputedProperties: function() {
var computed = this._computed;
var sorted = this._sortedComputedProperties = [];
var cycles;
var visited = blankObject();
function visit(key) {
if (cycles[key]) {
throw new Error('Cyclical dependency detected');
}
if (visited[key]) return;
visited[key] = true;
var c = computed[key];
if (c) {
cycles[key] = true;
c.deps.forEach(visit);
sorted.push(c);
}
}
for (var key in this._computed) {
cycles = blankObject();
visit(key);
}
},
compute: function(key, deps, fn) {
var store = this;
var value;
var c = {
deps: deps,
update: function(state, changed, dirty) {
var values = deps.map(function(dep) {
if (dep in changed) dirty = true;
return state[dep];
});
if (dirty) {
var newValue = fn.apply(null, values);
if (differs(newValue, value)) {
value = newValue;
changed[key] = true;
state[key] = value;
}
}
}
};
c.update(this._state, {}, true);
this._computed[key] = c;
this._sortComputedProperties();
},
get: get,
observe: observe,
onchange: function(callback) {
this._changeHandlers.push(callback);
return {
cancel: function() {
var index = this._changeHandlers.indexOf(callback);
if (~index) this._changeHandlers.splice(index, 1);
}
};
},
set: function(newState) {
var oldState = this._state,
changed = this._changed = {},
dirty = false;
for (var key in newState) {
if (this._computed[key]) throw new Error("'" + key + "' is a read-only property");
if (differs(newState[key], oldState[key])) changed[key] = dirty = true;
}
if (!dirty) return;
this._state = assign({}, oldState, newState);
for (var i = 0; i < this._sortedComputedProperties.length; i += 1) {
this._sortedComputedProperties[i].update(this._state, changed);
}
for (var i = 0; i < this._changeHandlers.length; i += 1) {
this._changeHandlers[i](this._state, changed);
}
dispatchObservers(this, this._observers.pre, changed, this._state, oldState);
var dependents = this._dependents.slice(); // guard against mutations
for (var i = 0; i < dependents.length; i += 1) {
var dependent = dependents[i];
var componentState = {};
dirty = false;
for (var j = 0; j < dependent.props.length; j += 1) {
var prop = dependent.props[j];
if (prop in changed) {
componentState['$' + prop] = this._state[prop];
dirty = true;
}
}
if (dirty) dependent.component.set(componentState);
}
dispatchObservers(this, this._observers.post, changed, this._state, oldState);
}
});
export { Store };

@ -91,12 +91,13 @@ function get(key) {
}
function init(component, options) {
component.options = options;
component._observers = { pre: blankObject(), post: blankObject() };
component._handlers = blankObject();
component._root = options._root || component;
component._bind = options._bind;
component.options = options;
component.store = component._root.options.store;
}
function observe(key, callback, options) {

@ -67,12 +67,13 @@ function get(key) {
}
function init(component, options) {
component.options = options;
component._observers = { pre: blankObject(), post: blankObject() };
component._handlers = blankObject();
component._root = options._root || component;
component._bind = options._bind;
component.options = options;
component.store = component._root.options.store;
}
function observe(key, callback, options) {

@ -67,12 +67,13 @@ function get(key) {
}
function init(component, options) {
component.options = options;
component._observers = { pre: blankObject(), post: blankObject() };
component._handlers = blankObject();
component._root = options._root || component;
component._bind = options._bind;
component.options = options;
component.store = component._root.options.store;
}
function observe(key, callback, options) {

@ -87,12 +87,13 @@ function get(key) {
}
function init(component, options) {
component.options = options;
component._observers = { pre: blankObject(), post: blankObject() };
component._handlers = blankObject();
component._root = options._root || component;
component._bind = options._bind;
component.options = options;
component.store = component._root.options.store;
}
function observe(key, callback, options) {

@ -79,12 +79,13 @@ function get(key) {
}
function init(component, options) {
component.options = options;
component._observers = { pre: blankObject(), post: blankObject() };
component._handlers = blankObject();
component._root = options._root || component;
component._bind = options._bind;
component.options = options;
component.store = component._root.options.store;
}
function observe(key, callback, options) {

@ -83,12 +83,13 @@ function get(key) {
}
function init(component, options) {
component.options = options;
component._observers = { pre: blankObject(), post: blankObject() };
component._handlers = blankObject();
component._root = options._root || component;
component._bind = options._bind;
component.options = options;
component.store = component._root.options.store;
}
function observe(key, callback, options) {

@ -87,12 +87,13 @@ function get(key) {
}
function init(component, options) {
component.options = options;
component._observers = { pre: blankObject(), post: blankObject() };
component._handlers = blankObject();
component._root = options._root || component;
component._bind = options._bind;
component.options = options;
component.store = component._root.options.store;
}
function observe(key, callback, options) {

@ -99,12 +99,13 @@ function get(key) {
}
function init(component, options) {
component.options = options;
component._observers = { pre: blankObject(), post: blankObject() };
component._handlers = blankObject();
component._root = options._root || component;
component._bind = options._bind;
component.options = options;
component.store = component._root.options.store;
}
function observe(key, callback, options) {

@ -79,12 +79,13 @@ function get(key) {
}
function init(component, options) {
component.options = options;
component._observers = { pre: blankObject(), post: blankObject() };
component._handlers = blankObject();
component._root = options._root || component;
component._bind = options._bind;
component.options = options;
component.store = component._root.options.store;
}
function observe(key, callback, options) {

@ -83,12 +83,13 @@ function get(key) {
}
function init(component, options) {
component.options = options;
component._observers = { pre: blankObject(), post: blankObject() };
component._handlers = blankObject();
component._root = options._root || component;
component._bind = options._bind;
component.options = options;
component.store = component._root.options.store;
}
function observe(key, callback, options) {

@ -83,12 +83,13 @@ function get(key) {
}
function init(component, options) {
component.options = options;
component._observers = { pre: blankObject(), post: blankObject() };
component._handlers = blankObject();
component._root = options._root || component;
component._bind = options._bind;
component.options = options;
component.store = component._root.options.store;
}
function observe(key, callback, options) {

@ -83,12 +83,13 @@ function get(key) {
}
function init(component, options) {
component.options = options;
component._observers = { pre: blankObject(), post: blankObject() };
component._handlers = blankObject();
component._root = options._root || component;
component._bind = options._bind;
component.options = options;
component.store = component._root.options.store;
}
function observe(key, callback, options) {

@ -83,12 +83,13 @@ function get(key) {
}
function init(component, options) {
component.options = options;
component._observers = { pre: blankObject(), post: blankObject() };
component._handlers = blankObject();
component._root = options._root || component;
component._bind = options._bind;
component.options = options;
component.store = component._root.options.store;
}
function observe(key, callback, options) {

@ -83,12 +83,13 @@ function get(key) {
}
function init(component, options) {
component.options = options;
component._observers = { pre: blankObject(), post: blankObject() };
component._handlers = blankObject();
component._root = options._root || component;
component._bind = options._bind;
component.options = options;
component.store = component._root.options.store;
}
function observe(key, callback, options) {

@ -83,12 +83,13 @@ function get(key) {
}
function init(component, options) {
component.options = options;
component._observers = { pre: blankObject(), post: blankObject() };
component._handlers = blankObject();
component._root = options._root || component;
component._bind = options._bind;
component.options = options;
component.store = component._root.options.store;
}
function observe(key, callback, options) {

@ -87,12 +87,13 @@ function get(key) {
}
function init(component, options) {
component.options = options;
component._observers = { pre: blankObject(), post: blankObject() };
component._handlers = blankObject();
component._root = options._root || component;
component._bind = options._bind;
component.options = options;
component.store = component._root.options.store;
}
function observe(key, callback, options) {

@ -85,12 +85,13 @@ function get(key) {
}
function init(component, options) {
component.options = options;
component._observers = { pre: blankObject(), post: blankObject() };
component._handlers = blankObject();
component._root = options._root || component;
component._bind = options._bind;
component.options = options;
component.store = component._root.options.store;
}
function observe(key, callback, options) {

@ -102,12 +102,13 @@ function get(key) {
}
function init(component, options) {
component.options = options;
component._observers = { pre: blankObject(), post: blankObject() };
component._handlers = blankObject();
component._root = options._root || component;
component._bind = options._bind;
component.options = options;
component.store = component._root.options.store;
}
function observe(key, callback, options) {

@ -95,12 +95,13 @@ function get(key) {
}
function init(component, options) {
component.options = options;
component._observers = { pre: blankObject(), post: blankObject() };
component._handlers = blankObject();
component._root = options._root || component;
component._bind = options._bind;
component.options = options;
component.store = component._root.options.store;
}
function observe(key, callback, options) {

@ -81,12 +81,13 @@ function get(key) {
}
function init(component, options) {
component.options = options;
component._observers = { pre: blankObject(), post: blankObject() };
component._handlers = blankObject();
component._root = options._root || component;
component._bind = options._bind;
component.options = options;
component.store = component._root.options.store;
}
function observe(key, callback, options) {

@ -67,12 +67,13 @@ function get(key) {
}
function init(component, options) {
component.options = options;
component._observers = { pre: blankObject(), post: blankObject() };
component._handlers = blankObject();
component._root = options._root || component;
component._bind = options._bind;
component.options = options;
component.store = component._root.options.store;
}
function observe(key, callback, options) {

@ -24,7 +24,7 @@ function SvelteComponent(options) {
init(this, options);
this._state = assign({}, options.data);
this._handlers.destroy = [ondestroy]
this._handlers.destroy = [ondestroy];
var _oncreate = oncreate.bind(this);

@ -67,12 +67,13 @@ function get(key) {
}
function init(component, options) {
component.options = options;
component._observers = { pre: blankObject(), post: blankObject() };
component._handlers = blankObject();
component._root = options._root || component;
component._bind = options._bind;
component.options = options;
component.store = component._root.options.store;
}
function observe(key, callback, options) {

@ -4,7 +4,7 @@ SvelteComponent.data = function() {
return {};
};
SvelteComponent.render = function(state, options) {
SvelteComponent.render = function(state, options = {}) {
state = Object.assign({}, state);
return ``.trim();

@ -6,7 +6,7 @@ SvelteComponent.data = function() {
return {};
};
SvelteComponent.render = function(state, options) {
SvelteComponent.render = function(state, options = {}) {
state = Object.assign({}, state);
return ``.trim();

@ -91,12 +91,13 @@ function get(key) {
}
function init(component, options) {
component.options = options;
component._observers = { pre: blankObject(), post: blankObject() };
component._handlers = blankObject();
component._root = options._root || component;
component._bind = options._bind;
component.options = options;
component.store = component._root.options.store;
}
function observe(key, callback, options) {

@ -87,12 +87,13 @@ function get(key) {
}
function init(component, options) {
component.options = options;
component._observers = { pre: blankObject(), post: blankObject() };
component._handlers = blankObject();
component._root = options._root || component;
component._bind = options._bind;
component.options = options;
component.store = component._root.options.store;
}
function observe(key, callback, options) {

@ -0,0 +1,148 @@
import assert from 'assert';
import {svelte} from '../helpers.js';
describe('preprocess', () => {
it('preprocesses entire component', () => {
const source = `
<h1>Hello __NAME__!</h1>
`;
const expected = `
<h1>Hello world!</h1>
`;
return svelte.preprocess(source, {
markup: ({ content }) => {
return {
code: content.replace('__NAME__', 'world')
};
}
}).then(processed => {
assert.equal(processed.toString(), expected);
});
});
it('preprocesses style', () => {
const source = `
<div class='brand-color'>$brand</div>
<style>
.brand-color {
color: $brand;
}
</style>
`;
const expected = `
<div class='brand-color'>$brand</div>
<style>
.brand-color {
color: purple;
}
</style>
`;
return svelte.preprocess(source, {
style: ({ content }) => {
return {
code: content.replace('$brand', 'purple')
};
}
}).then(processed => {
assert.equal(processed.toString(), expected);
});
});
it('preprocesses style asynchronously', () => {
const source = `
<div class='brand-color'>$brand</div>
<style>
.brand-color {
color: $brand;
}
</style>
`;
const expected = `
<div class='brand-color'>$brand</div>
<style>
.brand-color {
color: purple;
}
</style>
`;
return svelte.preprocess(source, {
style: ({ content }) => {
return Promise.resolve({
code: content.replace('$brand', 'purple')
});
}
}).then(processed => {
assert.equal(processed.toString(), expected);
});
});
it('preprocesses script', () => {
const source = `
<script>
console.log(__THE_ANSWER__);
</script>
`;
const expected = `
<script>
console.log(42);
</script>
`;
return svelte.preprocess(source, {
script: ({ content }) => {
return {
code: content.replace('__THE_ANSWER__', '42')
};
}
}).then(processed => {
assert.equal(processed.toString(), expected);
});
});
it('parses attributes', () => {
const source = `
<style type='text/scss' data-foo="bar" bool></style>
`;
return svelte.preprocess(source, {
style: ({ attributes }) => {
assert.deepEqual(attributes, {
type: 'text/scss',
'data-foo': 'bar',
bool: true
});
}
});
});
it('ignores null/undefined returned from preprocessor', () => {
const source = `
<script>
console.log('ignore me');
</script>
`;
const expected = `
<script>
console.log('ignore me');
</script>
`;
return svelte.preprocess(source, {
script: () => null
}).then(processed => {
assert.equal(processed.toString(), expected);
});
});
});

@ -63,6 +63,7 @@ describe("runtime", () => {
compileOptions.shared = shared;
compileOptions.hydratable = hydrate;
compileOptions.dev = config.dev;
compileOptions.store = !!config.store;
// check that no ES2015+ syntax slipped in
if (!config.allowES2015) {
@ -88,7 +89,7 @@ describe("runtime", () => {
}
} catch (err) {
failed.add(dir);
showOutput(cwd, { shared, format: 'cjs' }, svelte); // eslint-disable-line no-console
showOutput(cwd, { shared, format: 'cjs', store: !!compileOptions.store }, svelte); // eslint-disable-line no-console
throw err;
}
}
@ -130,12 +131,10 @@ describe("runtime", () => {
};
};
global.window = window;
try {
SvelteComponent = require(`./samples/${dir}/main.html`);
} catch (err) {
showOutput(cwd, { shared, format: 'cjs', hydratable: hydrate }, svelte); // eslint-disable-line no-console
showOutput(cwd, { shared, format: 'cjs', hydratable: hydrate, store: !!compileOptions.store }, svelte); // eslint-disable-line no-console
throw err;
}
@ -155,7 +154,8 @@ describe("runtime", () => {
const options = Object.assign({}, {
target,
hydrate,
data: config.data
data: config.data,
store: config.store
}, config.options || {});
const component = new SvelteComponent(options);
@ -190,12 +190,12 @@ describe("runtime", () => {
config.error(assert, err);
} else {
failed.add(dir);
showOutput(cwd, { shared, format: 'cjs', hydratable: hydrate }, svelte); // eslint-disable-line no-console
showOutput(cwd, { shared, format: 'cjs', hydratable: hydrate, store: !!compileOptions.store }, svelte); // eslint-disable-line no-console
throw err;
}
})
.then(() => {
if (config.show) showOutput(cwd, { shared, format: 'cjs', hydratable: hydrate }, svelte);
if (config.show) showOutput(cwd, { shared, format: 'cjs', hydratable: hydrate, store: !!compileOptions.store }, svelte);
});
});
}

@ -10,19 +10,17 @@ export default {
selected: [ values[1] ]
},
'skip-ssr': true, // values are rendered as [object Object]
html: `
<label>
<input type="checkbox"> Alpha
<input type="checkbox" value="[object Object]"> Alpha
</label>
<label>
<input type="checkbox"> Beta
<input type="checkbox" value="[object Object]"> Beta
</label>
<label>
<input type="checkbox"> Gamma
<input type="checkbox" value="[object Object]"> Gamma
</label>
<p>Beta</p>`,
@ -40,15 +38,15 @@ export default {
assert.htmlEqual( target.innerHTML, `
<label>
<input type="checkbox"> Alpha
<input type="checkbox" value="[object Object]"> Alpha
</label>
<label>
<input type="checkbox"> Beta
<input type="checkbox" value="[object Object]"> Beta
</label>
<label>
<input type="checkbox"> Gamma
<input type="checkbox" value="[object Object]"> Gamma
</label>
<p>Alpha, Beta</p>
@ -61,15 +59,15 @@ export default {
assert.htmlEqual( target.innerHTML, `
<label>
<input type="checkbox"> Alpha
<input type="checkbox" value="[object Object]"> Alpha
</label>
<label>
<input type="checkbox"> Beta
<input type="checkbox" value="[object Object]"> Beta
</label>
<label>
<input type="checkbox"> Gamma
<input type="checkbox" value="[object Object]"> Gamma
</label>
<p>Beta, Gamma</p>

@ -10,19 +10,17 @@ export default {
selected: [ values[1] ]
},
'skip-ssr': true, // values are rendered as [object Object]
html: `
<label>
<input type="checkbox"> Alpha
<input type="checkbox" value="[object Object]"> Alpha
</label>
<label>
<input type="checkbox"> Beta
<input type="checkbox" value="[object Object]"> Beta
</label>
<label>
<input type="checkbox"> Gamma
<input type="checkbox" value="[object Object]"> Gamma
</label>
<p>Beta</p>`,
@ -40,15 +38,15 @@ export default {
assert.htmlEqual( target.innerHTML, `
<label>
<input type="checkbox"> Alpha
<input type="checkbox" value="[object Object]"> Alpha
</label>
<label>
<input type="checkbox"> Beta
<input type="checkbox" value="[object Object]"> Beta
</label>
<label>
<input type="checkbox"> Gamma
<input type="checkbox" value="[object Object]"> Gamma
</label>
<p>Alpha, Beta</p>
@ -61,15 +59,15 @@ export default {
assert.htmlEqual( target.innerHTML, `
<label>
<input type="checkbox"> Alpha
<input type="checkbox" value="[object Object]"> Alpha
</label>
<label>
<input type="checkbox"> Beta
<input type="checkbox" value="[object Object]"> Beta
</label>
<label>
<input type="checkbox"> Gamma
<input type="checkbox" value="[object Object]"> Gamma
</label>
<p>Beta, Gamma</p>

@ -10,19 +10,17 @@ export default {
selected: values[1]
},
'skip-ssr': true, // values are rendered as [object Object]
html: `
<label>
<input type="radio"> Alpha
<input type="radio" value="[object Object]"> Alpha
</label>
<label>
<input type="radio"> Beta
<input type="radio" value="[object Object]"> Beta
</label>
<label>
<input type="radio"> Gamma
<input type="radio" value="[object Object]"> Gamma
</label>
<p>Beta</p>`,
@ -40,15 +38,15 @@ export default {
assert.htmlEqual( target.innerHTML, `
<label>
<input type="radio"> Alpha
<input type="radio" value="[object Object]"> Alpha
</label>
<label>
<input type="radio"> Beta
<input type="radio" value="[object Object]"> Beta
</label>
<label>
<input type="radio"> Gamma
<input type="radio" value="[object Object]"> Gamma
</label>
<p>Alpha</p>
@ -65,15 +63,15 @@ export default {
assert.htmlEqual( target.innerHTML, `
<label>
<input type="radio"> Alpha
<input type="radio" value="[object Object]"> Alpha
</label>
<label>
<input type="radio"> Beta
<input type="radio" value="[object Object]"> Beta
</label>
<label>
<input type="radio"> Gamma
<input type="radio" value="[object Object]"> Gamma
</label>
<p>Gamma</p>

@ -0,0 +1,3 @@
export default {
html: `<a href='/cool'>link</a>`
};

@ -0,0 +1,10 @@
<Link x href="/cool"/>
<script>
import Link from './Link.html';
export default {
components: {
Link
}
};
</script>

@ -1,6 +1,10 @@
export default {
dev: true,
data: {
a: 42
},
test ( assert, component ) {
try {
component.set({ foo: 1 });

@ -1,10 +1,14 @@
export default {
dev: true,
data: {
a: 42
},
test ( assert, component ) {
const obj = { a: 1 };
component.set( obj );
component.set( obj ); // will fail if the object is not cloned
component.destroy();
}
}
};

@ -0,0 +1,28 @@
import { Store } from '../../../../store.js';
const store = new Store({
name: 'world'
});
export default {
store,
html: `
<h1>Hello world!</h1>
<input>
`,
test(assert, component, target, window) {
const input = target.querySelector('input');
const event = new window.Event('input');
input.value = 'everybody';
input.dispatchEvent(event);
assert.equal(store.get('name'), 'everybody');
assert.htmlEqual(target.innerHTML, `
<h1>Hello everybody!</h1>
<input>
`);
}
};

@ -0,0 +1,10 @@
<h1>Hello {{$name}}!</h1>
<NameInput/>
<script>
import NameInput from './NameInput.html';
export default {
components: { NameInput }
};
</script>

@ -0,0 +1,15 @@
{{#if isVisible}}
<div class='{{todo.done ? "done": "pending"}}'>{{todo.description}}</div>
{{/if}}
<script>
export default {
computed: {
isVisible: ($filter, todo) => {
if ($filter === 'all') return true;
if ($filter === 'done') return todo.done;
if ($filter === 'pending') return !todo.done;
}
}
};
</script>

@ -0,0 +1,63 @@
import { Store } from '../../../../store.js';
class MyStore extends Store {
setFilter(filter) {
this.set({ filter });
}
toggleTodo(todo) {
todo.done = !todo.done;
this.set({ todos: this.get('todos') });
}
}
const todos = [
{
description: 'Buy some milk',
done: true,
},
{
description: 'Do the laundry',
done: true,
},
{
description: "Find life's true purpose",
done: false,
}
];
const store = new MyStore({
filter: 'all',
todos
});
export default {
store,
html: `
<div class='done'>Buy some milk</div>
<div class='done'>Do the laundry</div>
<div class='pending'>Find life's true purpose</div>
`,
test(assert, component, target) {
store.setFilter('pending');
assert.htmlEqual(target.innerHTML, `
<div class='pending'>Find life's true purpose</div>
`);
store.toggleTodo(todos[1]);
assert.htmlEqual(target.innerHTML, `
<div class='pending'>Do the laundry</div>
<div class='pending'>Find life's true purpose</div>
`);
store.setFilter('done');
assert.htmlEqual(target.innerHTML, `
<div class='done'>Buy some milk</div>
`);
}
};

@ -0,0 +1,11 @@
{{#each $todos as todo}}
<Todo :todo/>
{{/each}}
<script>
import Todo from './Todo.html';
export default {
components: { Todo }
};
</script>

@ -0,0 +1 @@
<input on:input='store.setName(this.value)'>

@ -0,0 +1,34 @@
import { Store } from '../../../../store.js';
class MyStore extends Store {
setName(name) {
this.set({ name });
}
}
const store = new MyStore({
name: 'world'
});
export default {
store,
html: `
<h1>Hello world!</h1>
<input>
`,
test(assert, component, target, window) {
const input = target.querySelector('input');
const event = new window.Event('input');
input.value = 'everybody';
input.dispatchEvent(event);
assert.equal(store.get('name'), 'everybody');
assert.htmlEqual(target.innerHTML, `
<h1>Hello everybody!</h1>
<input>
`);
}
};

@ -0,0 +1,10 @@
<h1>Hello {{$name}}!</h1>
<NameInput/>
<script>
import NameInput from './NameInput.html';
export default {
components: { NameInput }
};
</script>

@ -0,0 +1,17 @@
import { Store } from '../../../../store.js';
const store = new Store({
name: 'world'
});
export default {
store,
html: `<h1>Hello world!</h1>`,
test(assert, component, target) {
store.set({ name: 'everybody' });
assert.htmlEqual(target.innerHTML, `<h1>Hello everybody!</h1>`);
}
};

@ -0,0 +1 @@
<h1>Hello {{$name}}!</h1>

@ -0,0 +1,17 @@
export default {
test(assert, component, target, window, raf) {
component.set({ visible: true });
const div = target.querySelector('div');
assert.equal(div.foo, 0);
raf.tick(50);
assert.equal(div.foo, 100);
raf.tick(100);
assert.equal(div.foo, 200);
raf.tick(101);
component.destroy();
},
};

@ -0,0 +1,18 @@
{{#if visible}}
<div in:foo='{k: 200}'>fades in</div>
{{/if}}
<script>
export default {
transitions: {
foo: function(node, params) {
return {
duration: 100,
tick: t => {
node.foo = t * params.k;
}
};
}
}
};
</script>

@ -22,7 +22,8 @@ function tryToReadFile(file) {
describe("ssr", () => {
before(() => {
require("../../ssr/register")({
extensions: ['.svelte', '.html']
extensions: ['.svelte', '.html'],
store: true
});
return setupHtmlEqual();
@ -98,9 +99,15 @@ describe("ssr", () => {
delete require.cache[resolved];
});
require("../../ssr/register")({
store: !!config.store
});
try {
const component = require(`../runtime/samples/${dir}/main.html`);
const html = component.render(config.data);
const html = component.render(config.data, {
store: config.store
});
if (config.html) {
assert.htmlEqual(html, config.html);

@ -0,0 +1,190 @@
import fs from 'fs';
import assert from 'assert';
import MagicString from 'magic-string';
import { parse } from 'acorn';
import { Store } from '../../store.js';
describe('store', () => {
it('is written in ES5', () => {
const source = fs.readFileSync('store.js', 'utf-8');
const ast = parse(source, {
sourceType: 'module'
});
const magicString = new MagicString(source);
ast.body.forEach(node => {
if (/^(Im|Ex)port/.test(node.type)) magicString.remove(node.start, node.end);
});
parse(magicString.toString(), {
ecmaVersion: 5
});
});
describe('get', () => {
it('gets a specific key', () => {
const store = new Store({
foo: 'bar'
});
assert.equal(store.get('foo'), 'bar');
});
it('gets the entire state object', () => {
const store = new Store({
foo: 'bar'
});
assert.deepEqual(store.get(), { foo: 'bar' });
});
});
describe('set', () => {
it('sets state', () => {
const store = new Store();
store.set({
foo: 'bar'
});
assert.equal(store.get('foo'), 'bar');
});
});
describe('observe', () => {
it('observes state', () => {
let newFoo;
let oldFoo;
const store = new Store({
foo: 'bar'
});
store.observe('foo', (n, o) => {
newFoo = n;
oldFoo = o;
});
assert.equal(newFoo, 'bar');
assert.equal(oldFoo, undefined);
store.set({
foo: 'baz'
});
assert.equal(newFoo, 'baz');
assert.equal(oldFoo, 'bar');
});
});
describe('onchange', () => {
it('fires a callback when state changes', () => {
const store = new Store();
let count = 0;
let args;
store.onchange((state, changed) => {
count += 1;
args = { state, changed };
});
store.set({ foo: 'bar' });
assert.equal(count, 1);
assert.deepEqual(args, {
state: { foo: 'bar' },
changed: { foo: true }
});
// this should be a noop
store.set({ foo: 'bar' });
assert.equal(count, 1);
// this shouldn't
store.set({ foo: 'baz' });
assert.equal(count, 2);
assert.deepEqual(args, {
state: { foo: 'baz' },
changed: { foo: true }
});
});
});
describe('computed', () => {
it('computes a property based on data', () => {
const store = new Store({
foo: 1
});
store.compute('bar', ['foo'], foo => foo * 2);
assert.equal(store.get('bar'), 2);
const values = [];
store.observe('bar', bar => {
values.push(bar);
});
store.set({ foo: 2 });
assert.deepEqual(values, [2, 4]);
});
it('computes a property based on another computed property', () => {
const store = new Store({
foo: 1
});
store.compute('bar', ['foo'], foo => foo * 2);
store.compute('baz', ['bar'], bar => bar * 2);
assert.equal(store.get('baz'), 4);
const values = [];
store.observe('baz', baz => {
values.push(baz);
});
store.set({ foo: 2 });
assert.deepEqual(values, [4, 8]);
});
it('prevents computed properties from being set', () => {
const store = new Store({
foo: 1
});
store.compute('bar', ['foo'], foo => foo * 2);
assert.throws(() => {
store.set({ bar: 'whatever' });
}, /'bar' is a read-only property/);
});
it('allows multiple dependents to depend on the same computed property', () => {
const store = new Store({
a: 1
});
store.compute('b', ['a'], a => a * 2);
store.compute('c', ['b'], b => b * 3);
store.compute('d', ['b'], b => b * 4);
assert.deepEqual(store.get(), { a: 1, b: 2, c: 6, d: 8 });
// bit cheeky, testing a private property, but whatever
assert.equal(store._sortedComputedProperties.length, 3);
});
it('prevents cyclical dependencies', () => {
const store = new Store();
assert.throws(() => {
store.compute('a', ['b'], b => b + 1);
store.compute('b', ['a'], a => a + 1);
}, /Cyclical dependency detected/);
});
});
});

@ -0,0 +1 @@
<button on:click='store.foo()'>foo</button>

@ -0,0 +1,8 @@
[{
"message": "compile with `store: true` in order to call store methods",
"loc": {
"line": 1,
"column": 18
},
"pos": 18
}]

@ -10,7 +10,7 @@
version "8.0.53"
resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.53.tgz#396b35af826fa66aad472c8cb7b8d5e277f4e6d8"
"@types/node@^7.0.18", "@types/node@^7.0.48":
"@types/node@^7.0.18":
version "7.0.48"
resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.48.tgz#24bfdc0aa82e8f6dbd017159c58094a2e06d0abb"
@ -64,8 +64,8 @@ ajv@^4.9.1:
json-stable-stringify "^1.0.1"
ajv@^5.1.0, ajv@^5.2.3, ajv@^5.3.0:
version "5.4.0"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.4.0.tgz#32d1cf08dbc80c432f426f12e10b2511f6b46474"
version "5.5.1"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.1.tgz#b38bb8876d9e86bee994956a04e721e88b248eb2"
dependencies:
co "^4.6.0"
fast-deep-equal "^1.0.0"
@ -441,8 +441,8 @@ chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0:
supports-color "^4.0.0"
chardet@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.0.tgz#0bbe1355ac44d7a3ed4a925707c4ef70f8190f6c"
version "0.4.2"
resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2"
chokidar@^1.7.0:
version "1.7.0"
@ -538,10 +538,8 @@ commander@2.9.0:
graceful-readlink ">= 1.0.0"
commander@^2.9.0:
version "2.12.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.12.0.tgz#2f13615c39c687a77926aa68ef25c099db1e72fb"
dependencies:
"@types/node" "^7.0.48"
version "2.12.2"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.12.2.tgz#0f5946c427ed9ec0d91a46bb9def53e54650e555"
commondir@^1.0.1:
version "1.0.1"
@ -580,8 +578,8 @@ content-type-parser@^1.0.1:
resolved "https://registry.yarnpkg.com/content-type-parser/-/content-type-parser-1.0.2.tgz#caabe80623e63638b2502fd4c7f12ff4ce2352e7"
convert-source-map@^1.3.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.0.tgz#9acd70851c6d5dfdd93d9282e5edf94a03ff46b5"
version "1.5.1"
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5"
core-js@^2.4.0:
version "2.5.1"
@ -744,12 +742,11 @@ doctrine@1.5.0:
esutils "^2.0.2"
isarray "^1.0.0"
doctrine@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.0.0.tgz#c73d8d2909d22291e1a007a395804da8b665fe63"
doctrine@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.0.2.tgz#68f96ce8efc56cc42651f1faadb4f175273b0075"
dependencies:
esutils "^2.0.2"
isarray "^1.0.0"
dom-serializer@0:
version "0.1.0"
@ -890,8 +887,8 @@ eslint-scope@^3.7.1:
estraverse "^4.1.1"
eslint@^4.3.0:
version "4.11.0"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.11.0.tgz#39a8c82bc0a3783adf5a39fa27fdd9d36fac9a34"
version "4.12.1"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.12.1.tgz#5ec1973822b4a066b353770c3c6d69a2a188e880"
dependencies:
ajv "^5.3.0"
babel-code-frame "^6.22.0"
@ -899,7 +896,7 @@ eslint@^4.3.0:
concat-stream "^1.6.0"
cross-spawn "^5.1.0"
debug "^3.0.1"
doctrine "^2.0.0"
doctrine "^2.0.2"
eslint-scope "^3.7.1"
espree "^3.5.2"
esquery "^1.0.0"
@ -908,7 +905,7 @@ eslint@^4.3.0:
file-entry-cache "^2.0.0"
functional-red-black-tree "^1.0.1"
glob "^7.1.2"
globals "^9.17.0"
globals "^11.0.1"
ignore "^3.3.3"
imurmurhash "^0.1.4"
inquirer "^3.0.6"
@ -1030,10 +1027,14 @@ extract-zip@^1.0.3:
mkdirp "0.5.0"
yauzl "2.4.1"
extsprintf@1.3.0, extsprintf@^1.2.0:
extsprintf@1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
extsprintf@^1.2.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
fast-deep-equal@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz#96256a3bc975595eb36d82e9929d060d893439ff"
@ -1272,7 +1273,11 @@ glob@^7.0.3, glob@^7.0.5, glob@^7.0.6, glob@^7.1.1, glob@^7.1.2:
once "^1.3.0"
path-is-absolute "^1.0.0"
globals@^9.17.0, globals@^9.18.0:
globals@^11.0.1:
version "11.0.1"
resolved "https://registry.yarnpkg.com/globals/-/globals-11.0.1.tgz#12a87bb010e5154396acc535e1e43fc753b0e5e8"
globals@^9.18.0:
version "9.18.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a"
@ -1599,8 +1604,8 @@ is-path-in-cwd@^1.0.0:
is-path-inside "^1.0.0"
is-path-inside@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.0.tgz#fc06e5a1683fbda13de667aff717bbc10a48f37f"
version "1.0.1"
resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036"
dependencies:
path-is-inside "^1.0.1"
@ -1723,8 +1728,8 @@ jsbn@~0.1.0:
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
jsdom@^11.1.0:
version "11.4.0"
resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-11.4.0.tgz#a3941a9699cbb0d61f8ab86f6f28f4ad5ea60d04"
version "11.5.1"
resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-11.5.1.tgz#5df753b8d0bca20142ce21f4f6c039f99a992929"
dependencies:
abab "^1.0.3"
acorn "^5.1.2"
@ -1737,6 +1742,7 @@ jsdom@^11.1.0:
domexception "^1.0.0"
escodegen "^1.9.0"
html-encoding-sniffer "^1.0.1"
left-pad "^1.2.0"
nwmatcher "^1.4.3"
parse5 "^3.0.2"
pn "^1.0.0"
@ -1839,6 +1845,10 @@ lcid@^1.0.0:
dependencies:
invert-kv "^1.0.0"
left-pad@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/left-pad/-/left-pad-1.2.0.tgz#d30a73c6b8201d8f7d8e7956ba9616087a68e0ee"
levn@^0.3.0, levn@~0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee"
@ -1866,8 +1876,8 @@ load-json-file@^2.0.0:
strip-bom "^3.0.0"
locate-character@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/locate-character/-/locate-character-2.0.1.tgz#48f9599f342daf26f73db32f45941eae37bae391"
version "2.0.3"
resolved "https://registry.yarnpkg.com/locate-character/-/locate-character-2.0.3.tgz#85a5aedae26b3536c3e97016af164cdaa3ae5ae1"
locate-path@^2.0.0:
version "2.0.0"
@ -3286,8 +3296,8 @@ typescript@^1.8.9:
resolved "https://registry.yarnpkg.com/typescript/-/typescript-1.8.10.tgz#b475d6e0dff0bf50f296e5ca6ef9fbb5c7320f1e"
typescript@^2.6.1:
version "2.6.1"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.6.1.tgz#ef39cdea27abac0b500242d6726ab90e0c846631"
version "2.6.2"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.6.2.tgz#3c5b6fd7f6de0914269027f03c0946758f7673a4"
uglify-js@^2.6:
version "2.8.29"

Loading…
Cancel
Save