pull/3539/head
Rich Harris 6 years ago
parent 1d8d17bc07
commit 50280232e8

@ -1,4 +1,3 @@
import MagicString from 'magic-string';
// @ts-ignore
import { walk, childKeys } from 'estree-walker';
import { getLocator } from 'locate-character';
@ -23,14 +22,13 @@ import flatten_reference from './utils/flatten_reference';
import is_reference from 'is-reference';
import TemplateScope from './nodes/shared/TemplateScope';
import fuzzymatch from '../utils/fuzzymatch';
import { remove_indentation, add_indentation } from '../utils/indentation';
import get_object from './utils/get_object';
import unwrap_parens from './utils/unwrap_parens';
import Slot from './nodes/Slot';
import { Node as ESTreeNode } from 'estree';
import add_to_set from './utils/add_to_set';
import check_graph_for_cycles from './utils/check_graph_for_cycles';
import { print } from 'code-red';
import { print, x } from 'code-red';
interface ComponentOptions {
namespace?: string;
@ -48,37 +46,13 @@ childKeys.Attribute = ['value'];
childKeys.ExportNamedDeclaration = ['declaration', 'specifiers'];
function remove_node(
code: MagicString,
start: number,
end: number,
body: Node,
node: Node
) {
const i = body.indexOf(node);
if (i === -1) throw new Error('node not in list');
let a;
let b;
if (body.length === 1) {
// remove everything, leave {}
a = start;
b = end;
} else if (i === 0) {
// remove everything before second node, including comments
a = start;
while (/\s/.test(code.original[a])) a += 1;
b = body[i].end;
while (/[\s,]/.test(code.original[b])) b += 1;
} else {
// remove the end of the previous node to the end of this one
a = body[i - 1].end;
b = node.end;
}
code.remove(a, b);
return;
body.splice(i, 1);
}
export default class Component {
@ -89,7 +63,6 @@ export default class Component {
ast: Ast;
source: string;
code: MagicString;
name: Identifier;
compile_options: CompileOptions;
fragment: Fragment;
@ -173,8 +146,6 @@ export default class Component {
: compile_options.filename);
this.locate = getLocator(this.source);
this.code = new MagicString(source);
// styles
this.stylesheet = new Stylesheet(
source,
@ -261,15 +232,6 @@ export default class Component {
}
}
add_sourcemap_locations(node: Node) {
walk(node, {
enter: (node: Node) => {
this.code.addSourcemapLocation(node.start);
this.code.addSourcemapLocation(node.end);
},
});
}
alias(name: string) {
if (!this.aliases.has(name)) {
this.aliases.set(name, this.get_unique_name(name));
@ -502,21 +464,20 @@ export default class Component {
}
extract_imports(content) {
const { code } = this;
content.body.forEach(node => {
if (node.type === 'ImportDeclaration') {
// imports need to be hoisted out of the IIFE
remove_node(code, content.start, content.end, content.body, node);
remove_node(content.body, node);
this.imports.push(node);
}
});
}
extract_exports(content) {
const { code } = this;
let i = content.body.length;
while (i--) {
const node = content.body[i];
content.body.forEach(node => {
if (node.type === 'ExportDefaultDeclaration') {
this.error(node, {
code: `default-export`,
@ -546,21 +507,20 @@ export default class Component {
variable.export_name = name;
}
code.remove(node.start, node.declaration.start);
content.body[i] = node.declaration;
} else {
remove_node(code, content.start, content.end, content.body, node);
node.specifiers.forEach(specifier => {
const variable = this.var_lookup.get(specifier.local.name);
if (variable) {
variable.export_name = specifier.exported.name;
} else {
// TODO what happens with `export { Math }` or some other global?
}
});
content.body.splice(i, 1);
}
}
});
}
}
extract_javascript(script) {
@ -573,35 +533,37 @@ export default class Component {
return true;
});
return nodes_to_include;
if (nodes_to_include.length === 0) return null;
let a = script.content.start;
while (/\s/.test(this.source[a])) a += 1;
let b = a;
// let b = a;
let result = '';
// let result = '';
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;
}
// 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;
// }
b = node.end;
});
// b = node.end;
// });
// while (/\s/.test(this.source[a - 1])) a -= 1;
b = script.content.end;
while (/\s/.test(this.source[b - 1])) b -= 1;
// b = script.content.end;
// while (/\s/.test(this.source[b - 1])) b -= 1;
if (a < b) result += `[✂${a}-${b}✂]`;
// if (a < b) result += `[✂${a}-${b}✂]`;
return result || null;
// return result || null;
}
walk_module_js() {
@ -620,8 +582,6 @@ export default class Component {
},
});
this.add_sourcemap_locations(script.content);
const { scope, globals } = create_scopes(script.content);
this.module_scope = scope;
@ -657,7 +617,6 @@ export default class Component {
this.extract_imports(script.content);
this.extract_exports(script.content);
remove_indentation(this.code, script.content);
this.module_javascript = this.extract_javascript(script);
}
@ -665,8 +624,6 @@ export default class Component {
const script = this.ast.instance;
if (!script) return;
this.add_sourcemap_locations(script.content);
// inject vars for reactive declarations
script.content.body.forEach(node => {
if (node.type !== 'LabeledStatement') return;
@ -893,18 +850,16 @@ export default class Component {
.join(', ');
}
rewrite_props(get_insert: (variable: Var) => string) {
rewrite_props(_get_insert: (variable: Var) => string) {
// TODO
const component = this;
const { code, instance_scope, instance_scope_map: map } = this;
const { instance_scope, instance_scope_map: map } = this;
let scope = instance_scope;
const coalesced_declarations = [];
let current_group;
walk(this.ast.instance.content, {
enter(node, parent) {
enter(node) {
if (/Function/.test(node.type)) {
current_group = null;
return this.skip();
}
@ -914,16 +869,15 @@ export default class Component {
if (node.type === 'VariableDeclaration') {
if (node.kind === 'var' || scope === instance_scope) {
node.declarations.forEach((declarator, i) => {
const next = node.declarations[i + 1];
node.declarations.forEach(declarator => {
// const next = node.declarations[i + 1];
if (declarator.id.type !== 'Identifier') {
const inserts = [];
extract_names(declarator.id).forEach(name => {
const variable = component.var_lookup.get(name);
if (variable.export_name) {
// TODO is this still true post-#3539?
component.error(declarator, {
code: 'destructured-prop',
message: `Cannot declare props in destructured declaration`,
@ -931,22 +885,10 @@ export default class Component {
}
if (variable.subscribable) {
inserts.push(get_insert(variable));
// TODO
}
});
if (inserts.length > 0) {
if (next) {
code.overwrite(
declarator.end,
next.start,
`; ${inserts.join('; ')}; ${node.kind} `
);
} else {
code.appendLeft(declarator.end, `; ${inserts.join('; ')}`);
}
}
return;
}
@ -954,112 +896,43 @@ export default class Component {
const variable = component.var_lookup.get(name);
if (variable.export_name) {
if (current_group && current_group.kind !== node.kind) {
current_group = null;
}
const insert = variable.subscribable
? get_insert(variable)
: null;
if (!current_group || (current_group.insert && insert)) {
current_group = {
kind: node.kind,
declarators: [declarator],
insert,
};
coalesced_declarations.push(current_group);
} else if (insert) {
current_group.insert = insert;
current_group.declarators.push(declarator);
} else {
current_group.declarators.push(declarator);
}
if (
variable.writable &&
variable.name !== variable.export_name
) {
code.prependRight(
declarator.id.start,
`${variable.export_name}: `
);
}
if (next) {
const next_variable = component.var_lookup.get(next.id.name);
const new_declaration =
!next_variable.export_name ||
(current_group.insert && next_variable.subscribable);
if (new_declaration) {
code.overwrite(
declarator.end,
next.start,
` ${node.kind} `
);
}
}
} else {
current_group = null;
if (variable.subscribable) {
const insert = get_insert(variable);
if (next) {
code.overwrite(
declarator.end,
next.start,
`; ${insert}; ${node.kind} `
);
} else {
code.appendLeft(declarator.end, `; ${insert}`);
}
}
// const insert = variable.subscribable
// ? get_insert(variable)
// : null;
declarator.id = {
type: 'ObjectPattern',
properties: [{
type: 'Property',
method: false,
shorthand: true,
computed: false,
kind: 'init',
key: declarator.id,
value: {
type: 'AssignmentPattern',
left: declarator.id,
right: declarator.init
}
}]
};
declarator.init = x`$$props`;
}
});
}
} else {
if (node.type !== 'ExportNamedDeclaration') {
if (!parent || parent.type === 'Program') current_group = null;
}
}
},
leave(node) {
leave(node, _parent, _key, index) {
if (map.has(node)) {
scope = scope.parent;
}
},
});
coalesced_declarations.forEach(group => {
const writable = group.kind === 'var' || group.kind === 'let';
let c = 0;
let combining = false;
group.declarators.forEach(declarator => {
const { id } = declarator;
if (combining) {
code.overwrite(c, id.start, ', ');
} else {
if (writable) code.appendLeft(id.start, '{ ');
combining = true;
if (node.type === 'ExportNamedDeclaration' && node.declaration) {
_parent.body[index] = node.declaration;
}
c = declarator.end;
});
if (combining) {
const insert = group.insert ? `; ${group.insert}` : '';
const suffix =
`${writable ? ` } = $$props` : ``}${insert}` +
(code.original[c] === ';' ? `` : `;`);
code.appendLeft(c, suffix);
}
},
});
}
@ -1213,8 +1086,6 @@ export default class Component {
variable.hoistable = true;
hoistable_nodes.add(node);
remove_indentation(this.code, node);
const i = body.indexOf(node);
body.splice(i, 1);
this.fully_hoisted.push(node);
@ -1280,8 +1151,6 @@ export default class Component {
},
});
add_indentation(this.code, node.body, 2);
const expression =
node.body.expression && unwrap_parens(node.body.expression);
const declaration = expression && expression.left;

@ -1,18 +1,18 @@
import Component from '../../Component';
import { walk } from 'estree-walker';
import is_reference from 'is-reference';
import { b } from 'code-red';
// import { b } from 'code-red';
import flatten_reference from '../../utils/flatten_reference';
import { create_scopes, Scope, extract_names } from '../../utils/scope';
import { Node } from '../../../interfaces';
import { globals , sanitize } from '../../../utils/names';
import { globals } from '../../../utils/names';
import Wrapper from '../../render_dom/wrappers/shared/Wrapper';
import TemplateScope from './TemplateScope';
import get_object from '../../utils/get_object';
import Block from '../../render_dom/Block';
import { INode } from '../interfaces';
import is_dynamic from '../../render_dom/wrappers/shared/is_dynamic';
import { invalidate } from '../../utils/invalidate';
// import { invalidate } from '../../utils/invalidate';
const binary_operators: Record<string, number> = {
'**': 15,
@ -224,192 +224,189 @@ export default class Expression {
}
// TODO move this into a render-dom wrapper?
render(block?: Block) {
if (this.rendered) return this.rendered;
const {
component,
declarations,
scope_map: map,
template_scope,
owner,
is_synthetic
} = this;
let scope = this.scope;
const { code } = component;
let function_expression;
let dependencies: Set<string>;
let contextual_dependencies: Set<string>;
// rewrite code as appropriate
walk(this.node, {
enter(node: any, parent: any, key: string) {
// don't manipulate shorthand props twice
if (key === 'value' && parent.shorthand) return;
code.addSourcemapLocation(node.start);
code.addSourcemapLocation(node.end);
if (map.has(node)) {
scope = map.get(node);
}
if (is_reference(node, parent)) {
const { name, nodes } = flatten_reference(node);
if (scope.has(name)) return;
if (globals.has(name) && !component.var_lookup.has(name)) return;
if (function_expression) {
if (template_scope.names.has(name)) {
contextual_dependencies.add(name);
template_scope.dependencies_for_name.get(name).forEach(dependency => {
dependencies.add(dependency);
});
} else {
dependencies.add(name);
component.add_reference(name); // TODO is this redundant/misplaced?
}
} else if (!is_synthetic && is_contextual(component, template_scope, name)) {
code.prependRight(node.start, key === 'key' && parent.shorthand
? `${name}: ctx.`
: 'ctx.');
}
if (node.type === 'MemberExpression') {
nodes.forEach(node => {
code.addSourcemapLocation(node.start);
code.addSourcemapLocation(node.end);
});
}
this.skip();
}
if (!function_expression) {
if (node.type === 'AssignmentExpression') {
// TODO should this be a warning/error? `<p>{foo = 1}</p>`
}
if (node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression') {
function_expression = node;
dependencies = new Set();
contextual_dependencies = new Set();
}
}
},
leave(node: Node, parent: Node) {
if (map.has(node)) scope = scope.parent;
if (node === function_expression) {
const id = component.get_unique_name(
sanitize(get_function_name(node, owner))
);
const args = contextual_dependencies.size > 0
? [`{ ${Array.from(contextual_dependencies).join(', ')} }`]
: [];
let original_params;
if (node.params.length > 0) {
original_params = code.slice(node.params[0].start, node.params[node.params.length - 1].end);
args.push(original_params);
}
const body = code.slice(node.body.start, node.body.end).trim();
const fn = node.type === 'FunctionExpression'
? b`${node.async ? 'async ' : ''}function${node.generator ? '*' : ''} ${id}(${args.join(', ')}) ${body}`
: b`const ${id} = ${node.async ? 'async ' : ''}(${args.join(', ')}) => ${body};`;
if (dependencies.size === 0 && contextual_dependencies.size === 0) {
// we can hoist this out of the component completely
component.fully_hoisted.push(fn);
code.overwrite(node.start, node.end, id.name);
component.add_var({
name: id.name,
internal: true,
hoistable: true,
referenced: true
});
}
else if (contextual_dependencies.size === 0) {
// function can be hoisted inside the component init
component.partly_hoisted.push(fn);
code.overwrite(node.start, node.end, `ctx.${id}`);
component.add_var({
name: id.name,
internal: true,
referenced: true
});
}
else {
// we need a combo block/init recipe
component.partly_hoisted.push(fn);
code.overwrite(node.start, node.end, id.name);
component.add_var({
name: id.name,
internal: true,
referenced: true
});
declarations.push(b`
function ${id}(${original_params ? '...args' : ''}) {
return ctx.${id}(ctx${original_params ? ', ...args' : ''});
}
`);
}
if (parent && parent.method) {
code.prependRight(node.start, ': ');
}
function_expression = null;
dependencies = null;
contextual_dependencies = null;
}
if (node.type === 'AssignmentExpression' || node.type === 'UpdateExpression') {
const assignee = node.type === 'AssignmentExpression' ? node.left : node.argument;
// normally (`a = 1`, `b.c = 2`), there'll be a single name
// (a or b). In destructuring cases (`[d, e] = [e, d]`) there
// may be more, in which case we need to tack the extra ones
// onto the initial function call
const names = new Set(extract_names(assignee));
const traced: Set<string> = new Set();
names.forEach(name => {
const dependencies = template_scope.dependencies_for_name.get(name);
if (dependencies) {
dependencies.forEach(name => traced.add(name));
} else {
traced.add(name);
}
});
invalidate(component, scope, code, node, traced);
}
}
});
if (declarations.length > 0) {
block.maintain_context = true;
declarations.forEach(declaration => {
block.chunks.init.push(declaration);
});
}
render(_block?: Block) {
// TODO
// if (this.rendered) return this.rendered;
// const {
// component,
// declarations,
// scope_map: map,
// template_scope,
// owner,
// is_synthetic
// } = this;
// let scope = this.scope;
// let function_expression;
// let dependencies: Set<string>;
// let contextual_dependencies: Set<string>;
// // rewrite code as appropriate
// walk(this.node, {
// enter(node: any, parent: any, key: string) {
// // don't manipulate shorthand props twice
// if (key === 'value' && parent.shorthand) return;
// if (map.has(node)) {
// scope = map.get(node);
// }
// if (is_reference(node, parent)) {
// const { name, nodes } = flatten_reference(node);
// if (scope.has(name)) return;
// if (globals.has(name) && !component.var_lookup.has(name)) return;
// if (function_expression) {
// if (template_scope.names.has(name)) {
// contextual_dependencies.add(name);
// template_scope.dependencies_for_name.get(name).forEach(dependency => {
// dependencies.add(dependency);
// });
// } else {
// dependencies.add(name);
// component.add_reference(name); // TODO is this redundant/misplaced?
// }
// } else if (!is_synthetic && is_contextual(component, template_scope, name)) {
// code.prependRight(node.start, key === 'key' && parent.shorthand
// ? `${name}: ctx.`
// : 'ctx.');
// }
// if (node.type === 'MemberExpression') {
// nodes.forEach(node => {
// code.addSourcemapLocation(node.start);
// code.addSourcemapLocation(node.end);
// });
// }
// this.skip();
// }
// if (!function_expression) {
// if (node.type === 'AssignmentExpression') {
// // TODO should this be a warning/error? `<p>{foo = 1}</p>`
// }
// if (node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression') {
// function_expression = node;
// dependencies = new Set();
// contextual_dependencies = new Set();
// }
// }
// },
// leave(node: Node, parent: Node) {
// if (map.has(node)) scope = scope.parent;
// if (node === function_expression) {
// const id = component.get_unique_name(
// sanitize(get_function_name(node, owner))
// );
// const args = contextual_dependencies.size > 0
// ? [`{ ${Array.from(contextual_dependencies).join(', ')} }`]
// : [];
// let original_params;
// if (node.params.length > 0) {
// original_params = code.slice(node.params[0].start, node.params[node.params.length - 1].end);
// args.push(original_params);
// }
// const body = code.slice(node.body.start, node.body.end).trim();
// const fn = node.type === 'FunctionExpression'
// ? b`${node.async ? 'async ' : ''}function${node.generator ? '*' : ''} ${id}(${args.join(', ')}) ${body}`
// : b`const ${id} = ${node.async ? 'async ' : ''}(${args.join(', ')}) => ${body};`;
// if (dependencies.size === 0 && contextual_dependencies.size === 0) {
// // we can hoist this out of the component completely
// component.fully_hoisted.push(fn);
// code.overwrite(node.start, node.end, id.name);
// component.add_var({
// name: id.name,
// internal: true,
// hoistable: true,
// referenced: true
// });
// }
// else if (contextual_dependencies.size === 0) {
// // function can be hoisted inside the component init
// component.partly_hoisted.push(fn);
// code.overwrite(node.start, node.end, `ctx.${id}`);
// component.add_var({
// name: id.name,
// internal: true,
// referenced: true
// });
// }
// else {
// // we need a combo block/init recipe
// component.partly_hoisted.push(fn);
// code.overwrite(node.start, node.end, id.name);
// component.add_var({
// name: id.name,
// internal: true,
// referenced: true
// });
// declarations.push(b`
// function ${id}(${original_params ? '...args' : ''}) {
// return ctx.${id}(ctx${original_params ? ', ...args' : ''});
// }
// `);
// }
// if (parent && parent.method) {
// code.prependRight(node.start, ': ');
// }
// function_expression = null;
// dependencies = null;
// contextual_dependencies = null;
// }
// if (node.type === 'AssignmentExpression' || node.type === 'UpdateExpression') {
// const assignee = node.type === 'AssignmentExpression' ? node.left : node.argument;
// // normally (`a = 1`, `b.c = 2`), there'll be a single name
// // (a or b). In destructuring cases (`[d, e] = [e, d]`) there
// // may be more, in which case we need to tack the extra ones
// // onto the initial function call
// const names = new Set(extract_names(assignee));
// const traced: Set<string> = new Set();
// names.forEach(name => {
// const dependencies = template_scope.dependencies_for_name.get(name);
// if (dependencies) {
// dependencies.forEach(name => traced.add(name));
// } else {
// traced.add(name);
// }
// });
// invalidate(component, scope, code, node, traced);
// }
// }
// });
// if (declarations.length > 0) {
// block.maintain_context = true;
// declarations.forEach(declaration => {
// block.chunks.init.push(declaration);
// });
// }
throw new Error(`bad`);
@ -417,29 +414,29 @@ export default class Expression {
}
}
function get_function_name(_node, parent) {
if (parent.type === 'EventHandler') {
return `${parent.name}_handler`;
}
// function get_function_name(_node, parent) {
// if (parent.type === 'EventHandler') {
// return `${parent.name}_handler`;
// }
if (parent.type === 'Action') {
return `${parent.name}_function`;
}
// if (parent.type === 'Action') {
// return `${parent.name}_function`;
// }
return 'func';
}
// return 'func';
// }
function is_contextual(component: Component, scope: TemplateScope, name: string) {
if (name === '$$props') return true;
// function is_contextual(component: Component, scope: TemplateScope, name: string) {
// if (name === '$$props') return true;
// if it's a name below root scope, it's contextual
if (!scope.is_top_level(name)) return true;
// // if it's a name below root scope, it's contextual
// if (!scope.is_top_level(name)) return true;
const variable = component.var_lookup.get(name);
// const variable = component.var_lookup.get(name);
// hoistables, module declarations, and imports are non-contextual
if (!variable || variable.hoistable) return false;
// // hoistables, module declarations, and imports are non-contextual
// if (!variable || variable.hoistable) return false;
// assume contextual
return true;
}
// // assume contextual
// return true;
// }

@ -14,7 +14,7 @@ export default function dom(
component: Component,
options: CompileOptions
) {
const { name, code } = component;
const { name } = component;
const renderer = new Renderer(component, options);
const { block } = renderer;
@ -198,7 +198,7 @@ export default function dom(
// onto the initial function call
const names = new Set(extract_names(assignee));
invalidate(component, scope, code, node, names);
invalidate(component, scope, node, names);
}
}
});

@ -2,7 +2,7 @@ import Renderer from '../Renderer';
import Wrapper from './shared/Wrapper';
import Block from '../Block';
import DebugTag from '../../nodes/DebugTag';
import add_to_set from '../../utils/add_to_set';
// import add_to_set from '../../utils/add_to_set';
import { b } from 'code-red';
export default class DebugTagWrapper extends Wrapper {
@ -21,11 +21,11 @@ export default class DebugTagWrapper extends Wrapper {
render(block: Block, _parent_node: string, _parent_nodes: string) {
const { renderer } = this;
const { component } = renderer;
// const { component } = renderer;
if (!renderer.options.dev) return;
const { var_lookup } = component;
// const { var_lookup } = component;
if (this.node.expressions.length === 0) {
// Debug all
@ -37,43 +37,45 @@ export default class DebugTagWrapper extends Wrapper {
block.chunks.create.push(b`debugger`);
block.chunks.update.push(b`debugger`);
} else {
const { code } = component;
code.overwrite(this.node.start + 1, this.node.start + 7, 'log', {
storeName: true
});
const log = `[✂${this.node.start + 1}-${this.node.start + 7}✂]`;
// TODO
const dependencies = new Set();
this.node.expressions.forEach(expression => {
add_to_set(dependencies, expression.dependencies);
});
// const { code } = component;
// code.overwrite(this.node.start + 1, this.node.start + 7, 'log', {
// storeName: true
// });
// const log = `[✂${this.node.start + 1}-${this.node.start + 7}✂]`;
// const dependencies = new Set();
// this.node.expressions.forEach(expression => {
// add_to_set(dependencies, expression.dependencies);
// });
const condition = Array.from(dependencies).map(d => `changed.${d}`).join(' || ');
// const condition = Array.from(dependencies).map(d => `changed.${d}`).join(' || ');
const ctx_identifiers = this.node.expressions
.filter(e => {
const looked_up_var = var_lookup.get(e.node.name);
return !(looked_up_var && looked_up_var.hoistable);
})
.map(e => e.node.name)
.join(', ');
const logged_identifiers = this.node.expressions.map(e => e.node.name).join(', ');
// const ctx_identifiers = this.node.expressions
// .filter(e => {
// const looked_up_var = var_lookup.get(e.node.name);
// return !(looked_up_var && looked_up_var.hoistable);
// })
// .map(e => e.node.name)
// .join(', ');
// const logged_identifiers = this.node.expressions.map(e => e.node.name).join(', ');
block.chunks.update.push(b`
if (${condition}) {
const { ${ctx_identifiers} } = ctx;
@_console.${log}({ ${logged_identifiers} });
debugger;
}
`);
// block.chunks.update.push(b`
// if (${condition}) {
// const { ${ctx_identifiers} } = ctx;
// @_console.${log}({ ${logged_identifiers} });
// debugger;
// }
// `);
block.chunks.create.push(b`
{
const { ${ctx_identifiers} } = ctx;
@_console.${log}({ ${logged_identifiers} });
debugger;
}
`);
// block.chunks.create.push(b`
// {
// const { ${ctx_identifiers} } = ctx;
// @_console.${log}({ ${logged_identifiers} });
// debugger;
// }
// `);
}
}
}

@ -104,11 +104,12 @@ export default class EachBlockWrapper extends Wrapper {
? node.expression.node.elements.length
: null;
// TODO
// hack the sourcemap, so that if data is missing the bug
// is easy to find
let c = this.node.start + 2;
while (renderer.component.source[c] !== 'e') c += 1;
renderer.component.code.overwrite(c, c + 4, 'length');
// renderer.component.code.overwrite(c, c + 4, 'length');
const each_block_value = renderer.component.get_unique_name(`${this.var}_value`);
const iterations = block.get_unique_name(`${this.var}_blocks`);

@ -18,7 +18,7 @@ export default class MustacheTagWrapper extends Tag {
render(block: Block, parent_node: string, parent_nodes: string) {
const { init } = this.rename_this_method(
block,
value => `@set_data(${this.var}, ${value});`
value => x`@set_data(${this.var}, ${value});`
);
block.add_element(

@ -46,7 +46,7 @@ export default class RawMustacheTagWrapper extends Tag {
const { init } = this.rename_this_method(
block,
content => `${html_tag}.p(${content});`
content => x`${html_tag}.p(${content});`
);
const update_anchor = in_head ? 'null' : needs_anchor ? html_anchor : this.next ? this.next.var : 'null';

@ -4,6 +4,7 @@ import Renderer from '../../Renderer';
import Block from '../../Block';
import MustacheTag from '../../../nodes/MustacheTag';
import RawMustacheTag from '../../../nodes/RawMustacheTag';
import { Node } from '../../../../interfaces';
export default class Tag extends Wrapper {
node: MustacheTag | RawMustacheTag;
@ -17,7 +18,7 @@ export default class Tag extends Wrapper {
rename_this_method(
block: Block,
update: ((value: string) => string)
update: ((value: Node) => Node)
) {
const dependencies = this.node.expression.dynamic_dependencies();
const snippet = this.node.expression.node;

@ -1,66 +1,67 @@
import Component from '../Component';
import MagicString from 'magic-string';
import { Node } from '../../interfaces';
import { nodes_match } from '../../utils/nodes_match';
// import { nodes_match } from '../../utils/nodes_match';
import { Scope } from './scope';
export function invalidate(component: Component, scope: Scope, code: MagicString, node: Node, names: Set<string>) {
const [head, ...tail] = Array.from(names).filter(name => {
const owner = scope.find_owner(name);
if (owner && owner !== component.instance_scope) return false;
export function invalidate(_component: Component, _scope: Scope, _node: Node, _names: Set<string>) {
// const [head, ...tail] = Array.from(names).filter(name => {
// const owner = scope.find_owner(name);
// if (owner && owner !== component.instance_scope) return false;
const variable = component.var_lookup.get(name);
// const variable = component.var_lookup.get(name);
return variable && (
!variable.hoistable &&
!variable.global &&
!variable.module &&
(
variable.referenced ||
variable.is_reactive_dependency ||
variable.export_name ||
variable.name[0] === '$'
)
);
});
// return variable && (
// !variable.hoistable &&
// !variable.global &&
// !variable.module &&
// (
// variable.referenced ||
// variable.is_reactive_dependency ||
// variable.export_name ||
// variable.name[0] === '$'
// )
// );
// });
if (head) {
component.has_reactive_assignments = true;
// TODO
if (node.operator === '=' && nodes_match(node.left, node.right) && tail.length === 0) {
code.overwrite(node.start, node.end, component.invalidate(head));
} else {
let suffix = ')';
// if (head) {
// component.has_reactive_assignments = true;
if (head[0] === '$') {
code.prependRight(node.start, `${component.helper('set_store_value')}(${head.slice(1)}, `);
} else {
let prefix = `$$invalidate`;
// if (node.operator === '=' && nodes_match(node.left, node.right) && tail.length === 0) {
// code.overwrite(node.start, node.end, component.invalidate(head));
// } else {
// let suffix = ')';
const variable = component.var_lookup.get(head);
if (variable.subscribable && variable.reassigned) {
prefix = `$$subscribe_${head}($$invalidate`;
suffix += `)`;
}
// if (head[0] === '$') {
// code.prependRight(node.start, `${component.helper('set_store_value')}(${head.slice(1)}, `);
// } else {
// let prefix = `$$invalidate`;
code.prependRight(node.start, `${prefix}('${head}', `);
}
// const variable = component.var_lookup.get(head);
// if (variable.subscribable && variable.reassigned) {
// prefix = `$$subscribe_${head}($$invalidate`;
// suffix += `)`;
// }
const extra_args = tail.map(name => component.invalidate(name));
// code.prependRight(node.start, `${prefix}('${head}', `);
// }
const pass_value = (
extra_args.length > 0 ||
(node.type === 'AssignmentExpression' && node.left.type !== 'Identifier') ||
(node.type === 'UpdateExpression' && !node.prefix)
);
// const extra_args = tail.map(name => component.invalidate(name));
if (pass_value) {
extra_args.unshift(head);
}
// const pass_value = (
// extra_args.length > 0 ||
// (node.type === 'AssignmentExpression' && node.left.type !== 'Identifier') ||
// (node.type === 'UpdateExpression' && !node.prefix)
// );
suffix = `${extra_args.map(arg => `, ${arg}`).join('')}${suffix}`;
// if (pass_value) {
// extra_args.unshift(head);
// }
code.appendLeft(node.end, suffix);
}
}
// suffix = `${extra_args.map(arg => `, ${arg}`).join('')}${suffix}`;
// code.appendLeft(node.end, suffix);
// }
// }
}

@ -1,57 +0,0 @@
import MagicString from 'magic-string';
import { Node } from '../interfaces';
import { walk } from 'estree-walker';
import repeat from './repeat';
export function remove_indentation(code: MagicString, node: Node) {
const indent = code.getIndentString();
const pattern = new RegExp(`^${indent}`, 'gm');
const excluded = [];
walk(node, {
enter(node) {
if (node.type === 'TemplateElement') {
excluded.push(node);
}
}
});
const str = code.original.slice(node.start, node.end);
let match;
while (match = pattern.exec(str)) {
const index = node.start + match.index;
while (excluded[0] && excluded[0].end < index) excluded.shift();
if (excluded[0] && excluded[0].start < index) continue;
code.remove(index, index + indent.length);
}
}
export function add_indentation(code: MagicString, node: Node, levels = 1) {
const base_indent = code.getIndentString();
const indent = repeat(base_indent, levels);
const pattern = /\n/gm;
const excluded = [];
walk(node, {
enter(node) {
if (node.type === 'TemplateElement') {
excluded.push(node);
}
}
});
const str = code.original.slice(node.start, node.end);
let match;
while (match = pattern.exec(str)) {
const index = node.start + match.index;
while (excluded[0] && excluded[0].end < index) excluded.shift();
if (excluded[0] && excluded[0].start < index) continue;
code.appendLeft(index + 1, indent);
}
}

@ -1,5 +1,5 @@
<script>
let name = 'world';
export let name = 'world';
</script>
<h1>Hello {name}!</h1>
Loading…
Cancel
Save