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 flattenReference from '../utils/flattenReference';
import addToSet from '../utils/addToSet';
import isReference from 'is-reference';
type Meta = {
namespace?: string;
@ -51,7 +52,8 @@ export default class Component {
name: string;
options: CompileOptions;
fragment: Fragment;
scope: Scope;
module_scope: Scope;
module_scope_map: WeakMap<Node, Scope>;
meta: Meta;
@ -379,8 +381,59 @@ export default class Component {
}
findDependenciesForFunctionCall(name) {
// TODO
return null;
const declaration = this.node_for_declaration.get(name);
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) {
@ -448,6 +501,11 @@ export default class Component {
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
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);
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.declarations.push(name);
this.node_for_declaration.set(name, node);
});
this.writable_declarations = scope.writable_declarations;

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

Loading…
Cancel
Save