trace dependencies where possible

pull/1864/head
Rich Harris 7 years ago
parent b33f2d8660
commit 05a4f5d7c8

@ -16,6 +16,7 @@ import error from '../utils/error';
import getCodeFrame from '../utils/getCodeFrame'; import getCodeFrame from '../utils/getCodeFrame';
import flattenReference from '../utils/flattenReference'; import flattenReference from '../utils/flattenReference';
import addToSet from '../utils/addToSet'; import addToSet from '../utils/addToSet';
import isReference from 'is-reference';
type Meta = { type Meta = {
namespace?: string; namespace?: string;
@ -51,7 +52,8 @@ export default class Component {
name: string; name: string;
options: CompileOptions; options: CompileOptions;
fragment: Fragment; fragment: Fragment;
scope: Scope; module_scope: Scope;
module_scope_map: WeakMap<Node, Scope>;
meta: Meta; meta: Meta;
@ -379,8 +381,59 @@ export default class Component {
} }
findDependenciesForFunctionCall(name) { findDependenciesForFunctionCall(name) {
// TODO const declaration = this.node_for_declaration.get(name);
return null;
const dependencies = new Set();
if (!declaration) {
// Global or module-scoped function — can't have
// local state as dependency by definition
return dependencies;
}
let { module_scope, module_scope_map: map } = this;
let scope = module_scope;
const component = this;
let bail = false;
walk(declaration, {
enter(node, parent) {
if (map.has(node)) {
scope = map.get(node);
}
if (isReference(node, parent)) {
const { name } = flattenReference(node);
if (scope.findOwner(name) === module_scope) {
dependencies.add(name);
}
}
if (node.type === 'CallExpression') {
if (node.callee.type === 'Identifier') {
const call_dependencies = component.findDependenciesForFunctionCall(node.callee.name);
if (!call_dependencies) {
bail = true;
return this.skip();
}
addToSet(dependencies, call_dependencies);
} else {
bail = true;
return this.skip();
}
}
},
leave(node) {
if (map.has(node)) {
scope = map.get(node);
}
}
});
return bail ? null : dependencies;
} }
extract_imports_and_exports(content, imports, exports) { extract_imports_and_exports(content, imports, exports) {
@ -448,6 +501,11 @@ export default class Component {
this.addSourcemapLocations(script.content); this.addSourcemapLocations(script.content);
// const { scope, map, globals } = createScopes(script.content);
// scope.declarations.forEach((node, name) => {
// this.node_for_declaration.set(name, node);
// });
// TODO unindent // TODO unindent
this.extract_imports_and_exports(script.content, this.imports, this.module_exports); this.extract_imports_and_exports(script.content, this.imports, this.module_exports);
@ -471,11 +529,14 @@ export default class Component {
}); });
let { scope, map, globals } = createScopes(script.content); let { scope, map, globals } = createScopes(script.content);
this.scope = scope; this.module_scope = scope;
this.module_scope_map = map;
scope.declarations.forEach(name => { scope.declarations.forEach((node, name) => {
this.userVars.add(name); this.userVars.add(name);
this.declarations.push(name); this.declarations.push(name);
this.node_for_declaration.set(name, node);
}); });
this.writable_declarations = scope.writable_declarations; this.writable_declarations = scope.writable_declarations;

@ -12,18 +12,18 @@ export function createScopes(expression: Node) {
enter(node: Node, parent: Node) { enter(node: Node, parent: Node) {
if (/Function/.test(node.type)) { if (/Function/.test(node.type)) {
if (node.type === 'FunctionDeclaration') { if (node.type === 'FunctionDeclaration') {
scope.declarations.add(node.id.name); scope.declarations.set(node.id.name, node);
scope = new Scope(scope, false); scope = new Scope(scope, false);
map.set(node, scope); map.set(node, scope);
} else { } else {
scope = new Scope(scope, false); scope = new Scope(scope, false);
map.set(node, scope); map.set(node, scope);
if (node.id) scope.declarations.add(node.id.name); if (node.id) scope.declarations.set(node.id.name, node);
} }
node.params.forEach((param: Node) => { node.params.forEach((param: Node) => {
extractNames(param).forEach(name => { extractNames(param).forEach(name => {
scope.declarations.add(name); scope.declarations.set(name, node);
}); });
}); });
} else if (/For(?:In|Of)Statement/.test(node.type)) { } else if (/For(?:In|Of)Statement/.test(node.type)) {
@ -55,7 +55,7 @@ export class Scope {
parent: Scope; parent: Scope;
block: boolean; block: boolean;
declarations: Set<string> = new Set(); declarations: Map<string, Node> = new Map();
writable_declarations: Set<string> = new Set(); writable_declarations: Set<string> = new Set();
initialised_declarations: Set<string> = new Set(); initialised_declarations: Set<string> = new Set();
@ -73,13 +73,13 @@ export class Scope {
node.declarations.forEach((declarator: Node) => { node.declarations.forEach((declarator: Node) => {
extractNames(declarator.id).forEach(name => { extractNames(declarator.id).forEach(name => {
this.declarations.add(name); this.declarations.set(name, node);
if (writable) this.writable_declarations.add(name); if (writable) this.writable_declarations.add(name);
if (initialised) this.initialised_declarations.add(name); if (initialised) this.initialised_declarations.add(name);
}); });
}); });
} else { } else {
this.declarations.add(node.id.name); this.declarations.set(node.id.name, node);
} }
} }

Loading…
Cancel
Save