Merge branch 'master' into master

pull/2379/head
Rich Harris 5 years ago committed by GitHub
commit c1960f9ef8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,7 +1,3 @@
src/shared
shared.js
store.js
test/test.js
test/setup.js
**/_actual.js
**/expected.js
**/expected.js
test/*/samples/*/output.js

@ -1,43 +1,76 @@
{
"root": true,
"rules": {
"indent": [2, "tab", { "SwitchCase": 1 }],
"semi": [2, "always"],
"keyword-spacing": [2, { "before": true, "after": true }],
"space-before-blocks": [2, "always"],
"no-mixed-spaces-and-tabs": [2, "smart-tabs"],
"no-cond-assign": 0,
"no-unused-vars": 2,
"object-shorthand": [2, "always"],
"no-const-assign": 2,
"no-class-assign": 2,
"no-this-before-super": 2,
"no-var": 2,
"no-unreachable": 2,
"valid-typeof": 2,
"quote-props": [2, "as-needed"],
"one-var": [2, "never"],
"prefer-arrow-callback": 2,
"prefer-const": [2, { "destructuring": "all" }],
"arrow-spacing": 2,
"no-inner-declarations": 0
},
"env": {
"es6": true,
"browser": true,
"node": true,
"mocha": true
},
"extends": [
"eslint:recommended",
"plugin:import/errors",
"plugin:import/warnings"
],
"parserOptions": {
"ecmaVersion": 9,
"sourceType": "module"
},
"settings": {
"import/core-modules": ["svelte"]
}
"root": true,
"rules": {
"indent": "off",
"no-unused-vars": "off",
"semi": [2, "always"],
"keyword-spacing": [2, { "before": true, "after": true }],
"space-before-blocks": [2, "always"],
"no-mixed-spaces-and-tabs": [2, "smart-tabs"],
"no-cond-assign": 0,
"object-shorthand": [2, "always"],
"no-const-assign": 2,
"no-class-assign": 2,
"no-this-before-super": 2,
"no-var": 2,
"no-unreachable": 2,
"valid-typeof": 2,
"quote-props": [2, "as-needed"],
"one-var": [2, "never"],
"prefer-arrow-callback": 2,
"prefer-const": [2, { "destructuring": "all" }],
"arrow-spacing": 2,
"no-inner-declarations": 0,
"@typescript-eslint/indent": ["error", "tab", {
"SwitchCase": 1,
"ignoredNodes": ["TemplateLiteral"]
}],
"@typescript-eslint/camelcase": "off",
"@typescript-eslint/no-use-before-define": "off",
"@typescript-eslint/array-type": ["error", "array-simple"],
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/explicit-member-accessibility": "off",
"@typescript-eslint/no-unused-vars": ["error", {
"argsIgnorePattern": "^_"
}],
"@typescript-eslint/no-object-literal-type-assertion": ["error", {
"allowAsParameter": true
}],
"@typescript-eslint/no-unused-vars": "off"
},
"env": {
"es6": true,
"browser": true,
"node": true,
"mocha": true
},
"extends": [
"eslint:recommended",
"plugin:import/errors",
"plugin:import/warnings",
"plugin:import/typescript",
"plugin:@typescript-eslint/recommended"
],
"parserOptions": {
"ecmaVersion": 9,
"sourceType": "module"
},
"settings": {
"import/core-modules": [
"svelte",
"svelte/internal",
"svelte/store",
"svelte/easing",
"estree"
]
},
"overrides": [
{
"files": ["*.js"],
"rules": {
"@typescript-eslint/no-var-requires": "off"
}
}
]
}

@ -1,7 +1,8 @@
language: node_js
node_js:
- "node"
- "8"
- "10"
- "12"
env:
global:
- BUILD_TIMEOUT=20000

941
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -18,6 +18,9 @@
"svelte",
"README.md"
],
"engines": {
"node": ">= 8"
},
"types": "types/runtime",
"scripts": {
"test": "mocha --opts mocha.opts",
@ -35,7 +38,8 @@
"prepublishOnly": "export PUBLISH=true && npm test && npm run create-stubs",
"create-stubs": "node scripts/create-stubs.js",
"tsd": "tsc -p . --emitDeclarationOnly",
"typecheck": "tsc -p . --noEmit"
"typecheck": "tsc -p . --noEmit",
"lint": "eslint \"{src,test}/**/*.{ts,js}\""
},
"repository": {
"type": "git",
@ -57,12 +61,16 @@
"@sveltejs/svelte-repl": "0.0.5",
"@types/mocha": "^5.2.0",
"@types/node": "^10.5.5",
"@typescript-eslint/eslint-plugin": "^1.9.0",
"@typescript-eslint/parser": "^1.9.0",
"acorn": "^6.1.1",
"acorn-dynamic-import": "^4.0.0",
"agadoo": "^1.0.1",
"c8": "^3.4.0",
"codecov": "^3.0.0",
"css-tree": "1.0.0-alpha22",
"eslint": "^5.16.0",
"eslint-plugin-import": "^2.17.3",
"estree-walker": "^0.6.1",
"is-reference": "^1.1.1",
"jsdom": "^12.2.0",

@ -1,4 +1,4 @@
FROM mhart/alpine-node:11.14
FROM mhart/alpine-node:12
# install dependencies
WORKDIR /app
@ -9,7 +9,7 @@ RUN npm ci --production
# Only copy over the Node pieces we need
# ~> Saves 35MB
###
FROM mhart/alpine-node:base-11.14
FROM mhart/alpine-node:slim-12
WORKDIR /app
COPY --from=0 /app .

@ -3,4 +3,4 @@
let name = 'Rick Astley';
</script>
<img {src} alt="{name} dancing">
<img {src} alt="{name} dances.">

@ -19,10 +19,10 @@ When building web apps, it's important to make sure that they're *accessible* to
In this case, we're missing the `alt` attribute that describes the image for people using screenreaders, or people with slow or flaky internet connections that can't download the image. Let's add one:
```html
<img src={src} alt="A man dancing">
<img src={src} alt="A man dances.">
```
We can use curly braces *inside* attributes. Try changing it to `"{name} dancing"` — remember to declare a `name` variable in the `<script>` block.
We can use curly braces *inside* attributes. Try changing it to `"{name} dances."` — remember to declare a `name` variable in the `<script>` block.
## Shorthand attributes
@ -30,6 +30,6 @@ We can use curly braces *inside* attributes. Try changing it to `"{name} dancing
It's not uncommon to have an attribute where the name and value are the same, like `src={src}`. Svelte gives us a convenient shorthand for these cases:
```html
<img {src} alt="A man dancing">
<img {src} alt="A man dances.">
```

@ -13,7 +13,7 @@ function addNumber() {
}
```
But there's a more *idiomatic* solution:
But there's a more idiomatic solution:
```js
function addNumber() {
@ -23,4 +23,10 @@ function addNumber() {
You can use similar patterns to replace `pop`, `shift`, `unshift` and `splice`.
> Assignments to *properties* of arrays and objects — e.g. `obj.foo += 1` or `array[i] = x` — work the same way as assignments to the values themselves.
Assignments to *properties* of arrays and objects — e.g. `obj.foo += 1` or `array[i] = x` — work the same way as assignments to the values themselves.
```js
function addNumber() {
numbers[numbers.length] = numbers.length + 1;
}
```

@ -10,9 +10,9 @@ We can easily specify default values for props:
</script>
```
If we now instantiate the component without an `answer` prop, it will fall back to the default:
If we now add a second component *without* an `answer` prop, it will fall back to the default:
```html
<Nested answer={42}/>
<Nested/>
```
```

@ -5,7 +5,7 @@ const now = (typeof process !== 'undefined' && process.hrtime)
}
: () => self.performance.now();
type Timing = {
interface Timing {
label: string;
start: number;
end: number;

@ -24,13 +24,13 @@ import unwrap_parens from './utils/unwrap_parens';
import Slot from './nodes/Slot';
import { Node as ESTreeNode } from 'estree';
type ComponentOptions = {
interface ComponentOptions {
namespace?: string;
tag?: string;
immutable?: boolean;
accessors?: boolean;
preserveWhitespace?: boolean;
};
}
// We need to tell estree-walker that it should always
// look for an `else` block, otherwise it might get
@ -97,7 +97,7 @@ export default class Component {
node_for_declaration: Map<string, Node> = new Map();
partly_hoisted: string[] = [];
fully_hoisted: string[] = [];
reactive_declarations: Array<{ assignees: Set<string>, dependencies: Set<string>, node: Node, declaration: Node }> = [];
reactive_declarations: Array<{ assignees: Set<string>; dependencies: Set<string>; node: Node; declaration: Node }> = [];
reactive_declaration_nodes: Set<Node> = new Set();
has_reactive_assignments = false;
injected_reactive_declaration_vars: Set<string> = new Set();
@ -106,12 +106,12 @@ export default class Component {
indirect_dependencies: Map<string, Set<string>> = new Map();
file: string;
locate: (c: number) => { line: number, column: number };
locate: (c: number) => { line: number; column: number };
// TODO this does the same as component.locate! remove one or the other
locator: (search: number, startIndex?: number) => {
line: number,
column: number
line: number;
column: number;
};
stylesheet: Stylesheet;
@ -140,6 +140,7 @@ export default class Component {
this.compile_options = compile_options;
this.file = compile_options.filename && (
// eslint-disable-next-line no-useless-escape
typeof process !== 'undefined' ? compile_options.filename.replace(process.cwd(), '').replace(/^[\/\\]/, '') : compile_options.filename
);
this.locate = getLocator(this.source);
@ -248,7 +249,7 @@ export default class Component {
result = result
.replace(/__svelte:self__/g, this.name)
.replace(compile_options.generate === 'ssr' ? /(@+|#+)(\w*(?:-\w*)?)/g : /(@+)(\w*(?:-\w*)?)/g, (match: string, sigil: string, name: string) => {
.replace(compile_options.generate === 'ssr' ? /(@+|#+)(\w*(?:-\w*)?)/g : /(@+)(\w*(?:-\w*)?)/g, (_match: string, sigil: string, name: string) => {
if (sigil === '@') {
if (internal_exports.has(name)) {
if (compile_options.dev && internal_exports.has(`${name}Dev`)) name = `${name}Dev`;
@ -379,7 +380,7 @@ export default class Component {
reserved.forEach(add);
internal_exports.forEach(add);
this.var_lookup.forEach((value, key) => add(key));
this.var_lookup.forEach((_value, key) => add(key));
return (name: string) => {
if (test) name = `${name}$`;
@ -398,12 +399,12 @@ export default class Component {
error(
pos: {
start: number,
end: number
start: number;
end: number;
},
e : {
code: string,
message: string
e: {
code: string;
message: string;
}
) {
error(e.message, {
@ -418,12 +419,12 @@ export default class Component {
warn(
pos: {
start: number,
end: number
start: number;
end: number;
},
warning: {
code: string,
message: string
code: string;
message: string;
}
) {
if (!this.locator) {
@ -527,7 +528,7 @@ export default class Component {
let result = '';
script.content.body.forEach((node, i) => {
script.content.body.forEach((node) => {
if (this.hoistable_nodes.has(node) || this.reactive_declaration_nodes.has(node)) {
if (a !== b) result += `[✂${a}-${b}✂]`;
a = node.end;
@ -564,7 +565,7 @@ export default class Component {
this.add_sourcemap_locations(script.content);
let { scope, globals } = create_scopes(script.content);
const { scope, globals } = create_scopes(script.content);
this.module_scope = scope;
scope.declarations.forEach((node, name) => {
@ -588,7 +589,7 @@ export default class Component {
this.error(node, {
code: 'illegal-subscription',
message: `Cannot reference store value inside <script context="module">`
})
});
} else {
this.add_var({
name,
@ -624,7 +625,7 @@ export default class Component {
});
});
let { scope: instance_scope, map, globals } = create_scopes(script.content);
const { scope: instance_scope, map, globals } = create_scopes(script.content);
this.instance_scope = instance_scope;
this.instance_scope_map = map;
@ -646,7 +647,7 @@ export default class Component {
this.node_for_declaration.set(name, node);
});
globals.forEach((node, name) => {
globals.forEach((_node, name) => {
if (this.var_lookup.has(name)) return;
if (this.injected_reactive_declaration_vars.has(name)) {
@ -705,7 +706,7 @@ export default class Component {
let scope = instance_scope;
walk(this.ast.instance.content, {
enter(node, parent) {
enter(node) {
if (map.has(node)) {
scope = map.get(node);
}
@ -738,7 +739,7 @@ export default class Component {
scope = scope.parent;
}
}
})
});
}
extract_reactive_store_references() {
@ -786,7 +787,7 @@ export default class Component {
}
if (name[0] === '$' && name[1] !== '$') {
return `${name.slice(1)}.set(${name})`
return `${name.slice(1)}.set(${name})`;
}
if (variable && !variable.referenced && !variable.is_reactive_dependency && !variable.export_name && !name.startsWith('$$')) {
@ -888,13 +889,13 @@ export default class Component {
}
if (variable.writable && variable.name !== variable.export_name) {
code.prependRight(declarator.id.start, `${variable.export_name}: `)
code.prependRight(declarator.id.start, `${variable.export_name}: `);
}
if (next) {
const next_variable = component.var_lookup.get(next.id.name)
const next_variable = component.var_lookup.get(next.id.name);
const new_declaration = !next_variable.export_name
|| (current_group.insert && next_variable.subscribable)
|| (current_group.insert && next_variable.subscribable);
if (new_declaration) {
code.overwrite(declarator.end, next.start, ` ${node.kind} `);
@ -904,7 +905,7 @@ export default class Component {
current_group = null;
if (variable.subscribable) {
let insert = get_insert(variable);
const insert = get_insert(variable);
if (next) {
code.overwrite(declarator.end, next.start, `; ${insert}; ${node.kind} `);
@ -975,9 +976,9 @@ export default class Component {
if (!d.init) return false;
if (d.init.type !== 'Literal') return false;
const v = this.var_lookup.get(d.id.name)
if (v.reassigned) return false
if (v.export_name) return false
const v = this.var_lookup.get(d.id.name);
if (v.reassigned) return false;
if (v.export_name) return false;
if (this.var_lookup.get(d.id.name).reassigned) return false;
if (this.vars.find(variable => variable.name === d.id.name && variable.module)) return false;
@ -1006,7 +1007,7 @@ export default class Component {
});
const checked = new Set();
let walking = new Set();
const walking = new Set();
const is_hoistable = fn_declaration => {
if (fn_declaration.type === 'ExportNamedDeclaration') {
@ -1015,7 +1016,7 @@ export default class Component {
const instance_scope = this.instance_scope;
let scope = this.instance_scope;
let map = this.instance_scope_map;
const map = this.instance_scope_map;
let hoistable = true;
@ -1051,7 +1052,7 @@ export default class Component {
hoistable = false;
} else if (!is_hoistable(other_declaration)) {
hoistable = false;
}
}
}
else {
@ -1103,7 +1104,7 @@ export default class Component {
const dependencies = new Set();
let scope = this.instance_scope;
let map = this.instance_scope_map;
const map = this.instance_scope_map;
walk(node.body, {
enter(node, parent) {
@ -1320,14 +1321,16 @@ function process_component_options(component: Component, nodes) {
case 'accessors':
case 'immutable':
case 'preserveWhitespace':
{
const code = `invalid-${name}-value`;
const message = `${name} attribute must be true or false`
const message = `${name} attribute must be true or false`;
const value = get_value(attribute, code, message);
if (typeof value !== 'boolean') component.error(attribute, { code, message });
component_options[name] = value;
break;
}
default:
component.error(attribute, {

@ -5,10 +5,10 @@ import { stringify_props } from './utils/stringify_props';
const wrappers = { esm, cjs };
type Export = {
interface Export {
name: string;
as: string;
};
}
export default function create_module(
code: string,
@ -16,7 +16,7 @@ export default function create_module(
name: string,
banner: string,
sveltePath = 'svelte',
helpers: { name: string, alias: string }[],
helpers: Array<{ name: string; alias: string }>,
imports: Node[],
module_exports: Export[],
source: string
@ -44,7 +44,7 @@ function esm(
banner: string,
sveltePath: string,
internal_path: string,
helpers: { name: string, alias: string }[],
helpers: Array<{ name: string; alias: string }>,
imports: Node[],
module_exports: Export[],
source: string
@ -84,7 +84,7 @@ function cjs(
banner: string,
sveltePath: string,
internal_path: string,
helpers: { name: string, alias: string }[],
helpers: Array<{ name: string; alias: string }>,
imports: Node[],
module_exports: Export[]
) {
@ -115,7 +115,7 @@ function cjs(
const source = edit_source(node.source.value, sveltePath);
return `const ${lhs} = require("${source}");`
return `const ${lhs} = require("${source}");`;
});
const exports = [`exports.default = ${name};`].concat(
@ -131,5 +131,5 @@ function cjs(
${code}
${exports}`
}
${exports}`;
}

@ -73,7 +73,7 @@ export default class Selector {
}
}
this.blocks.forEach((block, i) => {
this.blocks.forEach((block) => {
if (block.global) {
const selector = block.selectors[0];
const first = selector.children[0];
@ -238,8 +238,8 @@ function attribute_matches(node: Node, name: string, expected_value: string, ope
}
function class_matches(node, name: string) {
return node.classes.some(function(class_directive) {
return class_directive.name === name;
return node.classes.some((class_directive) => {
return new RegExp(`\\b${name}\\b`).test(class_directive.name);
});
}
@ -287,7 +287,7 @@ function group_selectors(selector: Node) {
const blocks = [block];
selector.children.forEach((child: Node, i: number) => {
selector.children.forEach((child: Node) => {
if (child.type === 'WhiteSpace' || child.type === 'Combinator') {
block = new Block(child);
blocks.push(block);

@ -43,11 +43,11 @@ class Rule {
return this.selectors.some(s => s.used);
}
minify(code: MagicString, dev: boolean) {
minify(code: MagicString, _dev: boolean) {
let c = this.node.start;
let started = false;
this.selectors.forEach((selector, i) => {
this.selectors.forEach((selector) => {
if (selector.used) {
const separator = started ? ',' : '';
if ((selector.node.start - c) > separator.length) {
@ -140,7 +140,7 @@ class Declaration {
class Atrule {
node: Node;
children: (Atrule|Rule)[];
children: Array<Atrule|Rule>;
constructor(node: Node) {
this.node = node;
@ -163,7 +163,7 @@ class Atrule {
}
}
is_used(dev: boolean) {
is_used(_dev: boolean) {
return true; // TODO
}
@ -253,7 +253,7 @@ export default class Stylesheet {
has_styles: boolean;
id: string;
children: (Rule|Atrule)[] = [];
children: Array<Rule|Atrule> = [];
keyframes: Map<string, string> = new Map();
nodes_with_css_class: Set<Node> = new Set();
@ -269,7 +269,7 @@ export default class Stylesheet {
this.has_styles = true;
const stack: (Rule | Atrule)[] = [];
const stack: Array<Rule | Atrule> = [];
let current_atrule: Atrule = null;
walk(ast.css, {

@ -3,7 +3,7 @@ import Stats from '../Stats';
import parse from '../parse/index';
import render_dom from './render-dom/index';
import render_ssr from './render-ssr/index';
import { CompileOptions, Ast, Warning } from '../interfaces';
import { CompileOptions, Warning } from '../interfaces';
import Component from './Component';
import fuzzymatch from '../utils/fuzzymatch';
@ -57,6 +57,7 @@ function validate_options(options: CompileOptions, warnings: Warning[]) {
function get_name(filename: string) {
if (!filename) return null;
// eslint-disable-next-line no-useless-escape
const parts = filename.split(/[\/\\]/);
if (parts.length > 1 && /^index\.\w+/.test(parts[parts.length - 1])) {
@ -79,12 +80,10 @@ export default function compile(source: string, options: CompileOptions = {}) {
const stats = new Stats();
const warnings = [];
let ast: Ast;
validate_options(options, warnings);
stats.start('parse');
ast = parse(source, options);
const ast = parse(source, options);
stats.stop('parse');
stats.start('create component');

@ -21,7 +21,7 @@ export default class Attribute extends Node {
is_synthetic: boolean;
should_cache: boolean;
expression?: Expression;
chunks: (Text | Expression)[];
chunks: Array<Text | Expression>;
dependencies: Set<string>;
constructor(component, parent, scope, info) {

@ -8,13 +8,13 @@ import { Node as INode } from '../../interfaces';
import { new_tail } from '../utils/tail';
import Element from './Element';
type Context = {
key: INode,
name?: string,
tail: string
};
interface Context {
key: INode;
name?: string;
tail: string;
}
function unpack_destructuring(contexts: Array<Context>, node: INode, tail: string) {
function unpack_destructuring(contexts: Context[], node: INode, tail: string) {
if (!node) return;
if (node.type === 'Identifier' || node.type === 'RestIdentifier') {
@ -25,7 +25,7 @@ function unpack_destructuring(contexts: Array<Context>, node: INode, tail: strin
} else if (node.type === 'ArrayPattern') {
node.elements.forEach((element, i) => {
if (element && element.type === 'RestIdentifier') {
unpack_destructuring(contexts, element, `${tail}.slice(${i})`)
unpack_destructuring(contexts, element, `${tail}.slice(${i})`);
} else {
unpack_destructuring(contexts, element, `${tail}[${i}]`);
}
@ -60,7 +60,7 @@ export default class EachBlock extends AbstractBlock {
context: string;
key: Expression;
scope: TemplateScope;
contexts: Array<Context>;
contexts: Context[];
has_animation: boolean;
has_binding = false;

@ -54,7 +54,7 @@ const a11y_required_content = new Set([
'h4',
'h5',
'h6'
])
]);
const invisible_elements = new Set(['meta', 'html', 'script', 'style']);
@ -180,10 +180,12 @@ export default class Element extends Node {
break;
case 'Transition':
{
const transition = new Transition(component, this, scope, node);
if (node.intro) this.intro = transition;
if (node.outro) this.outro = transition;
break;
}
case 'Animation':
this.animation = new Animation(component, this, scope, node);
@ -706,7 +708,7 @@ export default class Element extends Node {
if (class_attribute.chunks.length === 1 && class_attribute.chunks[0].type === 'Text') {
(class_attribute.chunks[0] as Text).data += ` ${class_name}`;
} else {
(<Node[]>class_attribute.chunks).push(
(class_attribute.chunks as Node[]).push(
new Text(this.component, this, this.scope, {
type: 'Text',
data: ` ${class_name}`

@ -36,6 +36,7 @@ export default class InlineComponent extends Node {
: null;
info.attributes.forEach(node => {
/* eslint-disable no-fallthrough */
switch (node.type) {
case 'Action':
component.error(node, {
@ -82,6 +83,7 @@ export default class InlineComponent extends Node {
default:
throw new Error(`Not implemented: ${node.type}`);
}
/* eslint-enable no-fallthrough */
});
if (this.lets.length > 0) {

@ -2,7 +2,7 @@ import map_children from './shared/map_children';
import AbstractBlock from './shared/AbstractBlock';
export default class PendingBlock extends AbstractBlock {
type: 'PendingBlock';
type: 'PendingBlock';
constructor(component, parent, scope, info) {
super(component, parent, scope, info);
this.children = map_children(component, parent, scope, info.children);

@ -44,8 +44,8 @@ export default class Window extends Node {
if (!~valid_bindings.indexOf(node.name)) {
const match = (
node.name === 'width' ? 'innerWidth' :
node.name === 'height' ? 'innerHeight' :
fuzzymatch(node.name, valid_bindings)
node.name === 'height' ? 'innerHeight' :
fuzzymatch(node.name, valid_bindings)
);
const message = `'${node.name}' is not a valid binding on <svelte:window>`;

@ -33,32 +33,32 @@ import Window from './Window';
// note: to write less types each of types in union below should have type defined as literal
// https://www.typescriptlang.org/docs/handbook/advanced-types.html#discriminated-unions
export type INode = Action
| Animation
| Attribute
| AwaitBlock
| Binding
| Body
| CatchBlock
| Class
| Comment
| DebugTag
| EachBlock
| Element
| ElseBlock
| EventHandler
| Fragment
| Head
| IfBlock
| InlineComponent
| Let
| MustacheTag
| Options
| PendingBlock
| RawMustacheTag
| Slot
| Tag
| Text
| ThenBlock
| Title
| Transition
| Window;
| Animation
| Attribute
| AwaitBlock
| Binding
| Body
| CatchBlock
| Class
| Comment
| DebugTag
| EachBlock
| Element
| ElseBlock
| EventHandler
| Fragment
| Head
| IfBlock
| InlineComponent
| Let
| MustacheTag
| Options
| PendingBlock
| RawMustacheTag
| Slot
| Tag
| Text
| ThenBlock
| Title
| Transition
| Window;

@ -4,10 +4,10 @@ import is_reference from 'is-reference';
import flatten_reference from '../../utils/flatten_reference';
import { create_scopes, Scope, extract_names } from '../../utils/scope';
import { Node } from '../../../interfaces';
import { globals } from '../../../utils/names';
import { globals , sanitize } from '../../../utils/names';
import deindent from '../../utils/deindent';
import Wrapper from '../../render-dom/wrappers/shared/Wrapper';
import { sanitize } from '../../../utils/names';
import TemplateScope from './TemplateScope';
import get_object from '../../utils/get_object';
import { nodes_match } from '../../../utils/nodes_match';
@ -28,8 +28,8 @@ const binary_operators: Record<string, number> = {
'<=': 11,
'>': 11,
'>=': 11,
'in': 11,
'instanceof': 11,
in: 11,
instanceof: 11,
'==': 10,
'!=': 10,
'===': 10,
@ -490,7 +490,7 @@ export default class Expression {
}
}
function get_function_name(node, parent) {
function get_function_name(_node, parent) {
if (parent.type === 'EventHandler') {
return `${parent.name}_handler`;
}

@ -17,7 +17,7 @@ export default class Node {
var: string;
attributes: Attribute[];
constructor(component: Component, parent, scope, info: any) {
constructor(component: Component, parent, _scope, info: any) {
this.start = info.start;
this.end = info.end;
this.type = info.type;

@ -9,7 +9,7 @@ export interface BlockOptions {
renderer?: Renderer;
comment?: string;
key?: string;
bindings?: Map<string, { object: string, property: string, snippet: string }>;
bindings?: Map<string, { object: string; property: string; snippet: string }>;
dependencies?: Set<string>;
}
@ -26,7 +26,7 @@ export default class Block {
dependencies: Set<string>;
bindings: Map<string, { object: string, property: string, snippet: string }>;
bindings: Map<string, { object: string; property: string; snippet: string }>;
builders: {
init: CodeBuilder;
@ -357,6 +357,7 @@ export default class Block {
`);
}
/* eslint-disable @typescript-eslint/indent,indent */
return deindent`
${this.variables.size > 0 &&
`var ${Array.from(this.variables.keys())
@ -371,9 +372,10 @@ export default class Block {
return {
${properties}
};
`.replace(/(#+)(\w*)/g, (match: string, sigil: string, name: string) => {
`.replace(/(#+)(\w*)/g, (_match: string, sigil: string, name: string) => {
return sigil === '#' ? this.alias(name) : sigil.slice(1) + name;
});
/* eslint-enable @typescript-eslint/indent,indent */
}
render_listeners(chunk: string = '') {
@ -387,7 +389,7 @@ export default class Block {
this.builders.destroy.add_line(
`#dispose${chunk}();`
)
);
} else {
this.builders.hydrate.add_block(deindent`
#dispose${chunk} = [

@ -8,7 +8,7 @@ export default class Renderer {
component: Component; // TODO Maybe Renderer shouldn't know about Component?
options: CompileOptions;
blocks: (Block | string)[] = [];
blocks: Array<Block | string> = [];
readonly: Set<string> = new Set();
meta_bindings: CodeBuilder = new CodeBuilder(); // initial values for e.g. window.innerWidth, if there's a <svelte:window> meta tag
binding_groups: string[] = [];
@ -17,7 +17,7 @@ export default class Renderer {
fragment: FragmentWrapper;
file_var: string;
locate: (c: number) => { line: number; column: number; };
locate: (c: number) => { line: number; column: number };
constructor(component: Component, options: CompileOptions) {
this.component = component;

@ -74,18 +74,20 @@ export default function dom(
const props = component.vars.filter(variable => !variable.module && variable.export_name);
const writable_props = props.filter(variable => variable.writable);
/* eslint-disable @typescript-eslint/indent,indent */
const set = (uses_props || writable_props.length > 0 || component.slots.size > 0)
? deindent`
${$$props} => {
${uses_props && component.invalidate('$$props', `$$props = @assign(@assign({}, $$props), $$new_props)`)}
${writable_props.map(prop =>
`if ('${prop.export_name}' in $$props) ${component.invalidate(prop.name, `${prop.name} = $$props.${prop.export_name}`)};`
`if ('${prop.export_name}' in $$props) ${component.invalidate(prop.name, `${prop.name} = $$props.${prop.export_name}`)};`
)}
${component.slots.size > 0 &&
`if ('$$scope' in ${$$props}) ${component.invalidate('$$scope', `$$scope = ${$$props}.$$scope`)};`}
}
`
: null;
/* eslint-enable @typescript-eslint/indent,indent */
const body = [];
@ -152,12 +154,12 @@ export default function dom(
// instrument assignments
if (component.ast.instance) {
let scope = component.instance_scope;
let map = component.instance_scope_map;
const map = component.instance_scope_map;
let pending_assignments = new Set();
walk(component.ast.instance.content, {
enter: (node, parent) => {
enter: (node) => {
if (map.has(node)) {
scope = map.get(node);
}
@ -390,7 +392,7 @@ export default function dom(
const store = component.var_lookup.get(name);
if (store && store.reassigned) {
return `${$name}, $$unsubscribe_${name} = @noop, $$subscribe_${name} = () => { $$unsubscribe_${name}(); $$unsubscribe_${name} = ${name}.subscribe($$value => { ${$name} = $$value; $$invalidate('${$name}', ${$name}); }) }`
return `${$name}, $$unsubscribe_${name} = @noop, $$subscribe_${name} = () => { $$unsubscribe_${name}(); $$unsubscribe_${name} = ${name}.subscribe($$value => { ${$name} = $$value; $$invalidate('${$name}', ${$name}); }) }`;
}
return $name;

@ -6,7 +6,7 @@ import Body from '../../nodes/Body';
export default class BodyWrapper extends Wrapper {
node: Body;
render(block: Block, parent_node: string, parent_nodes: string) {
render(block: Block, _parent_node: string, _parent_nodes: string) {
this.node.handlers.forEach(handler => {
const snippet = handler.render(block);

@ -13,13 +13,13 @@ export default class DebugTagWrapper extends Wrapper {
block: Block,
parent: Wrapper,
node: DebugTag,
strip_whitespace: boolean,
next_sibling: Wrapper
_strip_whitespace: boolean,
_next_sibling: Wrapper
) {
super(renderer, block, parent, node);
}
render(block: Block, parent_node: string, parent_nodes: string) {
render(block: Block, _parent_node: string, _parent_nodes: string) {
const { renderer } = this;
const { component } = renderer;

@ -425,7 +425,7 @@ export default class EachBlockWrapper extends Wrapper {
all_dependencies.add(dependency);
});
const outro_block = this.block.has_outros && block.get_unique_name('outro_block')
const outro_block = this.block.has_outros && block.get_unique_name('outro_block');
if (outro_block) {
block.builders.init.add_block(deindent`
function ${outro_block}(i, detaching, local) {

@ -52,7 +52,7 @@ export default class AttributeWrapper {
element.node.bindings.find(
(binding) =>
/checked|group/.test(binding.name)
)));
)));
const property_name = is_indirectly_bound_value
? '__value'
@ -70,7 +70,7 @@ export default class AttributeWrapper {
const is_legacy_input_type = element.renderer.component.compile_options.legacy && name === 'type' && this.parent.node.name === 'input';
const is_dataset = /^data-/.test(name) && !element.renderer.component.compile_options.legacy && !element.node.namespace;
const camel_case_name = is_dataset ? name.replace('data-', '').replace(/(-\w)/g, function (m) {
const camel_case_name = is_dataset ? name.replace('data-', '').replace(/(-\w)/g, (m) => {
return m[1].toUpperCase();
}) : name;
@ -219,7 +219,7 @@ export default class AttributeWrapper {
return `="${value.map(chunk => {
return chunk.type === 'Text'
? chunk.data.replace(/"/g, '\\"')
: `\${${chunk.render()}}`
: `\${${chunk.render()}}`;
})}"`;
}
}

@ -1,6 +1,5 @@
import Binding from '../../../nodes/Binding';
import ElementWrapper from '../Element';
import { dimensions } from '../../../../utils/patterns';
import get_object from '../../../utils/get_object';
import Block from '../../Block';
import Node from '../../../nodes/shared/Node';
@ -23,8 +22,8 @@ export default class BindingWrapper {
handler: {
uses_context: boolean;
mutation: string;
contextual_dependencies: Set<string>,
snippet?: string
contextual_dependencies: Set<string>;
snippet?: string;
};
snippet: string;
is_readonly: boolean;
@ -87,7 +86,7 @@ export default class BindingWrapper {
}
is_readonly_media_attribute() {
return this.node.is_readonly_media_attribute()
return this.node.is_readonly_media_attribute();
}
render(block: Block, lock: string) {
@ -95,23 +94,23 @@ export default class BindingWrapper {
const { parent } = this;
let update_conditions: string[] = this.needs_lock ? [`!${lock}`] : [];
const update_conditions: string[] = this.needs_lock ? [`!${lock}`] : [];
const dependency_array = [...this.node.expression.dependencies];
if (dependency_array.length === 1) {
update_conditions.push(`changed.${dependency_array[0]}`)
update_conditions.push(`changed.${dependency_array[0]}`);
} else if (dependency_array.length > 1) {
update_conditions.push(
`(${dependency_array.map(prop => `changed.${prop}`).join(' || ')})`
)
);
}
if (parent.node.name === 'input') {
const type = parent.node.get_static_attribute_value('type');
if (type === null || type === "" || type === "text") {
update_conditions.push(`(${parent.var}.${this.node.name} !== ${this.snippet})`)
update_conditions.push(`(${parent.var}.${this.node.name} !== ${this.snippet})`);
}
}
@ -121,6 +120,7 @@ export default class BindingWrapper {
// special cases
switch (this.node.name) {
case 'group':
{
const binding_group = get_binding_group(parent.renderer, this.node.expression.node);
block.builders.hydrate.add_line(
@ -131,6 +131,7 @@ export default class BindingWrapper {
`ctx.$$binding_groups[${binding_group}].splice(ctx.$$binding_groups[${binding_group}].indexOf(${parent.var}), 1);`
);
break;
}
case 'currentTime':
case 'playbackRate':
@ -139,6 +140,7 @@ export default class BindingWrapper {
break;
case 'paused':
{
// this is necessary to prevent audio restarting by itself
const last = block.get_unique_name(`${parent.var}_is_paused`);
block.add_variable(last, 'true');
@ -146,6 +148,7 @@ export default class BindingWrapper {
update_conditions.push(`${last} !== (${last} = ${this.snippet})`);
update_dom = `${parent.var}[${last} ? "pause" : "play"]();`;
break;
}
case 'value':
if (parent.node.get_static_attribute_value('type') === 'file') {
@ -192,7 +195,7 @@ function get_dom_updater(
? `~${binding.snippet}.indexOf(${element.var}.__value)`
: `${element.var}.__value === ${binding.snippet}`;
return `${element.var}.checked = ${condition};`
return `${element.var}.checked = ${condition};`;
}
if (binding.node.name === 'text') {
@ -312,7 +315,7 @@ function get_value_from_dom(
}
if ((name === 'buffered' || name === 'seekable' || name === 'played')) {
return `@time_ranges_to_array(this.${name})`
return `@time_ranges_to_array(this.${name})`;
}
if (name === 'text') {

@ -9,7 +9,7 @@ import Text from '../../../nodes/Text';
export interface StyleProp {
key: string;
value: (Text|Expression)[];
value: Array<Text|Expression>;
}
export default class StyleAttributeWrapper extends AttributeWrapper {
@ -65,7 +65,7 @@ export default class StyleAttributeWrapper extends AttributeWrapper {
}
}
function optimize_style(value: (Text|Expression)[]) {
function optimize_style(value: Array<Text|Expression>) {
const props: StyleProp[] = [];
let chunks = value.slice();
@ -83,12 +83,14 @@ function optimize_style(value: (Text|Expression)[]) {
const remaining_data = chunk.data.slice(offset);
if (remaining_data) {
/* eslint-disable @typescript-eslint/no-object-literal-type-assertion */
chunks[0] = {
start: chunk.start + offset,
end: chunk.end,
type: 'Text',
data: remaining_data
} as Text;
/* eslint-enable @typescript-eslint/no-object-literal-type-assertion */
} else {
chunks.shift();
}
@ -102,8 +104,8 @@ function optimize_style(value: (Text|Expression)[]) {
return props;
}
function get_style_value(chunks: (Text | Expression)[]) {
const value: (Text|Expression)[] = [];
function get_style_value(chunks: Array<Text | Expression>) {
const value: Array<Text|Expression> = [];
let in_url = false;
let quote_mark = null;
@ -171,6 +173,6 @@ function get_style_value(chunks: (Text | Expression)[]) {
};
}
function is_dynamic(value: (Text|Expression)[]) {
function is_dynamic(value: Array<Text|Expression>) {
return value.length > 1 || value[0].type !== 'Text';
}

@ -2,7 +2,6 @@ import Renderer from '../../Renderer';
import Element from '../../../nodes/Element';
import Wrapper from '../shared/Wrapper';
import Block from '../../Block';
import Node from '../../../nodes/shared/Node';
import { is_void, quote_prop_if_necessary, quote_name_if_necessary, sanitize } from '../../../../utils/names';
import FragmentWrapper from '../Fragment';
import { stringify, escape_html, escape } from '../../../utils/stringify';
@ -24,7 +23,7 @@ import { get_context_merger } from '../shared/get_context_merger';
const events = [
{
event_names: ['input'],
filter: (node: Element, name: string) =>
filter: (node: Element, _name: string) =>
node.name === 'textarea' ||
node.name === 'input' && !/radio|checkbox|range/.test(node.get_static_attribute_value('type') as string)
},
@ -36,19 +35,19 @@ const events = [
},
{
event_names: ['change'],
filter: (node: Element, name: string) =>
filter: (node: Element, _name: string) =>
node.name === 'select' ||
node.name === 'input' && /radio|checkbox/.test(node.get_static_attribute_value('type') as string)
},
{
event_names: ['change', 'input'],
filter: (node: Element, name: string) =>
filter: (node: Element, _name: string) =>
node.name === 'input' && node.get_static_attribute_value('type') === 'range'
},
{
event_names: ['resize'],
filter: (node: Element, name: string) =>
filter: (_node: Element, name: string) =>
dimensions.test(name)
},
@ -99,7 +98,7 @@ const events = [
// details event
{
event_names: ['toggle'],
filter: (node: Element, name: string) =>
filter: (node: Element, _name: string) =>
node.name === 'details'
},
];
@ -125,7 +124,7 @@ export default class ElementWrapper extends Wrapper {
next_sibling: Wrapper
) {
super(renderer, block, parent, node);
this.var = node.name.replace(/[^a-zA-Z0-9_$]/g, '_')
this.var = node.name.replace(/[^a-zA-Z0-9_$]/g, '_');
this.class_dependencies = [];
@ -245,7 +244,7 @@ export default class ElementWrapper extends Wrapper {
}
const node = this.var;
const nodes = parent_nodes && block.get_unique_name(`${this.var}_nodes`) // if we're in unclaimable territory, i.e. <head>, parent_nodes is null
const nodes = parent_nodes && block.get_unique_name(`${this.var}_nodes`); // if we're in unclaimable territory, i.e. <head>, parent_nodes is null
block.add_variable(node);
const render_statement = this.get_render_statement();
@ -356,7 +355,7 @@ export default class ElementWrapper extends Wrapper {
let open = `<${wrapper.node.name}`;
(wrapper as ElementWrapper).attributes.forEach((attr: AttributeWrapper) => {
open += ` ${fix_attribute_casing(attr.node.name)}${attr.stringify()}`
open += ` ${fix_attribute_casing(attr.node.name)}${attr.stringify()}`;
});
if (is_void(wrapper.node.name)) return open + '>';
@ -769,6 +768,7 @@ export default class ElementWrapper extends Wrapper {
if (!this.node.animation) return;
const { component } = this.renderer;
const { outro } = this.node;
const rect = block.get_unique_name('rect');
const stop_animation = block.get_unique_name('stop_animation');
@ -783,6 +783,7 @@ export default class ElementWrapper extends Wrapper {
block.builders.fix.add_block(deindent`
@fix_position(${this.var});
${stop_animation}();
${outro && `@add_transform(${this.var}, ${rect});`}
`);
const params = this.node.animation.expression ? this.node.animation.expression.render(block) : '{}';
@ -802,7 +803,8 @@ export default class ElementWrapper extends Wrapper {
add_classes(block: Block) {
this.node.classes.forEach(class_directive => {
const { expression, name } = class_directive;
let snippet, dependencies;
let snippet;
let dependencies;
if (expression) {
snippet = expression.render(block);
dependencies = expression.dependencies;

@ -14,7 +14,6 @@ import Text from './Text';
import Title from './Title';
import Window from './Window';
import { INode } from '../../nodes/interfaces';
import TextWrapper from './Text';
import Renderer from '../Renderer';
import Block from '../Block';
import { trim_start, trim_end } from '../../../utils/trim';
@ -64,7 +63,7 @@ export default class FragmentWrapper {
const child = nodes[i];
if (!child.type) {
throw new Error(`missing type`)
throw new Error(`missing type`);
}
if (!(child.type in wrappers)) {
@ -102,7 +101,7 @@ export default class FragmentWrapper {
continue;
}
const wrapper = new TextWrapper(renderer, block, parent, child, data);
const wrapper = new Text(renderer, block, parent, child, data);
if (wrapper.skip) continue;
this.nodes.unshift(wrapper);
@ -120,7 +119,7 @@ export default class FragmentWrapper {
}
if (strip_whitespace) {
const first = this.nodes[0] as TextWrapper;
const first = this.nodes[0] as Text;
if (first && first.node.type === 'Text') {
first.data = trim_start(first.data);

@ -29,7 +29,7 @@ export default class HeadWrapper extends Wrapper {
);
}
render(block: Block, parent_node: string, parent_nodes: string) {
render(block: Block, _parent_node: string, _parent_nodes: string) {
this.fragment.render(block, 'document.head', 'nodes');
}
}

@ -201,7 +201,7 @@ export default class IfBlockWrapper extends Wrapper {
render_compound(
block: Block,
parent_node: string,
parent_nodes: string,
_parent_nodes: string,
dynamic,
{ name, anchor, has_else, if_name, has_transitions },
detaching
@ -210,6 +210,7 @@ export default class IfBlockWrapper extends Wrapper {
const current_block_type = block.get_unique_name(`current_block_type`);
const current_block_type_and = has_else ? '' : `${current_block_type} && `;
/* eslint-disable @typescript-eslint/indent,indent */
block.builders.init.add_block(deindent`
function ${select_block_type}(ctx) {
${this.branches
@ -217,6 +218,7 @@ export default class IfBlockWrapper extends Wrapper {
.join('\n')}
}
`);
/* eslint-enable @typescript-eslint/indent,indent */
block.builders.init.add_block(deindent`
var ${current_block_type} = ${select_block_type}(ctx);
@ -265,7 +267,7 @@ export default class IfBlockWrapper extends Wrapper {
render_compound_with_outros(
block: Block,
parent_node: string,
parent_nodes: string,
_parent_nodes: string,
dynamic,
{ name, anchor, has_else, has_transitions },
detaching
@ -283,6 +285,7 @@ export default class IfBlockWrapper extends Wrapper {
block.add_variable(current_block_type_index);
block.add_variable(name);
/* eslint-disable @typescript-eslint/indent,indent */
block.builders.init.add_block(deindent`
var ${if_block_creators} = [
${this.branches.map(branch => branch.block.name).join(',\n')}
@ -297,6 +300,7 @@ export default class IfBlockWrapper extends Wrapper {
${!has_else && `return -1;`}
}
`);
/* eslint-enable @typescript-eslint/indent,indent */
if (has_else) {
block.builders.init.add_block(deindent`
@ -386,7 +390,7 @@ export default class IfBlockWrapper extends Wrapper {
render_simple(
block: Block,
parent_node: string,
parent_nodes: string,
_parent_nodes: string,
dynamic,
{ name, anchor, if_name, has_transitions },
detaching

@ -17,7 +17,7 @@ import TemplateScope from '../../../nodes/shared/TemplateScope';
export default class InlineComponentWrapper extends Wrapper {
var: string;
slots: Map<string, { block: Block, scope: TemplateScope, fn?: string }> = new Map();
slots: Map<string, { block: Block; scope: TemplateScope; fn?: string }> = new Map();
node: InlineComponent;
fragment: FragmentWrapper;
@ -62,8 +62,8 @@ export default class InlineComponentWrapper extends Wrapper {
this.var = (
this.node.name === 'svelte:self' ? renderer.component.name :
this.node.name === 'svelte:component' ? 'switch_instance' :
sanitize(this.node.name)
this.node.name === 'svelte:component' ? 'switch_instance' :
sanitize(this.node.name)
).toLowerCase();
if (this.node.children.length) {
@ -232,14 +232,16 @@ export default class InlineComponentWrapper extends Wrapper {
.filter((attribute: Attribute) => attribute.is_dynamic)
.forEach((attribute: Attribute) => {
if (attribute.dependencies.size > 0) {
/* eslint-disable @typescript-eslint/indent,indent */
updates.push(deindent`
if (${[...attribute.dependencies]
.map(dependency => `changed.${dependency}`)
.join(' || ')}) ${name_changes}${quote_prop_if_necessary(attribute.name)} = ${attribute.get_value(block)};
`);
/* eslint-enable @typescript-eslint/indent,indent */
}
});
}
}
}
if (non_let_dependencies.length > 0) {
@ -265,7 +267,7 @@ export default class InlineComponentWrapper extends Wrapper {
// bind:x={y} — we can't just do `y = x`, we need to
// to `array[index] = x;
const { name } = binding.expression.node;
const { object, property, snippet } = block.bindings.get(name);
const { snippet } = block.bindings.get(name);
lhs = snippet;
// TODO we need to invalidate... something

@ -78,7 +78,7 @@ export default class SlotWrapper extends Wrapper {
});
if (attribute.dependencies.size > 0) {
changes_props.push(`${attribute.name}: ${[...attribute.dependencies].join(' || ')}`)
changes_props.push(`${attribute.name}: ${[...attribute.dependencies].join(' || ')}`);
}
});
@ -101,7 +101,7 @@ export default class SlotWrapper extends Wrapper {
const ${slot} = @create_slot(${slot_definition}, ctx, ${get_slot_context});
`);
let mount_before = block.builders.mount.toString();
const mount_before = block.builders.mount.toString();
block.builders.create.push_condition(`!${slot}`);
block.builders.claim.push_condition(`!${slot}`);

@ -14,13 +14,13 @@ export default class TitleWrapper extends Wrapper {
block: Block,
parent: Wrapper,
node: Title,
strip_whitespace: boolean,
next_sibling: Wrapper
_strip_whitespace: boolean,
_next_sibling: Wrapper
) {
super(renderer, block, parent, node);
}
render(block: Block, parent_node: string, parent_nodes: string) {
render(block: Block, _parent_node: string, _parent_nodes: string) {
const is_dynamic = !!this.node.children.find(node => node.type !== 'Text');
if (is_dynamic) {
@ -65,13 +65,12 @@ export default class TitleWrapper extends Wrapper {
if (this.node.should_cache) block.add_variable(last);
let updater;
const init = this.node.should_cache ? `${last} = ${value}` : value;
block.builders.init.add_line(
`document.title = ${init};`
);
updater = `document.title = ${this.node.should_cache ? last : value};`;
const updater = `document.title = ${this.node.should_cache ? last : value};`;
if (all_dependencies.size) {
const dependencies = Array.from(all_dependencies);

@ -1,6 +1,5 @@
import Renderer from '../Renderer';
import Block from '../Block';
import Node from '../../nodes/shared/Node';
import Wrapper from './shared/Wrapper';
import deindent from '../../utils/deindent';
import add_event_handlers from './shared/add_event_handlers';
@ -38,7 +37,7 @@ export default class WindowWrapper extends Wrapper {
super(renderer, block, parent, node);
}
render(block: Block, parent_node: string, parent_nodes: string) {
render(block: Block, _parent_node: string, _parent_nodes: string) {
const { renderer } = this;
const { component } = renderer;
@ -88,7 +87,7 @@ export default class WindowWrapper extends Wrapper {
bindings.scrollY && `"${bindings.scrollY}" in this._state`
].filter(Boolean).join(' || ');
const x = bindings.scrollX && `this._state.${bindings.scrollX}`;
const x = bindings.scrollX && `this._state.${bindings.scrollX}`;
const y = bindings.scrollY && `this._state.${bindings.scrollY}`;
renderer.meta_bindings.add_block(deindent`

@ -76,7 +76,7 @@ export default class Wrapper {
);
}
render(block: Block, parent_node: string, parent_nodes: string){
render(_block: Block, _parent_node: string, _parent_nodes: string) {
throw Error('Wrapper class is not renderable');
}
}

@ -10,7 +10,8 @@ export default function add_actions(
) {
actions.forEach(action => {
const { expression } = action;
let snippet, dependencies;
let snippet;
let dependencies;
if (expression) {
snippet = expression.render(block);
@ -44,4 +45,4 @@ export default function add_actions(
`if (${name} && typeof ${name}.destroy === 'function') ${name}.destroy();`
);
});
}
}

@ -16,7 +16,7 @@ import { INode } from '../nodes/interfaces';
type Handler = (node: any, renderer: Renderer, options: CompileOptions) => void;
function noop(){}
function noop() {}
const handlers: Record<string, Handler> = {
AwaitBlock,
@ -38,8 +38,8 @@ const handlers: Record<string, Handler> = {
};
export interface RenderOptions extends CompileOptions{
locate: (c: number) => { line: number; column: number; };
};
locate: (c: number) => { line: number; column: number };
}
export default class Renderer {
has_bindings = false;

@ -9,7 +9,7 @@ export default function(node: EachBlock, renderer: Renderer, options: RenderOpti
const ctx = node.index
? `([✂${start}-${end}✂], ${node.index})`
: `([✂${start}-${end}✂])`
: `([✂${start}-${end}✂])`;
const open = `\${${node.else ? `${snippet}.length ? ` : ''}@each(${snippet}, ${ctx} => \``;
renderer.append(open);

@ -1,7 +1,6 @@
import { is_void, quote_prop_if_necessary, quote_name_if_necessary } from '../../../utils/names';
import Attribute from '../../nodes/Attribute';
import Class from '../../nodes/Class';
import Node from '../../nodes/shared/Node';
import { snip } from '../../utils/snip';
import { stringify_attribute } from '../../utils/stringify_attribute';
import { get_slot_scope } from './shared/get_slot_scope';
@ -159,6 +158,9 @@ export default function(node: Element, renderer: Renderer, options: RenderOption
// Do not escape HTML content
node_contents = '${' + snippet + '}'
}
} else if (binding.name === 'value' && node.name === 'textarea') {
const snippet = snip(expression);
node_contents='${(' + snippet + ') || ""}';
} else {
const snippet = snip(expression);
opening_tag += ' ${(v => v ? ("' + name + '" + (v === true ? "" : "=" + JSON.stringify(v))) : "")(' + snippet + ')}';

@ -2,6 +2,6 @@ import { snip } from '../../utils/snip';
import Renderer, { RenderOptions } from '../Renderer';
import RawMustacheTag from '../../nodes/RawMustacheTag';
export default function(node: RawMustacheTag, renderer: Renderer, options: RenderOptions) {
export default function(node: RawMustacheTag, renderer: Renderer, _options: RenderOptions) {
renderer.append('${' + snip(node.expression) + '}');
}

@ -1,6 +1,6 @@
import { snip } from '../../utils/snip';
import Renderer, { RenderOptions } from '../Renderer';
export default function(node, renderer: Renderer, options: RenderOptions) {
export default function(node, renderer: Renderer, _options: RenderOptions) {
const snippet = snip(node.expression);
renderer.append(

@ -3,7 +3,7 @@ import Renderer, { RenderOptions } from '../Renderer';
import Text from '../../nodes/Text';
import Element from '../../nodes/Element';
export default function(node: Text, renderer: Renderer, options: RenderOptions) {
export default function(node: Text, renderer: Renderer, _options: RenderOptions) {
let text = node.data;
if (
!node.parent ||

@ -1,4 +1,4 @@
export default function add_to_set<T>(a: Set<T>, b: Set<T> | Array<T>) {
export default function add_to_set<T>(a: Set<T>, b: Set<T> | T[]) {
// @ts-ignore
b.forEach(item => {
a.add(item);

@ -50,10 +50,10 @@ export function create_scopes(expression: Node) {
if (map.has(node)) {
scope = scope.parent;
}
},
}
});
scope.declarations.forEach((node, name) => {
scope.declarations.forEach((_node, name) => {
globals.delete(name);
});

@ -7,33 +7,33 @@ interface BaseNode {
}
export interface Text extends BaseNode {
type: 'Text',
type: 'Text';
data: string;
}
export interface MustacheTag extends BaseNode {
type: 'MustacheTag',
type: 'MustacheTag';
expression: Node;
}
export type DirectiveType = 'Action'
| 'Animation'
| 'Binding'
| 'Class'
| 'EventHandler'
| 'Let'
| 'Ref'
| 'Transition';
| 'Animation'
| 'Binding'
| 'Class'
| 'EventHandler'
| 'Let'
| 'Ref'
| 'Transition';
interface BaseDirective extends BaseNode {
type: DirectiveType;
expression: null|Node;
name: string;
modifiers: string[]
modifiers: string[];
}
export interface Transition extends BaseDirective{
type: 'Transition',
type: 'Transition';
intro: boolean;
outro: boolean;
}
@ -41,17 +41,17 @@ export interface Transition extends BaseDirective{
export type Directive = BaseDirective | Transition;
export type Node = Text
| MustacheTag
| BaseNode
| Directive
| Transition;
| MustacheTag
| BaseNode
| Directive
| Transition;
export interface Parser {
readonly template: string;
readonly filename?: string;
index: number;
stack: Array<Node>;
stack: Node[];
html: Node;
css: Node;
@ -68,7 +68,7 @@ export interface Ast {
export interface Warning {
start?: { line: number; column: number; pos?: number };
end?: { line: number; column: number; };
end?: { line: number; column: number };
pos?: number;
code: string;
message: string;
@ -114,7 +114,7 @@ export interface Visitor {
export interface AppendTarget {
slots: Record<string, string>;
slot_stack: string[]
slot_stack: string[];
}
export interface Var {

@ -14,7 +14,7 @@ export class Parser {
readonly customElement: boolean;
index = 0;
stack: Array<Node> = [];
stack: Node[] = [];
html: Node;
css: Node[] = [];
@ -89,7 +89,7 @@ export class Parser {
}, err.pos);
}
error({ code, message }: { code: string, message: string }, index = this.index) {
error({ code, message }: { code: string; message: string }, index = this.index) {
error(message, {
name: 'ParseError',
code,

@ -1,13 +1,13 @@
import { Parser } from '../index';
type Identifier = {
interface Identifier {
start: number;
end: number;
type: 'Identifier';
name: string;
};
}
type Property = {
interface Property {
start: number;
end: number;
type: 'Property';
@ -15,9 +15,9 @@ type Property = {
shorthand: boolean;
key: Identifier;
value: Context;
};
}
type Context = {
interface Context {
start: number;
end: number;
type: 'Identifier' | 'ArrayPattern' | 'ObjectPattern' | 'RestIdentifier';
@ -91,7 +91,7 @@ export default function read_context(parser: Parser) {
end: parser.index,
type: 'Identifier',
name
}
};
const property: Property = {
start,
end: parser.index,
@ -100,7 +100,7 @@ export default function read_context(parser: Parser) {
shorthand: true,
key,
value: key
}
};
context.properties.push(property);

@ -12,6 +12,7 @@ export default function read_expression(parser: Parser): Node {
const end = start + name.length;
if (literals.has(name)) {
// eslint-disable-next-line @typescript-eslint/no-object-literal-type-assertion
return {
type: 'Literal',
start,
@ -21,6 +22,7 @@ export default function read_expression(parser: Parser): Node {
} as SimpleLiteral;
}
// eslint-disable-next-line @typescript-eslint/no-object-literal-type-assertion
return {
type: 'Identifier',
start,

@ -295,7 +295,7 @@ export default function mustache(parser: Parser) {
}
}
let await_block_shorthand = type === 'AwaitBlock' && parser.eat('then');
const await_block_shorthand = type === 'AwaitBlock' && parser.eat('then');
if (await_block_shorthand) {
parser.require_whitespace();
block.value = parser.read_identifier();

@ -8,6 +8,7 @@ import { Directive, DirectiveType, Node, Text } from '../../interfaces';
import fuzzymatch from '../../utils/fuzzymatch';
import list from '../../utils/list';
// eslint-disable-next-line no-useless-escape
const valid_tag_name = /^\!?[a-zA-Z]{1,}:?[a-zA-Z0-9\-]*/;
const meta_tags = new Map([
@ -36,7 +37,9 @@ const specials = new Map([
],
]);
// eslint-disable-next-line no-useless-escape
const SELF = /^svelte:self(?=[\s\/>])/;
// eslint-disable-next-line no-useless-escape
const COMPONENT = /^svelte:component(?=[\s\/>])/;
// based on http://developers.whatwg.org/syntax.html#syntax-tag-omission
@ -358,7 +361,8 @@ function read_attribute(parser: Parser, unique_names: Set<string>) {
}
}
let name = parser.read_until(/[\s=\/>"']/);
// eslint-disable-next-line no-useless-escape
const name = parser.read_until(/[\s=\/>"']/);
if (!name) return null;
let end = parser.index;
@ -401,7 +405,7 @@ function read_attribute(parser: Parser, unique_names: Set<string>) {
}
if (value[0]) {
if ((value as Array<any>).length > 1 || value[0].type === 'Text') {
if ((value as any[]).length > 1 || value[0].type === 'Text') {
parser.error({
code: `invalid-directive-value`,
message: `Directive value must be a JavaScript expression enclosed in curly braces`
@ -445,7 +449,7 @@ function read_attribute(parser: Parser, unique_names: Set<string>) {
};
}
function get_directive_type(name: string):DirectiveType {
function get_directive_type(name: string): DirectiveType {
if (name === 'use') return 'Action';
if (name === 'animate') return 'Animation';
if (name === 'bind') return 'Binding';

@ -14,7 +14,7 @@ export default function text(parser: Parser) {
data += parser.template[parser.index++];
}
let node = {
const node = {
start,
end: parser.index,
type: 'Text',

@ -2,18 +2,18 @@ import { SourceMap } from 'magic-string';
export interface PreprocessorGroup {
markup?: (options: {
content: string,
filename: string
}) => { code: string, map?: SourceMap | string, dependencies?: string[] };
content: string;
filename: string;
}) => { code: string; map?: SourceMap | string; dependencies?: string[] };
style?: Preprocessor;
script?: Preprocessor;
}
export type Preprocessor = (options: {
content: string,
attributes: Record<string, string | boolean>,
filename?: string
}) => { code: string, map?: SourceMap | string, dependencies?: string[] };
content: string;
attributes: Record<string, string | boolean>;
filename?: string;
}) => { code: string; map?: SourceMap | string; dependencies?: string[] };
interface Processed {
code: string;
@ -43,16 +43,16 @@ interface Replacement {
}
async function replace_async(str: string, re: RegExp, func: (...any) => Promise<string>) {
const replacements: Promise<Replacement>[] = [];
const replacements: Array<Promise<Replacement>> = [];
str.replace(re, (...args) => {
replacements.push(
func(...args).then(
res =>
<Replacement>({
res => // eslint-disable-next-line @typescript-eslint/no-object-literal-type-assertion
({
offset: args[args.length - 2],
length: args[0].length,
replacement: res,
})
}) as Replacement
)
);
return '';

@ -3,8 +3,8 @@ import get_code_frame from './get_code_frame';
class CompileError extends Error {
code: string;
start: { line: number, column: number };
end: { line: number, column: number };
start: { line: number; column: number };
end: { line: number; column: number };
pos: number;
filename: string;
frame: string;
@ -15,12 +15,12 @@ class CompileError extends Error {
}
export default function error(message: string, props: {
name: string,
code: string,
source: string,
filename: string,
start: number,
end?: number
name: string;
code: string;
source: string;
filename: string;
start: number;
end?: number;
}) {
const error = new CompileError(message);
error.name = props.name;

@ -2,9 +2,9 @@
// Reproduced under MIT License https://github.com/acornjs/acorn/blob/master/LICENSE
export default function full_char_code_at(str: string, i: number): number {
let code = str.charCodeAt(i)
const code = str.charCodeAt(i);
if (code <= 0xd7ff || code >= 0xe000) return code;
let next = str.charCodeAt(i + 1);
const next = str.charCodeAt(i + 1);
return (code << 10) + next - 0x35fdc00;
}

@ -144,7 +144,7 @@ class FuzzySet {
items[index] = [vector_normal, normalized_value];
this.items[gram_size] = items;
this.exact_set[normalized_value] = value;
};
}
get(value: string) {
const normalized_value = value.toLowerCase();
@ -232,5 +232,5 @@ class FuzzySet {
}
return new_results;
};
}
}
}

@ -3,20 +3,20 @@ import { is_function } from 'svelte/internal';
// todo: same as Transition, should it be shared?
export interface AnimationConfig {
delay?: number,
duration?: number,
easing?: (t: number) => number,
css?: (t: number, u: number) => string,
tick?: (t: number, u: number) => void
delay?: number;
duration?: number;
easing?: (t: number) => number;
css?: (t: number, u: number) => string;
tick?: (t: number, u: number) => void;
}
interface FlipParams {
delay: number;
duration: number | ((len: number) => number);
easing: (t: number) => number,
easing: (t: number) => number;
}
export function flip(node: Element, animation: { from: DOMRect, to: DOMRect }, params: FlipParams): AnimationConfig {
export function flip(node: Element, animation: { from: DOMRect; to: DOMRect }, params: FlipParams): AnimationConfig {
const style = getComputedStyle(node);
const transform = style.transform === 'none' ? '' : style.transform;
@ -35,6 +35,6 @@ export function flip(node: Element, animation: { from: DOMRect, to: DOMRect }, p
delay,
duration: is_function(duration) ? duration(d) : duration,
easing,
css: (t, u) => `transform: ${transform} translate(${u * dx}px, ${u * dy}px);`
css: (_t, u) => `transform: ${transform} translate(${u * dx}px, ${u * dy}px);`
};
}

@ -3,6 +3,7 @@ import { current_component, set_current_component } from './lifecycle';
import { blank_object, is_function, run, run_all, noop } from './utils';
import { children } from './dom';
// eslint-disable-next-line @typescript-eslint/class-name-casing
interface T$$ {
dirty: null;
ctx: null|any;
@ -16,7 +17,7 @@ interface T$$ {
before_render: any[];
context: Map<any, any>;
on_mount: any[];
on_destroy: any[]
on_destroy: any[];
}
export function bind(component, name, callback) {
@ -115,8 +116,10 @@ export function init(component, options, instance, create_fragment, not_equal, p
if (options.target) {
if (options.hydrate) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
$$.fragment!.l(children(options.target));
} else {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
$$.fragment!.c();
}
@ -145,7 +148,7 @@ if (typeof HTMLElement !== 'undefined') {
}
}
attributeChangedCallback(attr, oldValue, newValue) {
attributeChangedCallback(attr, _oldValue, newValue) {
this[attr] = newValue;
}

@ -7,7 +7,7 @@ import { AnimationConfig } from '../animate';
//todo: documentation says it is DOMRect, but in IE it would be ClientRect
type PositionRect = DOMRect|ClientRect;
type AnimationFn = (node: Element, { from, to }: { from: PositionRect, to: PositionRect }, params: any) => AnimationConfig;
type AnimationFn = (node: Element, { from, to }: { from: PositionRect; to: PositionRect }, params: any) => AnimationConfig;
export function create_animation(node: Element & ElementCSSInlineStyle, from: PositionRect, fn: AnimationFn, params) {
if (!from) return noop;
@ -86,13 +86,17 @@ export function fix_position(node: Element & ElementCSSInlineStyle) {
node.style.position = 'absolute';
node.style.width = width;
node.style.height = height;
const b = node.getBoundingClientRect();
add_transform(node, a);
}
}
if (a.left !== b.left || a.top !== b.top) {
const style = getComputedStyle(node);
const transform = style.transform === 'none' ? '' : style.transform;
export function add_transform(node: Element & ElementCSSInlineStyle, a: PositionRect) {
const b = node.getBoundingClientRect();
node.style.transform = `${transform} translate(${a.left - b.left}px, ${a.top - b.top}px)`;
}
if (a.left !== b.left || a.top !== b.top) {
const style = getComputedStyle(node);
const transform = style.transform === 'none' ? '' : style.transform;
node.style.transform = `${transform} translate(${a.left - b.left}px, ${a.top - b.top}px)`;
}
}

@ -1,8 +1,8 @@
export function append(target:Node, node:Node) {
export function append(target: Node, node: Node) {
target.appendChild(node);
}
export function insert(target: Node, node: Node, anchor?:Node) {
export function insert(target: Node, node: Node, anchor?: Node) {
target.insertBefore(node, anchor || null);
}
@ -16,13 +16,13 @@ export function detach_between(before: Node, after: Node) {
}
}
export function detach_before(after:Node) {
export function detach_before(after: Node) {
while (after.previousSibling) {
after.parentNode.removeChild(after.previousSibling);
}
}
export function detach_after(before:Node) {
export function detach_after(before: Node) {
while (before.nextSibling) {
before.parentNode.removeChild(before.nextSibling);
}
@ -38,7 +38,8 @@ export function element<K extends keyof HTMLElementTagNameMap>(name: K) {
return document.createElement<K>(name);
}
export function object_without_properties<T,K extends keyof T>(obj:T, exclude: K[]) {
export function object_without_properties<T, K extends keyof T>(obj: T, exclude: K[]) {
// eslint-disable-next-line @typescript-eslint/no-object-literal-type-assertion
const target = {} as Pick<T, Exclude<keyof T, K>>;
for (const k in obj) {
if (
@ -53,11 +54,11 @@ export function object_without_properties<T,K extends keyof T>(obj:T, exclude: K
return target;
}
export function svg_element<K extends keyof SVGElementTagNameMap>(name:K):SVGElement {
export function svg_element<K extends keyof SVGElementTagNameMap>(name: K): SVGElement {
return document.createElementNS<K>('http://www.w3.org/2000/svg', name);
}
export function text(data:string) {
export function text(data: string) {
return document.createTextNode(data);
}
@ -95,7 +96,7 @@ export function attr(node: Element, attribute: string, value?: string) {
else node.setAttribute(attribute, value);
}
export function set_attributes(node: Element & ElementCSSInlineStyle, attributes: { [x: string]: string; }) {
export function set_attributes(node: Element & ElementCSSInlineStyle, attributes: { [x: string]: string }) {
for (const key in attributes) {
if (key === 'style') {
node.style.cssText = attributes[key];

@ -23,7 +23,7 @@ export function clear_loops() {
running = false;
}
export function loop(fn: (number)=>void): Task {
export function loop(fn: (number) => void): Task {
let task;
if (!running) {

@ -71,14 +71,14 @@ export function create_in_transition(node: Element & ElementCSSInlineStyle, fn:
if (task) task.abort();
running = true;
add_render_callback(() => dispatch(node, true, 'start'));
add_render_callback(() => dispatch(node, true, 'start'));
task = loop(now => {
if (running) {
if (now >= end_time) {
tick(1, 0);
dispatch(node, true, 'end');
dispatch(node, true, 'end');
cleanup();
return running = false;
@ -146,14 +146,14 @@ export function create_out_transition(node: Element & ElementCSSInlineStyle, fn:
const start_time = now() + delay;
const end_time = start_time + duration;
add_render_callback(() => dispatch(node, false, 'start'));
add_render_callback(() => dispatch(node, false, 'start'));
loop(now => {
if (running) {
if (now >= end_time) {
tick(0, 1);
dispatch(node, false, 'end');
dispatch(node, false, 'end');
if (!--group.remaining) {
// this will result in `end()` being called,

@ -2,7 +2,7 @@ export function noop() {}
export const identity = x => x;
export function assign<T, S>(tar:T, src:S): T & S {
export function assign<T, S>(tar: T, src: S): T & S {
// @ts-ignore
for (const k in src) tar[k] = src[k];
return tar as T & S;

@ -6,10 +6,10 @@ interface TickContext<T> {
inv_mass: number;
dt: number;
opts: Spring<T>;
settled: boolean
settled: boolean;
}
function tick_spring<T>(ctx: TickContext<T>, last_value: T, current_value: T, target_value: T):T {
function tick_spring<T>(ctx: TickContext<T>, last_value: T, current_value: T, target_value: T): T {
if (typeof current_value === 'number' || is_date(current_value)) {
// @ts-ignore
const delta = target_value - current_value;
@ -45,9 +45,9 @@ function tick_spring<T>(ctx: TickContext<T>, last_value: T, current_value: T, ta
}
interface SpringOpts {
stiffness?: number,
damping?: number,
precision?: number,
stiffness?: number;
damping?: number;
precision?: number;
}
interface SpringUpdateOpts {
@ -62,7 +62,7 @@ interface Spring<T> extends Readable<T>{
update: (fn: Updater<T>, opts?: SpringUpdateOpts) => Promise<void>;
precision: number;
damping: number;
stiffness: number
stiffness: number;
}
export function spring<T=any>(value: T, opts: SpringOpts = {}): Spring<T> {
@ -72,13 +72,14 @@ export function spring<T=any>(value: T, opts: SpringOpts = {}): Spring<T> {
let last_time: number;
let task: Task;
let current_token: object;
let last_value:T = value;
let target_value:T = value;
let last_value: T = value;
let target_value: T = value;
let inv_mass = 1;
let inv_mass_recovery_rate = 0;
let cancel_task = false;
/* eslint-disable @typescript-eslint/no-use-before-define */
function set(new_value: T, opts: SpringUpdateOpts={}): Promise<void> {
target_value = new_value;
const token = current_token = {};
@ -133,15 +134,16 @@ export function spring<T=any>(value: T, opts: SpringOpts = {}): Spring<T> {
});
});
}
/* eslint-enable @typescript-eslint/no-use-before-define */
const spring = {
const spring: Spring<T> = {
set,
update: (fn, opts:SpringUpdateOpts) => set(fn(target_value, value), opts),
update: (fn, opts: SpringUpdateOpts) => set(fn(target_value, value), opts),
subscribe: store.subscribe,
stiffness,
damping,
precision
} as Spring<T>;
};
return spring;
}

@ -56,9 +56,9 @@ function get_interpolator(a, b) {
interface Options<T> {
delay?: number;
duration?: number | ((from: T, to: T) => number)
duration?: number | ((from: T, to: T) => number);
easing?: (t: number) => number;
interpolate?: (a: T, b: T) => (t: number) => T
interpolate?: (a: T, b: T) => (t: number) => T;
}
type Updater<T> = (target_value: T, value: T) => T;
@ -69,7 +69,7 @@ interface Tweened<T> extends Readable<T> {
update(updater: Updater<T>, opts: Options<T>): Promise<void>;
}
export function tweened<T>(value: T, defaults: Options<T> = {}):Tweened<T> {
export function tweened<T>(value: T, defaults: Options<T> = {}): Tweened<T> {
const store = writable(value);
let task: Task;
@ -122,7 +122,7 @@ export function tweened<T>(value: T, defaults: Options<T> = {}):Tweened<T> {
return {
set,
update: (fn, opts:Options<T>) => set(fn(target_value, value), opts),
update: (fn, opts: Options<T>) => set(fn(target_value, value), opts),
subscribe: store.subscribe
};
}

@ -10,7 +10,7 @@ type Unsubscriber = () => void;
type Updater<T> = (value: T) => T;
/** Cleanup logic callback. */
type Invalidater<T> = (value?: T) => void;
type Invalidator<T> = (value?: T) => void;
/** Start and stop notification callbacks. */
type StartStopNotifier<T> = (set: Subscriber<T>) => Unsubscriber | void;
@ -22,7 +22,7 @@ export interface Readable<T> {
* @param run subscription callback
* @param invalidate cleanup callback
*/
subscribe(run: Subscriber<T>, invalidate?: Invalidater<T>): Unsubscriber;
subscribe(run: Subscriber<T>, invalidate?: Invalidator<T>): Unsubscriber;
}
/** Writable interface for both updating and subscribing. */
@ -41,7 +41,7 @@ export interface Writable<T> extends Readable<T> {
}
/** Pair of subscriber and invalidator. */
type SubscribeInvalidateTuple<T> = [Subscriber<T>, Invalidater<T>];
type SubscribeInvalidateTuple<T> = [Subscriber<T>, Invalidator<T>];
/**
* Creates a `Readable` store that allows reading by subscription.
@ -78,7 +78,7 @@ export function writable<T>(value: T, start: StartStopNotifier<T> = noop): Writa
set(fn(value));
}
function subscribe(run: Subscriber<T>, invalidate: Invalidater<T> = noop): Unsubscriber {
function subscribe(run: Subscriber<T>, invalidate: Invalidator<T> = noop): Unsubscriber {
const subscriber: SubscribeInvalidateTuple<T> = [run, invalidate];
subscribers.push(subscriber);
if (subscribers.length === 1) {
@ -127,7 +127,9 @@ export function derived<T, S extends Stores>(
const auto = fn.length < 2;
return readable(initial_value, (set) => {
const invalidators: Array<Invalidator<T>> = [];
const store = readable(initial_value, (set) => {
let inited = false;
const values: StoresValues<S> = [] as StoresValues<S>;
@ -156,6 +158,7 @@ export function derived<T, S extends Stores>(
}
},
() => {
run_all(invalidators);
pending |= (1 << i);
}),
);
@ -168,6 +171,22 @@ export function derived<T, S extends Stores>(
cleanup();
};
});
return {
subscribe(run: Subscriber<T>, invalidate: Invalidator<T> = noop): Unsubscriber {
invalidators.push(invalidate);
const unsubscribe = store.subscribe(run, invalidate);
return () => {
const index = invalidators.indexOf(invalidate);
if (index !== -1) {
invalidators.splice(index, 1);
}
unsubscribe();
};
}
};
}
/**

@ -2,11 +2,11 @@ import { cubicOut, cubicInOut } from 'svelte/easing';
import { assign, is_function } from 'svelte/internal';
export interface TransitionConfig {
delay?: number,
duration?: number,
easing?: (t: number) => number,
css?: (t: number, u: number) => string,
tick?: (t: number, u: number) => void
delay?: number;
duration?: number;
easing?: (t: number) => number;
css?: (t: number, u: number) => string;
tick?: (t: number, u: number) => void;
}
interface FadeParams {
@ -30,7 +30,7 @@ export function fade(node: Element, {
interface FlyParams {
delay: number;
duration: number;
easing: (t: number)=>number,
easing: (t: number) => number;
x: number;
y: number;
opacity: number;
@ -63,7 +63,7 @@ export function fly(node: Element, {
interface SlideParams {
delay: number;
duration: number;
easing: (t: number)=>number,
easing: (t: number) => number;
}
export function slide(node: Element, {
@ -101,7 +101,7 @@ export function slide(node: Element, {
interface ScaleParams {
delay: number;
duration: number;
easing: (t: number)=>number,
easing: (t: number) => number;
start: number;
opacity: number;
}
@ -124,7 +124,7 @@ export function scale(node: Element, {
delay,
duration,
easing,
css: (t, u) => `
css: (_t, u) => `
transform: ${transform} scale(${1 - (sd * u)});
opacity: ${target_opacity - (od * u)}
`
@ -135,7 +135,7 @@ interface DrawParams {
delay: number;
speed: number;
duration: number | ((len: number) => number);
easing: (t: number) => number,
easing: (t: number) => number;
}
export function draw(node: SVGElement & { getTotalLength(): number }, {
@ -167,18 +167,18 @@ export function draw(node: SVGElement & { getTotalLength(): number }, {
interface CrossfadeParams {
delay: number;
duration: number | ((len: number) => number);
easing: (t: number) => number,
easing: (t: number) => number;
}
type ClientRectMap = Map<any, { rect: ClientRect }>;
export function crossfade({ fallback, ...defaults }: CrossfadeParams & {
fallback: (node: Element, params: CrossfadeParams, intro: boolean)=> TransitionConfig
fallback: (node: Element, params: CrossfadeParams, intro: boolean) => TransitionConfig;
}) {
const to_receive: ClientRectMap = new Map();
const to_send: ClientRectMap = new Map();
function crossfade(from: ClientRect, node: Element, params: CrossfadeParams):TransitionConfig {
function crossfade(from: ClientRect, node: Element, params: CrossfadeParams): TransitionConfig {
const {
delay = 0,
duration = d => Math.sqrt(d) * 30,

@ -0,0 +1,5 @@
{
"rules": {
"no-console": "off"
}
}

@ -0,0 +1 @@
<div class="svelte-xyz foo:bar">Hello world</div>

@ -0,0 +1,11 @@
<script>
const enabled = true;
</script>
<div class:foo:bar={enabled}>Hello world</div>
<style>
.foo\:bar {
color: red;
}
</style>

@ -29,9 +29,9 @@ export default {
right: 100,
top,
bottom: top + 20
}
};
};
})
});
component.things = [
{ id: 5, name: 'e' },

@ -29,9 +29,9 @@ export default {
right: 100,
top,
bottom: top + 20
}
};
};
})
});
component.things = [
{ id: 5, name: 'e' },

@ -29,9 +29,9 @@ export default {
right: 100,
top,
bottom: top + 20
}
};
};
})
});
component.things = [
{ id: 5, name: 'e' },

@ -29,7 +29,7 @@ export default {
right: 100,
top,
bottom: top + 20
}
};
};
});

@ -1,6 +1,6 @@
let fulfil;
let thePromise = new Promise(f => {
const thePromise = new Promise(f => {
fulfil = f;
});

@ -1,6 +1,6 @@
let fulfil;
let thePromise = new Promise(f => {
const thePromise = new Promise(f => {
fulfil = f;
});

@ -1,6 +1,6 @@
let fulfil;
let thePromise = new Promise(f => {
const thePromise = new Promise(f => {
fulfil = f;
});

@ -1,6 +1,7 @@
export default {
async test({ assert, component, target }) {
let resolve, reject;
let resolve;
let reject;
let promise = new Promise(ok => resolve = ok);
component.promise = promise;

@ -9,7 +9,7 @@ export default {
`,
ssrHtml: `
<textarea value="some text"></textarea>
<textarea>some text</textarea>
<p>some text</p>
`,

@ -2,4 +2,4 @@ export default {
html: `
<foo-bar>Hello</foo-bar>
`
}
};

@ -1,3 +1,3 @@
export default {
html: 'Compile plz'
}
html: 'Compile plz'
};

@ -1,7 +1,7 @@
export default {
props: {
greeting: 'Good day'
},
props: {
greeting: 'Good day'
},
html: '<h1>Good day, world</h1>'
}
html: '<h1>Good day, world</h1>'
};

@ -10,4 +10,4 @@ export default {
const { foo } = component;
assert.equal(foo, undefined);
}
}
};

@ -15,7 +15,7 @@ export default {
</div>`,
test({ assert, component, target }) {
var nested = component.nested;
const nested = component.nested;
assert.htmlEqual(target.innerHTML, `
<div>
@ -24,6 +24,7 @@ export default {
</div>
`);
// eslint-disable-next-line no-self-assign
nested.foo = nested.foo;
assert.htmlEqual(target.innerHTML, `
<div>

@ -4,6 +4,7 @@ export default {
html: `<div><h3>Called 1 times.</h3></div>`,
test({ assert, component, target }) {
// eslint-disable-next-line no-self-assign
component.foo = component.foo;
assert.htmlEqual(target.innerHTML, `<div><h3>Called 1 times.</h3></div>`);
}

@ -4,6 +4,7 @@ export default {
html: `<div><h3>Called 1 times.</h3></div>`,
test({ assert, component, target }) {
// eslint-disable-next-line no-self-assign
component.foo = component.foo;
assert.htmlEqual(target.innerHTML, `<div><h3>Called 2 times.</h3></div>`);
}

@ -2,6 +2,7 @@ export default {
html: `<div><h3>Called 1 times.</h3></div>`,
test({ assert, component, target }) {
// eslint-disable-next-line no-self-assign
component.foo = component.foo;
assert.htmlEqual(target.innerHTML, `<div><h3>Called 1 times.</h3></div>`);
}

@ -1,18 +1,18 @@
export default {
html: `
<p>internal: 1</p>
<button>click me</button>
`,
html: `
<p>internal: 1</p>
<button>click me</button>
`,
async test({ assert, target, window }) {
const button = target.querySelector('button');
const click = new window.MouseEvent('click');
async test({ assert, target, window }) {
const button = target.querySelector('button');
const click = new window.MouseEvent('click');
await button.dispatchEvent(click);
await button.dispatchEvent(click);
assert.htmlEqual(target.innerHTML, `
<p>internal: 1</p>
<button>click me</button>
`);
}
};
assert.htmlEqual(target.innerHTML, `
<p>internal: 1</p>
<button>click me</button>
`);
}
};

@ -1,9 +1,9 @@
export default {
props: {
a: 42
},
props: {
a: 42
},
html: `
42
`
}
html: `
42
`
};

@ -2,29 +2,29 @@ import { writable } from '../../../../store';
export default {
props: {
s1: writable(42),
s2: writable(43),
p1: 2,
p3: 3,
a1: writable(1),
a2: 4,
a6: writable(29),
for: 'loop',
continue: '...',
s1: writable(42),
s2: writable(43),
p1: 2,
p3: 3,
a1: writable(1),
a2: 4,
a6: writable(29),
for: 'loop',
continue: '...',
},
html: `
$s1=42
$s2=43
p1=2
p3=3
$v1=1
v2=4
vi1=4
$vs1=1
vl0=hello
vl1=test
$s3=29
loop...
`
}
$s1=42
$s2=43
p1=2
p3=3
$v1=1
v2=4
vi1=4
$vs1=1
vl0=hello
vl1=test
$s3=29
loop...
`
};

@ -1,3 +1,3 @@
export default {
html: `<p>0</p>`
}
};

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save