pull/3539/head
Rich Harris 6 years ago
parent 6514b142dc
commit af1057b4a3

10
package-lock.json generated

@ -330,11 +330,6 @@
"integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==",
"dev": true
},
"astring": {
"version": "github:Rich-Harris/astring#ff83f5e4e75b304cdd428ada4a71372276b0084d",
"from": "github:Rich-Harris/astring#generic-handler",
"dev": true
},
"async-limiter": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz",
@ -513,13 +508,16 @@
"dev": true,
"requires": {
"acorn": "^7.0.0",
"astring": "github:Rich-Harris/astring#ff83f5e4e75b304cdd428ada4a71372276b0084d",
"estree-walker": "^0.6.1",
"is-reference": "^1.1.3",
"periscopic": "^1.0.0",
"source-map": "^0.7.3"
},
"dependencies": {
"astring": {
"version": "github:Rich-Harris/astring#ff83f5e4e75b304cdd428ada4a71372276b0084d",
"from": "github:Rich-Harris/astring#ff83f5e4e75b304cdd428ada4a71372276b0084d"
},
"estree-walker": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz",

@ -912,11 +912,13 @@ export default class Component {
computed: false,
kind: 'init',
key: declarator.id,
value: {
type: 'AssignmentPattern',
left: declarator.id,
right: declarator.init
}
value: declarator.init
? {
type: 'AssignmentPattern',
left: declarator.id,
right: declarator.init
}
: declarator.id
}]
};
@ -1228,7 +1230,7 @@ export default class Component {
}
qualify(name) {
if (name === `$$props`) return `#ctx.$$props`;
if (name === `$$props`) return x`#ctx.$$props`;
const variable = this.var_lookup.get(name);
@ -1238,7 +1240,7 @@ export default class Component {
if (variable.hoistable) return name;
return `#ctx.${name}`;
return x`#ctx.${name}`;
}
warn_if_undefined(name: string, node, template_scope: TemplateScope) {

@ -173,7 +173,8 @@ function cjs(
shorthand: false,
computed: false,
key: s.imported || { type: 'Identifier', name: 'default' },
value: s.local
value: s.local,
kind: 'init'
}))
},
init: x`require("${edit_source(node.source.value, sveltePath)}")`

@ -4,6 +4,7 @@ import Expression from './shared/Expression';
import Component from '../Component';
import TemplateScope from './shared/TemplateScope';
import {dimensions} from "../../utils/patterns";
import { x } from 'code-red';
// TODO this should live in a specific binding
const read_only_media_attributes = new Set([
@ -68,8 +69,8 @@ export default class Binding extends Node {
if (!this.expression.node.computed) prop = `'${prop}'`;
obj = `[✂${this.expression.node.object.start}-${this.expression.node.object.end}✂]`;
} else {
obj = '#ctx';
prop = `'${name}'`;
obj = x`#ctx`;
prop = x`'${name}'`;
}
this.obj = obj;

@ -1,7 +1,7 @@
import Node from './shared/Node';
import Expression from './shared/Expression';
import Component from '../Component';
import { b } from 'code-red';
import { b, x } from 'code-red';
import Block from '../render_dom/Block';
import { sanitize } from '../../utils/names';
import { Identifier } from '../../interfaces';
@ -63,9 +63,11 @@ export default class EventHandler extends Node {
// TODO move this? it is specific to render-dom
render(block: Block) {
if (this.expression) this.expression.manipulate(block);
if (this.expression) {
return this.expression.manipulate(block);
}
// this.component.add_reference(this.handler_name);
return `#ctx.${this.handler_name}`;
return x`#ctx.${this.handler_name}`;
}
}

@ -57,7 +57,7 @@ export default class Block {
destroy: Node[];
};
event_listeners: string[] = [];
event_listeners: Node[] = [];
maintain_context: boolean;
has_animation: boolean;
@ -430,7 +430,7 @@ export default class Block {
} else {
this.chunks.hydrate.push(b`
${dispose} = [
${this.event_listeners.join(',\n')}
${this.event_listeners}
];
`);

@ -1,5 +1,4 @@
import { b, x } from 'code-red';
import deindent from '../utils/deindent';
import { stringify, escape } from '../utils/stringify';
import Component from '../Component';
import Renderer from './Renderer';
@ -99,44 +98,59 @@ export default function dom(
const not_equal = component.component_options.immutable ? x`@not_equal` : x`@safe_not_equal`;
let dev_props_check; let inject_state; let capture_state;
props.forEach(x => {
const variable = component.var_lookup.get(x.name);
props.forEach(prop => {
const variable = component.var_lookup.get(prop.name);
if (!variable.writable || component.component_options.accessors) {
accessors.push(deindent`
get ${x.export_name}() {
return ${x.hoistable ? x.name : 'this.$$.ctx.' + x.name};
}
`);
accessors.push({
type: 'MethodDefinition',
kind: 'get',
key: { type: 'Identifier', name: prop.export_name },
value: x`function() {
return ${prop.hoistable ? prop.name : x`this.$$.ctx.${prop.name}`}
}`
});
} else if (component.compile_options.dev) {
accessors.push(deindent`
get ${x.export_name}() {
accessors.push({
type: 'MethodDefinition',
kind: 'get',
key: { type: 'Identifier', name: prop.export_name },
value: x`function() {
throw new @_Error("<${component.tag}>: Props cannot be read directly from the component instance unless compiling with 'accessors: true' or '<svelte:options accessors/>'");
}
`);
}`
});
}
if (component.component_options.accessors) {
if (variable.writable && !renderer.readonly.has(x.name)) {
accessors.push(deindent`
set ${x.export_name}(${x.name}) {
this.$set({ ${x.name === x.export_name ? x.name : `${x.export_name}: ${x.name}`} });
if (variable.writable && !renderer.readonly.has(prop.name)) {
accessors.push({
type: 'MethodDefinition',
kind: 'set',
key: { type: 'Identifier', name: prop.export_name },
value: x`function(${prop.name}) {
this.$set({ ${prop.export_name}: ${prop.name} });
@flush();
}
`);
}`
});
} else if (component.compile_options.dev) {
accessors.push(deindent`
set ${x.export_name}(value) {
throw new @_Error("<${component.tag}>: Cannot set read-only property '${x.export_name}'");
}
`);
accessors.push({
type: 'MethodDefinition',
kind: 'set',
key: { type: 'Identifier', name: prop.export_name },
value: x`function(value) {
throw new @_Error("<${component.tag}>: Cannot set read-only property '${prop.export_name}'");
}`
});
}
} else if (component.compile_options.dev) {
accessors.push(deindent`
set ${x.export_name}(value) {
accessors.push({
type: 'MethodDefinition',
kind: 'set',
key: { type: 'Identifier', name: prop.export_name },
value: x`function(value) {
throw new @_Error("<${component.tag}>: Props cannot be set directly on the component instance unless compiling with 'accessors: true' or '<svelte:options accessors/>'");
}
`);
}`
});
}
});
@ -204,7 +218,7 @@ export default function dom(
// onto the initial function call
const names = new Set(extract_names(assignee));
invalidate(component, scope, node, names);
this.replace(invalidate(component, scope, node, names));
}
}
});
@ -405,7 +419,7 @@ export default function dom(
});
if (options.customElement) {
body.push(b`
const declaration = b`
class ${name} extends @SvelteElement {
constructor(options) {
super();
@ -428,15 +442,24 @@ export default function dom(
}`}
}
}
}
`[0];
if (props.length > 0) {
declaration.body.body.push({
type: 'MethodDefinition',
kind: 'get',
static: true,
key: { type: 'Identifier', name: 'observedAttributes' },
value: x`function() {
return [${props.map(prop => x`"${prop.export_name}"`)}];
}`
})
}
${props.length > 0 && deindent`
static get observedAttributes() {
return ${JSON.stringify(props.map(x => x.export_name))};
}`}
declaration.body.body.push(...accessors);
${body.length > 0 && body.join('\n\n')}
}
`);
body.push(declaration);
if (component.tag != null) {
body.push(b`
@ -449,9 +472,7 @@ export default function dom(
name: options.dev ? '@SvelteComponentDev' : '@SvelteComponent'
};
// TODO add accessors
body.push(b`
const declaration = b`
class ${name} extends ${superclass} {
constructor(options) {
super(${options.dev && `options`});
@ -462,7 +483,11 @@ export default function dom(
${dev_props_check}
}
}
`);
`[0];
declaration.body.body.push(...accessors);
body.push(declaration);
}
return flatten(body, []);

@ -63,7 +63,7 @@ export default class DebugTagWrapper extends Wrapper {
// block.chunks.update.push(b`
// if (${condition}) {
// const { ${ctx_identifiers} } = ctx;
// const { ${ctx_identifiers} } = #ctx;
// @_console.${log}({ ${logged_identifiers} });
// debugger;
// }
@ -71,7 +71,7 @@ export default class DebugTagWrapper extends Wrapper {
// block.chunks.create.push(b`
// {
// const { ${ctx_identifiers} } = ctx;
// const { ${ctx_identifiers} } = #ctx;
// @_console.${log}({ ${logged_identifiers} });
// debugger;
// }

@ -125,11 +125,11 @@ export default class BindingWrapper {
const binding_group = get_binding_group(parent.renderer, this.node.expression.node);
block.chunks.hydrate.push(
b`ctx.$$binding_groups[${binding_group}].push(${parent.var});`
b`#ctx.$$binding_groups[${binding_group}].push(${parent.var});`
);
block.chunks.destroy.push(
b`ctx.$$binding_groups[${binding_group}].splice(ctx.$$binding_groups[${binding_group}].indexOf(${parent.var}), 1);`
b`#ctx.$$binding_groups[${binding_group}].splice(#ctx.$$binding_groups[${binding_group}].indexOf(${parent.var}), 1);`
);
break;
}

@ -480,21 +480,21 @@ export default class ElementWrapper extends Wrapper {
${animation_frame} = @raf(${handler});
${needs_lock && `${lock} = true;`}
}
ctx.${handler}.call(${this.var}${contextual_dependencies.size > 0 ? ', ctx' : ''});
#ctx.${handler}.call(${this.var}${contextual_dependencies.size > 0 ? ', #ctx' : ''});
}
`);
} else {
block.chunks.init.push(b`
function ${handler}() {
${needs_lock && `${lock} = true;`}
ctx.${handler}.call(${this.var}${contextual_dependencies.size > 0 ? ', ctx' : ''});
#ctx.${handler}.call(${this.var}${contextual_dependencies.size > 0 ? ', #ctx' : ''});
}
`);
}
callee = handler;
} else {
callee = `ctx.${handler}`;
callee = x`#ctx.${handler}`;
}
this.renderer.component.partly_hoisted.push(b`
@ -519,7 +519,7 @@ export default class ElementWrapper extends Wrapper {
);
} else {
block.event_listeners.push(
`@listen(${this.var}, "${name}", ${callee})`
x`@listen(${this.var}, "${name}", ${callee})`
);
}
});

@ -250,14 +250,14 @@ export default class InlineComponentWrapper extends Wrapper {
}
if (non_let_dependencies.length > 0) {
updates.push(`if (${non_let_dependencies.map(n => `changed.${n}`).join(' || ')}) ${name_changes}.$$scope = { changed, ctx };`);
updates.push(`if (${non_let_dependencies.map(n => `changed.${n}`).join(' || ')}) ${name_changes}.$$scope = { changed: #changed, ctx: #ctx };`);
}
const munged_bindings = this.node.bindings.map(binding => {
component.has_reactive_assignments = true;
if (binding.name === 'this') {
return bind_this(component, block, binding, this.var.name);
return bind_this(component, block, binding, this.var);
}
const id = component.get_unique_name(`${this.var}_${binding.name}_binding`);
@ -306,7 +306,7 @@ export default class InlineComponentWrapper extends Wrapper {
block.chunks.init.push(b`
function ${name}(${value}) {
ctx.${name}.call(null, ${value}, ctx);
#ctx.${name}.call(null, ${value}, #ctx);
${updating} = true;
@add_flush_callback(() => ${updating} = false);
}
@ -316,7 +316,7 @@ export default class InlineComponentWrapper extends Wrapper {
} else {
block.chunks.init.push(b`
function ${id}(${value}) {
ctx.${name}.call(null, ${value});
#ctx.${name}.call(null, ${value});
${updating} = true;
@add_flush_callback(() => ${updating} = false);
}
@ -337,7 +337,7 @@ export default class InlineComponentWrapper extends Wrapper {
const munged_handlers = this.node.handlers.map(handler => {
let snippet = handler.render(block);
if (handler.modifiers.has('once')) snippet = `@once(${snippet})`;
if (handler.modifiers.has('once')) snippet = x`@once(${snippet})`;
return `${name}.$on("${handler.name}", ${snippet});`;
});
@ -351,7 +351,7 @@ export default class InlineComponentWrapper extends Wrapper {
block.chunks.init.push(b`
var ${switch_value} = ${snippet};
function ${switch_props}(ctx) {
function ${switch_props}(#ctx) {
${(this.node.attributes.length || this.node.bindings.length) && b`
${props && `let ${props} = ${attribute_object};`}`}
${statements}
@ -359,7 +359,7 @@ export default class InlineComponentWrapper extends Wrapper {
}
if (${switch_value}) {
var ${name} = new ${switch_value}(${switch_props}(ctx));
var ${name} = new ${switch_value}(${switch_props}(#ctx));
${munged_bindings}
${munged_handlers}
@ -403,7 +403,7 @@ export default class InlineComponentWrapper extends Wrapper {
}
if (${switch_value}) {
${name} = new ${switch_value}(${switch_props}(ctx));
${name} = new ${switch_value}(${switch_props}(#ctx));
${munged_bindings}
${munged_handlers}

@ -110,8 +110,8 @@ export default class SlotWrapper extends Wrapper {
const slot_definition = block.get_unique_name(`${sanitize(slot_name)}_slot_template`);
block.chunks.init.push(b`
const ${slot_definition} = ctx.$$slots${quote_prop_if_necessary(slot_name)};
const ${slot} = @create_slot(${slot_definition}, ctx, ${get_slot_context});
const ${slot_definition} = #ctx.$$slots${quote_prop_if_necessary(slot_name)};
const ${slot} = @create_slot(${slot_definition}, #ctx, ${get_slot_context});
`);
const mount_before = block.chunks.mount.slice();
@ -175,8 +175,8 @@ export default class SlotWrapper extends Wrapper {
block.chunks.update.push(b`
if (${slot} && ${slot}.p && ${update_conditions}) {
${slot}.p(
@get_slot_changes(${slot_definition}, ctx, changed, ${get_slot_changes}),
@get_slot_context(${slot_definition}, ctx, ${get_slot_context})
@get_slot_changes(${slot_definition}, #ctx, changed, ${get_slot_changes}),
@get_slot_context(${slot_definition}, #ctx, ${get_slot_context})
);
}
`);

@ -82,13 +82,12 @@ export default class WindowWrapper extends Wrapper {
block.add_variable(clear_scrolling, x`() => { ${scrolling} = false }`);
block.add_variable(scrolling_timeout);
const condition = [
bindings.scrollX && `"${bindings.scrollX}" in this._state`,
bindings.scrollY && `"${bindings.scrollY}" in this._state`
].filter(Boolean).join(' || ');
const condition = bindings.scrollX && bindings.scrollY
? x`"${bindings.scrollX}" in this._state || "${bindings.scrollY}" in this._state`
: x`"${bindings.scrollX || bindings.scrollY}" in this._state`;
const scrollX = bindings.scrollX && `this._state.${bindings.scrollX}`;
const scrollY = bindings.scrollY && `this._state.${bindings.scrollY}`;
const scrollX = bindings.scrollX && x`this._state.${bindings.scrollX}`;
const scrollY = bindings.scrollY && x`this._state.${bindings.scrollY}`;
renderer.meta_bindings.push(b`
if (${condition}) {
@ -98,12 +97,12 @@ export default class WindowWrapper extends Wrapper {
${scrollY && `${scrollY} = @_window.pageYOffset;`}
`);
block.event_listeners.push(b`
block.event_listeners.push(x`
@listen(@_window, "${event}", () => {
${scrolling} = true;
@_clearTimeout(${scrolling_timeout});
${scrolling_timeout} = @_setTimeout(${clear_scrolling}, 100);
ctx.${id}();
#ctx.${id}();
})
`);
} else {
@ -113,8 +112,8 @@ export default class WindowWrapper extends Wrapper {
);
});
block.event_listeners.push(b`
@listen(@_window, "${event}", ctx.${id})
block.event_listeners.push(x`
@listen(@_window, "${event}", #ctx.${id})
`);
}
@ -131,7 +130,7 @@ export default class WindowWrapper extends Wrapper {
`);
block.chunks.init.push(b`
@add_render_callback(ctx.${id});
@add_render_callback(#ctx.${id});
`);
component.has_reactive_assignments = true;
@ -148,9 +147,9 @@ export default class WindowWrapper extends Wrapper {
${scrolling} = true;
@_clearTimeout(${scrolling_timeout});
@_scrollTo(${
bindings.scrollX ? `ctx.${bindings.scrollX}` : `@_window.pageXOffset`
bindings.scrollX ? `#ctx.${bindings.scrollX}` : `@_window.pageXOffset`
}, ${
bindings.scrollY ? `ctx.${bindings.scrollY}` : `@_window.pageYOffset`
bindings.scrollY ? `#ctx.${bindings.scrollY}` : `@_window.pageYOffset`
});
${scrolling_timeout} = @_setTimeout(${clear_scrolling}, 100);
}
@ -175,12 +174,12 @@ export default class WindowWrapper extends Wrapper {
`);
block.chunks.init.push(b`
@add_render_callback(ctx.${id});
@add_render_callback(#ctx.${id});
`);
block.event_listeners.push(
`@listen(@_window, "online", ctx.${id})`,
`@listen(@_window, "offline", ctx.${id})`
x`@listen(@_window, "online", #ctx.${id})`,
x`@listen(@_window, "offline", #ctx.${id})`
);
component.has_reactive_assignments = true;

@ -1,5 +1,6 @@
import Block from '../../Block';
import EventHandler from '../../../nodes/EventHandler';
import { x } from 'code-red';
export default function add_event_handlers(
block: Block,
@ -8,35 +9,37 @@ export default function add_event_handlers(
) {
handlers.forEach(handler => {
let snippet = handler.render(block);
if (handler.modifiers.has('preventDefault')) snippet = `@prevent_default(${snippet})`;
if (handler.modifiers.has('stopPropagation')) snippet = `@stop_propagation(${snippet})`;
if (handler.modifiers.has('self')) snippet = `@self(${snippet})`;
if (handler.modifiers.has('preventDefault')) snippet = x`@prevent_default(${snippet})`;
if (handler.modifiers.has('stopPropagation')) snippet = x`@stop_propagation(${snippet})`;
if (handler.modifiers.has('self')) snippet = x`@self(${snippet})`;
let opts_string = '';
// let opts_string = '';
if (block.renderer.options.dev) {
if (handler.modifiers.has('stopPropagation')) {
opts_string = ', true';
}
// if (block.renderer.options.dev) {
// if (handler.modifiers.has('stopPropagation')) {
// opts_string = ', true';
// }
if (handler.modifiers.has('preventDefault')) {
opts_string = ', true' + opts_string;
} else if (opts_string) {
opts_string = ', false' + opts_string;
}
}
// if (handler.modifiers.has('preventDefault')) {
// opts_string = ', true' + opts_string;
// } else if (opts_string) {
// opts_string = ', false' + opts_string;
// }
// }
const opts = ['passive', 'once', 'capture'].filter(mod => handler.modifiers.has(mod));
if (opts.length) {
opts_string = (opts.length === 1 && opts[0] === 'capture')
? ', true'
: `, { ${opts.map(opt => `${opt}: true`).join(', ')} }`;
} else if (opts_string) {
opts_string = ', false' + opts_string;
}
// const opts = ['passive', 'once', 'capture'].filter(mod => handler.modifiers.has(mod));
// if (opts.length) {
// opts_string = (opts.length === 1 && opts[0] === 'capture')
// ? ', true'
// : `, { ${opts.map(opt => `${opt}: true`).join(', ')} }`;
// } else if (opts_string) {
// opts_string = ', false' + opts_string;
// }
// TODO modifiers
block.event_listeners.push(
`@listen(${target}, "${handler.name}", ${snippet}${opts_string})`
x`@listen(${target}, "${handler.name}", ${snippet})`
);
});
}

@ -5,8 +5,8 @@ import Block from '../../Block';
import Binding from '../../../nodes/Binding';
import { Identifier } from '../../../../interfaces';
export default function bind_this(component: Component, block: Block, binding: Binding, variable: string) {
const fn = component.get_unique_name(`${variable}_binding`);
export default function bind_this(component: Component, block: Block, binding: Binding, variable: Identifier) {
const fn = component.get_unique_name(`${variable.name}_binding`);
component.add_var({
name: fn.name,
@ -56,18 +56,18 @@ export default function bind_this(component: Component, block: Block, binding: B
for (const arg of contextual_dependencies) {
const id: Identifier = { type: 'Identifier', name: arg };
args.push(id);
block.add_variable(id, x`ctx.${id}`);
block.add_variable(id, x`#ctx.${id}`);
}
const assign = block.get_unique_name(`assign_${variable}`);
const unassign = block.get_unique_name(`unassign_${variable}`);
block.chunks.init.push(b`
const ${assign} = () => ctx.${fn}(${[variable].concat(args).join(', ')});
const ${unassign} = () => ctx.${fn}(${['null'].concat(args).join(', ')});
const ${assign} = () => #ctx.${fn}(${[variable].concat(args).join(', ')});
const ${unassign} = () => #ctx.${fn}(${['null'].concat(args).join(', ')});
`);
const condition = Array.from(contextual_dependencies).map(name => `${name} !== ctx.${name}`).join(' || ');
const condition = Array.from(contextual_dependencies).map(name => `${name} !== #ctx.${name}`).join(' || ');
// we push unassign and unshift assign so that references are
// nulled out before they're created, to avoid glitches
@ -75,7 +75,7 @@ export default function bind_this(component: Component, block: Block, binding: B
block.chunks.update.push(b`
if (${condition}) {
${unassign}();
${args.map(a => `${a} = ctx.${a}`).join(', ')};
${args.map(a => `${a} = #ctx.${a}`).join(', ')};
${assign}();
}`
);
@ -92,6 +92,6 @@ export default function bind_this(component: Component, block: Block, binding: B
}
`);
block.chunks.destroy.push(b`ctx.${fn}(null);`);
return b`ctx.${fn}(${variable});`;
block.chunks.destroy.push(b`#ctx.${fn}(null);`);
return b`#ctx.${fn}(${variable});`;
}

@ -85,7 +85,7 @@ export default function(node: Element, renderer: Renderer, options: RenderOption
const class_expression = node.classes.map((class_directive: Class) => {
const { expression, name } = class_directive;
const snippet = expression ? snip(expression) : `ctx${quote_prop_if_necessary(name)}`;
const snippet = expression ? snip(expression) : `#ctx${quote_prop_if_necessary(name)}`;
return `${snippet} ? "${name}" : ""`;
}).join(', ');

@ -55,7 +55,10 @@ export function invalidate(component: Component, scope: Scope, node: Node, names
);
if (pass_value) {
extra_args.unshift(head);
extra_args.unshift({
type: 'Identifier',
name: head
});
}
return x`$$invalidate("${head}", ${node}, ${extra_args})`;

@ -102,7 +102,6 @@ export function init(component, options, instance, create_fragment, not_equal, p
$$.ctx = instance
? instance(component, props, (key, ret, value = ret) => {
console.log(`invalidating`, key, ret, value);
if ($$.ctx && not_equal($$.ctx[key], $$.ctx[key] = value)) {
if ($$.bound[key]) $$.bound[key](value);
if (ready) make_dirty(component, key);

@ -4,7 +4,7 @@
function foo(node) {
const handler = () => {
x += 1;
}
};
node.addEventListener('click', handler);
handler();

@ -3,7 +3,7 @@ export default {
<button>action</button>
`,
async test({ assert, component, target, window }) {
async test({ assert, target, window }) {
const button = target.querySelector('button');
const enter = new window.MouseEvent('mouseenter');
const leave = new window.MouseEvent('mouseleave');

Loading…
Cancel
Save