|
|
@ -15,7 +15,6 @@ import { Node, Ast, CompileOptions, Var } from '../interfaces';
|
|
|
|
import error from '../utils/error';
|
|
|
|
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 isReference from 'is-reference';
|
|
|
|
import isReference from 'is-reference';
|
|
|
|
import TemplateScope from './nodes/shared/TemplateScope';
|
|
|
|
import TemplateScope from './nodes/shared/TemplateScope';
|
|
|
|
import fuzzymatch from '../utils/fuzzymatch';
|
|
|
|
import fuzzymatch from '../utils/fuzzymatch';
|
|
|
@ -65,7 +64,6 @@ export default class Component {
|
|
|
|
|
|
|
|
|
|
|
|
declarations: string[] = [];
|
|
|
|
declarations: string[] = [];
|
|
|
|
imported_declarations: Set<string> = new Set();
|
|
|
|
imported_declarations: Set<string> = new Set();
|
|
|
|
hoistable_names: Set<string> = new Set();
|
|
|
|
|
|
|
|
hoistable_nodes: Set<Node> = new Set();
|
|
|
|
hoistable_nodes: Set<Node> = new Set();
|
|
|
|
node_for_declaration: Map<string, Node> = new Map();
|
|
|
|
node_for_declaration: Map<string, Node> = new Map();
|
|
|
|
partly_hoisted: string[] = [];
|
|
|
|
partly_hoisted: string[] = [];
|
|
|
@ -148,20 +146,25 @@ export default class Component {
|
|
|
|
const props = [...this.template_references];
|
|
|
|
const props = [...this.template_references];
|
|
|
|
this.declarations.push(...props);
|
|
|
|
this.declarations.push(...props);
|
|
|
|
|
|
|
|
|
|
|
|
props.forEach(name => {
|
|
|
|
// props.forEach(name => {
|
|
|
|
this.add_var({
|
|
|
|
// this.add_var({
|
|
|
|
name,
|
|
|
|
// name,
|
|
|
|
kind: 'injected',
|
|
|
|
// kind: 'injected',
|
|
|
|
exported_as: name,
|
|
|
|
// export_name: name,
|
|
|
|
mutated: true, // TODO kind of a misnomer... it's *mutable* but not necessarily *mutated*. is that a problem?
|
|
|
|
// mutated: true, // TODO kind of a misnomer... it's *mutable* but not necessarily *mutated*. is that a problem?
|
|
|
|
referenced: true,
|
|
|
|
// referenced: true,
|
|
|
|
writable: true
|
|
|
|
// writable: true
|
|
|
|
});
|
|
|
|
// });
|
|
|
|
});
|
|
|
|
// });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
add_var(variable: Var) {
|
|
|
|
add_var(variable: Var) {
|
|
|
|
|
|
|
|
// TODO remove this
|
|
|
|
|
|
|
|
if (this.var_lookup.has(variable.name)) {
|
|
|
|
|
|
|
|
throw new Error(`dupe: ${variable.name}`);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
this.vars.push(variable);
|
|
|
|
this.vars.push(variable);
|
|
|
|
this.var_lookup.set(variable.name, variable);
|
|
|
|
this.var_lookup.set(variable.name, variable);
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -171,13 +174,21 @@ export default class Component {
|
|
|
|
|
|
|
|
|
|
|
|
if (variable) {
|
|
|
|
if (variable) {
|
|
|
|
variable.referenced = true;
|
|
|
|
variable.referenced = true;
|
|
|
|
} else if (!this.ast.instance || name[0] === '$') {
|
|
|
|
} else if (name[0] === '$') {
|
|
|
|
this.add_var({
|
|
|
|
this.add_var({
|
|
|
|
name,
|
|
|
|
name,
|
|
|
|
kind: 'injected',
|
|
|
|
kind: 'injected',
|
|
|
|
|
|
|
|
referenced: true,
|
|
|
|
|
|
|
|
mutated: true
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
} else if (!this.ast.instance) {
|
|
|
|
|
|
|
|
this.add_var({
|
|
|
|
|
|
|
|
name,
|
|
|
|
|
|
|
|
export_name: name,
|
|
|
|
|
|
|
|
kind: 'injected',
|
|
|
|
mutated: true,
|
|
|
|
mutated: true,
|
|
|
|
referenced: true,
|
|
|
|
referenced: true,
|
|
|
|
writable: name[0] !== '$'
|
|
|
|
writable: true
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -241,9 +252,9 @@ export default class Component {
|
|
|
|
options.sveltePath,
|
|
|
|
options.sveltePath,
|
|
|
|
importedHelpers,
|
|
|
|
importedHelpers,
|
|
|
|
this.imports,
|
|
|
|
this.imports,
|
|
|
|
this.vars.filter(variable => variable.module && variable.exported_as).map(variable => ({
|
|
|
|
this.vars.filter(variable => variable.module && variable.export_name).map(variable => ({
|
|
|
|
name: variable.name,
|
|
|
|
name: variable.name,
|
|
|
|
as: variable.exported_as
|
|
|
|
as: variable.export_name
|
|
|
|
})),
|
|
|
|
})),
|
|
|
|
this.source
|
|
|
|
this.source
|
|
|
|
);
|
|
|
|
);
|
|
|
@ -414,25 +425,19 @@ export default class Component {
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const imported_as = specifier.imported
|
|
|
|
const import_name = specifier.imported
|
|
|
|
? specifier.imported.name
|
|
|
|
? specifier.imported.name
|
|
|
|
: specifier.type === 'ImportDefaultSpecifier'
|
|
|
|
: specifier.type === 'ImportDefaultSpecifier'
|
|
|
|
? 'default'
|
|
|
|
? 'default'
|
|
|
|
: '*';
|
|
|
|
: '*';
|
|
|
|
|
|
|
|
|
|
|
|
const import_type = specifier.type === 'ImportSpecifier'
|
|
|
|
|
|
|
|
? 'named'
|
|
|
|
|
|
|
|
: specifier.type === 'ImportDefaultSpecifier'
|
|
|
|
|
|
|
|
? 'default'
|
|
|
|
|
|
|
|
: 'namespace';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.add_var({
|
|
|
|
this.add_var({
|
|
|
|
name: specifier.local.name,
|
|
|
|
name: specifier.local.name,
|
|
|
|
kind: 'import',
|
|
|
|
kind: 'import',
|
|
|
|
imported_as,
|
|
|
|
import_name,
|
|
|
|
import_type,
|
|
|
|
|
|
|
|
source: node.source.value,
|
|
|
|
source: node.source.value,
|
|
|
|
module: is_module,
|
|
|
|
module: is_module,
|
|
|
|
|
|
|
|
hoistable: true
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
this.imported_declarations.add(specifier.local.name);
|
|
|
|
this.imported_declarations.add(specifier.local.name);
|
|
|
@ -459,15 +464,9 @@ export default class Component {
|
|
|
|
if (node.declaration.type === 'VariableDeclaration') {
|
|
|
|
if (node.declaration.type === 'VariableDeclaration') {
|
|
|
|
node.declaration.declarations.forEach(declarator => {
|
|
|
|
node.declaration.declarations.forEach(declarator => {
|
|
|
|
extractNames(declarator.id).forEach(name => {
|
|
|
|
extractNames(declarator.id).forEach(name => {
|
|
|
|
this.add_var({
|
|
|
|
const variable = this.var_lookup.get(name);
|
|
|
|
name,
|
|
|
|
variable.export_name = name;
|
|
|
|
kind,
|
|
|
|
if (kind !== 'const') variable.mutated = true;
|
|
|
|
exported_as: name,
|
|
|
|
|
|
|
|
module: is_module,
|
|
|
|
|
|
|
|
mutated: !is_module,
|
|
|
|
|
|
|
|
writable: kind === 'let' || kind === 'var',
|
|
|
|
|
|
|
|
initialised: !!declarator.init
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
@ -482,14 +481,8 @@ export default class Component {
|
|
|
|
// sanity check
|
|
|
|
// sanity check
|
|
|
|
if (!kind) throw new Error(`Unknown declaration type ${node.declaration.type}`);
|
|
|
|
if (!kind) throw new Error(`Unknown declaration type ${node.declaration.type}`);
|
|
|
|
|
|
|
|
|
|
|
|
this.add_var({
|
|
|
|
const variable = this.var_lookup.get(name);
|
|
|
|
name,
|
|
|
|
variable.export_name = name;
|
|
|
|
kind,
|
|
|
|
|
|
|
|
exported_as: name,
|
|
|
|
|
|
|
|
module: is_module,
|
|
|
|
|
|
|
|
mutated: !is_module,
|
|
|
|
|
|
|
|
initialised: true
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
code.remove(node.start, node.declaration.start);
|
|
|
|
code.remove(node.start, node.declaration.start);
|
|
|
@ -499,7 +492,7 @@ export default class Component {
|
|
|
|
const variable = this.var_lookup.get(specifier.local.name);
|
|
|
|
const variable = this.var_lookup.get(specifier.local.name);
|
|
|
|
|
|
|
|
|
|
|
|
if (variable) {
|
|
|
|
if (variable) {
|
|
|
|
variable.exported_as = specifier.exported.name;
|
|
|
|
variable.export_name = specifier.exported.name;
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
// TODO what happens with `export { Math }` or some other global?
|
|
|
|
// TODO what happens with `export { Math }` or some other global?
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -577,7 +570,8 @@ export default class Component {
|
|
|
|
|
|
|
|
|
|
|
|
this.add_var({
|
|
|
|
this.add_var({
|
|
|
|
name,
|
|
|
|
name,
|
|
|
|
kind
|
|
|
|
kind,
|
|
|
|
|
|
|
|
module: true
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
this.declarations.push(name);
|
|
|
|
this.declarations.push(name);
|
|
|
@ -623,7 +617,8 @@ export default class Component {
|
|
|
|
this.add_var({
|
|
|
|
this.add_var({
|
|
|
|
name,
|
|
|
|
name,
|
|
|
|
kind,
|
|
|
|
kind,
|
|
|
|
initialised: instance_scope.initialised_declarations.has(name)
|
|
|
|
initialised: instance_scope.initialised_declarations.has(name),
|
|
|
|
|
|
|
|
writable: kind === 'var' || kind === 'let'
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
this.declarations.push(name);
|
|
|
|
this.declarations.push(name);
|
|
|
@ -633,6 +628,8 @@ export default class Component {
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
globals.forEach(name => {
|
|
|
|
globals.forEach(name => {
|
|
|
|
|
|
|
|
if (this.module_scope && this.module_scope.declarations.has(name)) return;
|
|
|
|
|
|
|
|
|
|
|
|
this.add_var({
|
|
|
|
this.add_var({
|
|
|
|
name,
|
|
|
|
name,
|
|
|
|
kind: 'global'
|
|
|
|
kind: 'global'
|
|
|
@ -756,7 +753,7 @@ export default class Component {
|
|
|
|
const variable = component.var_lookup.get(name);
|
|
|
|
const variable = component.var_lookup.get(name);
|
|
|
|
|
|
|
|
|
|
|
|
if (name === meta.props_object) {
|
|
|
|
if (name === meta.props_object) {
|
|
|
|
if (variable.exported_as) {
|
|
|
|
if (variable.export_name) {
|
|
|
|
component.error(declarator, {
|
|
|
|
component.error(declarator, {
|
|
|
|
code: 'exported-meta-props',
|
|
|
|
code: 'exported-meta-props',
|
|
|
|
message: `Cannot export props binding`
|
|
|
|
message: `Cannot export props binding`
|
|
|
@ -777,7 +774,7 @@ export default class Component {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (variable.exported_as) {
|
|
|
|
if (variable.export_name) {
|
|
|
|
has_exports = true;
|
|
|
|
has_exports = true;
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
has_only_exports = false;
|
|
|
|
has_only_exports = false;
|
|
|
@ -861,7 +858,7 @@ export default class Component {
|
|
|
|
// reference instance variables other than other
|
|
|
|
// reference instance variables other than other
|
|
|
|
// hoistable functions. TODO others?
|
|
|
|
// hoistable functions. TODO others?
|
|
|
|
|
|
|
|
|
|
|
|
const { hoistable_names, hoistable_nodes, imported_declarations, var_lookup } = this;
|
|
|
|
const { hoistable_nodes, imported_declarations, var_lookup } = this;
|
|
|
|
|
|
|
|
|
|
|
|
const top_level_function_declarations = new Map();
|
|
|
|
const top_level_function_declarations = new Map();
|
|
|
|
|
|
|
|
|
|
|
@ -871,7 +868,6 @@ export default class Component {
|
|
|
|
node.declarations.forEach(d => {
|
|
|
|
node.declarations.forEach(d => {
|
|
|
|
const variable = this.var_lookup.get(d.id.name);
|
|
|
|
const variable = this.var_lookup.get(d.id.name);
|
|
|
|
variable.hoistable = true;
|
|
|
|
variable.hoistable = true;
|
|
|
|
hoistable_names.add(d.id.name);
|
|
|
|
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
hoistable_nodes.add(node);
|
|
|
|
hoistable_nodes.add(node);
|
|
|
@ -924,7 +920,6 @@ export default class Component {
|
|
|
|
|
|
|
|
|
|
|
|
const variable = var_lookup.get(name);
|
|
|
|
const variable = var_lookup.get(name);
|
|
|
|
if (variable.hoistable) return;
|
|
|
|
if (variable.hoistable) return;
|
|
|
|
if (imported_declarations.has(name)) return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (top_level_function_declarations.has(name)) {
|
|
|
|
if (top_level_function_declarations.has(name)) {
|
|
|
|
const other_declaration = top_level_function_declarations.get(name);
|
|
|
|
const other_declaration = top_level_function_declarations.get(name);
|
|
|
@ -962,7 +957,6 @@ export default class Component {
|
|
|
|
if (!checked.has(node) && is_hoistable(node)) {
|
|
|
|
if (!checked.has(node) && is_hoistable(node)) {
|
|
|
|
const variable = this.var_lookup.get(name);
|
|
|
|
const variable = this.var_lookup.get(name);
|
|
|
|
variable.hoistable = true;
|
|
|
|
variable.hoistable = true;
|
|
|
|
hoistable_names.add(name);
|
|
|
|
|
|
|
|
hoistable_nodes.add(node);
|
|
|
|
hoistable_nodes.add(node);
|
|
|
|
|
|
|
|
|
|
|
|
remove_indentation(this.code, node);
|
|
|
|
remove_indentation(this.code, node);
|
|
|
@ -1086,7 +1080,6 @@ export default class Component {
|
|
|
|
qualify(name) {
|
|
|
|
qualify(name) {
|
|
|
|
const variable = this.var_lookup.get(name);
|
|
|
|
const variable = this.var_lookup.get(name);
|
|
|
|
if (variable && variable.hoistable) return name;
|
|
|
|
if (variable && variable.hoistable) return name;
|
|
|
|
if (this.imported_declarations.has(name)) return name;
|
|
|
|
|
|
|
|
if (this.declarations.indexOf(name) === -1) return name;
|
|
|
|
if (this.declarations.indexOf(name) === -1) return name;
|
|
|
|
|
|
|
|
|
|
|
|
this.add_reference(name); // TODO we can probably remove most other occurrences of this
|
|
|
|
this.add_reference(name); // TODO we can probably remove most other occurrences of this
|
|
|
|