|
|
|
@ -11,7 +11,7 @@ import Stylesheet from './css/Stylesheet';
|
|
|
|
|
import { test } from '../config';
|
|
|
|
|
import Fragment from './nodes/Fragment';
|
|
|
|
|
import internal_exports from './internal-exports';
|
|
|
|
|
import { Node, Ast, CompileOptions, Var } from '../interfaces';
|
|
|
|
|
import { Node, Ast, CompileOptions, Var, Warning } from '../interfaces';
|
|
|
|
|
import error from '../utils/error';
|
|
|
|
|
import getCodeFrame from '../utils/getCodeFrame';
|
|
|
|
|
import flattenReference from '../utils/flattenReference';
|
|
|
|
@ -40,6 +40,7 @@ childKeys.ExportNamedDeclaration = ['declaration', 'specifiers'];
|
|
|
|
|
|
|
|
|
|
export default class Component {
|
|
|
|
|
stats: Stats;
|
|
|
|
|
warnings: Warning[];
|
|
|
|
|
|
|
|
|
|
ast: Ast;
|
|
|
|
|
source: string;
|
|
|
|
@ -93,11 +94,13 @@ export default class Component {
|
|
|
|
|
source: string,
|
|
|
|
|
name: string,
|
|
|
|
|
compileOptions: CompileOptions,
|
|
|
|
|
stats: Stats
|
|
|
|
|
stats: Stats,
|
|
|
|
|
warnings: Warning[]
|
|
|
|
|
) {
|
|
|
|
|
this.name = name;
|
|
|
|
|
|
|
|
|
|
this.stats = stats;
|
|
|
|
|
this.warnings = warnings;
|
|
|
|
|
this.ast = ast;
|
|
|
|
|
this.source = source;
|
|
|
|
|
this.compileOptions = compileOptions;
|
|
|
|
@ -161,7 +164,7 @@ export default class Component {
|
|
|
|
|
|
|
|
|
|
if (!compileOptions.customElement) this.stylesheet.reify();
|
|
|
|
|
|
|
|
|
|
this.stylesheet.warnOnUnusedSelectors(stats);
|
|
|
|
|
this.stylesheet.warnOnUnusedSelectors(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
add_var(variable: Var) {
|
|
|
|
@ -183,7 +186,11 @@ export default class Component {
|
|
|
|
|
writable: true
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
this.add_reference(name.slice(1));
|
|
|
|
|
const subscribable_name = name.slice(1);
|
|
|
|
|
this.add_reference(subscribable_name);
|
|
|
|
|
|
|
|
|
|
const variable = this.var_lookup.get(subscribable_name);
|
|
|
|
|
variable.subscribable = true;
|
|
|
|
|
} else if (!this.ast.instance) {
|
|
|
|
|
this.add_var({
|
|
|
|
|
name,
|
|
|
|
@ -213,7 +220,16 @@ export default class Component {
|
|
|
|
|
return this.aliases.get(name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
helper(name: string) {
|
|
|
|
|
this.helpers.add(name);
|
|
|
|
|
return this.alias(name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
generate(result: string) {
|
|
|
|
|
let js = null;
|
|
|
|
|
let css = null;
|
|
|
|
|
|
|
|
|
|
if (result) {
|
|
|
|
|
const { compileOptions, name } = this;
|
|
|
|
|
const { format = 'esm' } = compileOptions;
|
|
|
|
|
|
|
|
|
@ -296,23 +312,35 @@ export default class Component {
|
|
|
|
|
|
|
|
|
|
addString(finalChunk);
|
|
|
|
|
|
|
|
|
|
const css = compileOptions.customElement ?
|
|
|
|
|
css = compileOptions.customElement ?
|
|
|
|
|
{ code: null, map: null } :
|
|
|
|
|
this.stylesheet.render(compileOptions.cssOutputFilename, true);
|
|
|
|
|
|
|
|
|
|
const js = {
|
|
|
|
|
js = {
|
|
|
|
|
code: compiled.toString(),
|
|
|
|
|
map: compiled.generateMap({
|
|
|
|
|
includeContent: true,
|
|
|
|
|
file: compileOptions.outputFilename,
|
|
|
|
|
})
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
ast: this.ast,
|
|
|
|
|
js,
|
|
|
|
|
css,
|
|
|
|
|
stats: this.stats.render(this)
|
|
|
|
|
ast: this.ast,
|
|
|
|
|
warnings: this.warnings,
|
|
|
|
|
vars: this.vars.filter(v => !v.global && !v.implicit && !v.internal).map(v => ({
|
|
|
|
|
name: v.name,
|
|
|
|
|
export_name: v.export_name || null,
|
|
|
|
|
injected: v.injected || false,
|
|
|
|
|
module: v.module || false,
|
|
|
|
|
mutated: v.mutated || false,
|
|
|
|
|
reassigned: v.reassigned || false,
|
|
|
|
|
referenced: v.referenced || false,
|
|
|
|
|
writable: v.writable || false
|
|
|
|
|
})),
|
|
|
|
|
stats: this.stats.render()
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -393,7 +421,7 @@ export default class Component {
|
|
|
|
|
|
|
|
|
|
const frame = getCodeFrame(this.source, start.line - 1, start.column);
|
|
|
|
|
|
|
|
|
|
this.stats.warn({
|
|
|
|
|
this.warnings.push({
|
|
|
|
|
code: warning.code,
|
|
|
|
|
message: warning.message,
|
|
|
|
|
frame,
|
|
|
|
@ -641,6 +669,9 @@ export default class Component {
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
this.add_reference(name.slice(1));
|
|
|
|
|
|
|
|
|
|
const variable = this.var_lookup.get(name.slice(1));
|
|
|
|
|
variable.subscribable = true;
|
|
|
|
|
} else {
|
|
|
|
|
this.add_var({
|
|
|
|
|
name,
|
|
|
|
@ -738,7 +769,15 @@ export default class Component {
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rewrite_props() {
|
|
|
|
|
invalidate(name, value = name) {
|
|
|
|
|
const variable = this.var_lookup.get(name);
|
|
|
|
|
if (variable && (variable.subscribable && variable.reassigned)) {
|
|
|
|
|
return `$$subscribe_${name}(), $$invalidate('${name}', ${value})`;
|
|
|
|
|
}
|
|
|
|
|
return `$$invalidate('${name}', ${value})`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rewrite_props(get_insert: (variable: Var) => string) {
|
|
|
|
|
const component = this;
|
|
|
|
|
const { code, instance_scope, instance_scope_map: map, componentOptions } = this;
|
|
|
|
|
let scope = instance_scope;
|
|
|
|
@ -759,32 +798,52 @@ export default class Component {
|
|
|
|
|
|
|
|
|
|
if (node.type === 'VariableDeclaration') {
|
|
|
|
|
if (node.kind === 'var' || scope === instance_scope) {
|
|
|
|
|
let has_exports = false;
|
|
|
|
|
let has_only_exports = true;
|
|
|
|
|
node.declarations.forEach((declarator, i) => {
|
|
|
|
|
const next = node.declarations[i + 1];
|
|
|
|
|
|
|
|
|
|
if (declarator.id.type !== 'Identifier') {
|
|
|
|
|
const inserts = [];
|
|
|
|
|
|
|
|
|
|
node.declarations.forEach(declarator => {
|
|
|
|
|
extractNames(declarator.id).forEach(name => {
|
|
|
|
|
const variable = component.var_lookup.get(name);
|
|
|
|
|
|
|
|
|
|
if (name === componentOptions.props_object) {
|
|
|
|
|
if (variable.export_name) {
|
|
|
|
|
if (variable.export_name || name === componentOptions.props_object) {
|
|
|
|
|
component.error(declarator, {
|
|
|
|
|
code: 'exported-options-props',
|
|
|
|
|
message: `Cannot export props binding`
|
|
|
|
|
code: 'destructured-prop',
|
|
|
|
|
message: `Cannot declare props in destructured declaration`
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (declarator.id.type !== 'Identifier') {
|
|
|
|
|
if (variable.subscribable) {
|
|
|
|
|
inserts.push(get_insert(variable));
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (inserts.length > 0) {
|
|
|
|
|
if (next) {
|
|
|
|
|
code.overwrite(declarator.end, next.start, `; ${inserts.join('; ')}; ${node.kind} `);
|
|
|
|
|
} else {
|
|
|
|
|
code.appendLeft(declarator.end, `; ${inserts.join('; ')}`);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const { name } = declarator.id;
|
|
|
|
|
const variable = component.var_lookup.get(name);
|
|
|
|
|
|
|
|
|
|
if (name === componentOptions.props_object) {
|
|
|
|
|
if (variable.export_name) {
|
|
|
|
|
component.error(declarator, {
|
|
|
|
|
code: 'todo',
|
|
|
|
|
message: `props binding in destructured declaration is not yet supported`
|
|
|
|
|
code: 'exported-options-props',
|
|
|
|
|
message: `Cannot export props binding`
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// can't use the @ trick here, because we're
|
|
|
|
|
// manipulating the underlying magic string
|
|
|
|
|
component.helpers.add('exclude_internal_props');
|
|
|
|
|
const exclude_internal_props = component.alias('exclude_internal_props');
|
|
|
|
|
const exclude_internal_props = component.helper('exclude_internal_props');
|
|
|
|
|
|
|
|
|
|
const suffix = code.original[declarator.end] === ';'
|
|
|
|
|
? ` = ${exclude_internal_props}($$props)`
|
|
|
|
@ -798,34 +857,39 @@ export default class Component {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (variable.export_name) {
|
|
|
|
|
has_exports = true;
|
|
|
|
|
} else {
|
|
|
|
|
has_only_exports = false;
|
|
|
|
|
}
|
|
|
|
|
if (variable.subscribable) {
|
|
|
|
|
coalesced_declarations.push({
|
|
|
|
|
kind: node.kind,
|
|
|
|
|
declarators: [declarator],
|
|
|
|
|
insert: get_insert(variable)
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (has_only_exports) {
|
|
|
|
|
if (current_group && current_group[current_group.length - 1].kind !== node.kind) {
|
|
|
|
|
} else {
|
|
|
|
|
if (current_group && current_group.kind !== node.kind) {
|
|
|
|
|
current_group = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// rewrite as a group, later
|
|
|
|
|
if (!current_group) {
|
|
|
|
|
current_group = [];
|
|
|
|
|
current_group = { kind: node.kind, declarators: [], insert: null };
|
|
|
|
|
coalesced_declarations.push(current_group);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
current_group.push(node);
|
|
|
|
|
} else {
|
|
|
|
|
if (has_exports) {
|
|
|
|
|
// rewrite in place
|
|
|
|
|
throw new Error('TODO rewrite prop declaration in place');
|
|
|
|
|
current_group.declarators.push(declarator);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
current_group = null;
|
|
|
|
|
|
|
|
|
|
if (variable.subscribable) {
|
|
|
|
|
let insert = get_insert(variable);
|
|
|
|
|
|
|
|
|
|
if (next) {
|
|
|
|
|
code.overwrite(declarator.end, next.start, `; ${insert}; ${node.kind} `);
|
|
|
|
|
} else {
|
|
|
|
|
code.appendLeft(declarator.end, `; ${insert}`);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (node.type !== 'ExportNamedDeclaration') {
|
|
|
|
|
if (!parent) current_group = null;
|
|
|
|
@ -845,14 +909,8 @@ export default class Component {
|
|
|
|
|
|
|
|
|
|
let combining = false;
|
|
|
|
|
|
|
|
|
|
group.forEach(node => {
|
|
|
|
|
node.declarations.forEach(declarator => {
|
|
|
|
|
const { id, init } = declarator;
|
|
|
|
|
|
|
|
|
|
if (id.type === 'Identifier') {
|
|
|
|
|
const value = init
|
|
|
|
|
? this.code.slice(id.start, init.end)
|
|
|
|
|
: this.code.slice(id.start, id.end);
|
|
|
|
|
group.declarators.forEach(declarator => {
|
|
|
|
|
const { id } = declarator;
|
|
|
|
|
|
|
|
|
|
if (combining) {
|
|
|
|
|
code.overwrite(c, id.start, ', ');
|
|
|
|
@ -860,16 +918,16 @@ export default class Component {
|
|
|
|
|
code.appendLeft(id.start, '{ ');
|
|
|
|
|
combining = true;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
throw new Error('TODO destructured declarations');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c = declarator.end;
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (combining) {
|
|
|
|
|
const suffix = code.original[c] === ';' ? ` } = $$props` : ` } = $$props;`;
|
|
|
|
|
const insert = group.insert
|
|
|
|
|
? `; ${group.insert}`
|
|
|
|
|
: '';
|
|
|
|
|
|
|
|
|
|
const suffix = code.original[c] === ';' ? ` } = $$props${insert}` : ` } = $$props${insert};`;
|
|
|
|
|
code.appendLeft(c, suffix);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|