|
|
|
@ -23,7 +23,7 @@ import getObject from '../utils/getObject';
|
|
|
|
|
import deindent from '../utils/deindent';
|
|
|
|
|
import globalWhitelist from '../utils/globalWhitelist';
|
|
|
|
|
|
|
|
|
|
type Meta = {
|
|
|
|
|
type ComponentOptions = {
|
|
|
|
|
namespace?: string;
|
|
|
|
|
tag?: string;
|
|
|
|
|
immutable?: boolean;
|
|
|
|
@ -45,13 +45,13 @@ export default class Component {
|
|
|
|
|
source: string;
|
|
|
|
|
code: MagicString;
|
|
|
|
|
name: string;
|
|
|
|
|
options: CompileOptions;
|
|
|
|
|
compileOptions: CompileOptions;
|
|
|
|
|
fragment: Fragment;
|
|
|
|
|
module_scope: Scope;
|
|
|
|
|
instance_scope: Scope;
|
|
|
|
|
instance_scope_map: WeakMap<Node, Scope>;
|
|
|
|
|
|
|
|
|
|
meta: Meta;
|
|
|
|
|
componentOptions: ComponentOptions;
|
|
|
|
|
namespace: string;
|
|
|
|
|
tag: string;
|
|
|
|
|
|
|
|
|
@ -90,7 +90,7 @@ export default class Component {
|
|
|
|
|
ast: Ast,
|
|
|
|
|
source: string,
|
|
|
|
|
name: string,
|
|
|
|
|
options: CompileOptions,
|
|
|
|
|
compileOptions: CompileOptions,
|
|
|
|
|
stats: Stats
|
|
|
|
|
) {
|
|
|
|
|
this.name = name;
|
|
|
|
@ -98,34 +98,34 @@ export default class Component {
|
|
|
|
|
this.stats = stats;
|
|
|
|
|
this.ast = ast;
|
|
|
|
|
this.source = source;
|
|
|
|
|
this.options = options;
|
|
|
|
|
this.compileOptions = compileOptions;
|
|
|
|
|
|
|
|
|
|
this.file = options.filename && (
|
|
|
|
|
typeof process !== 'undefined' ? options.filename.replace(process.cwd(), '').replace(/^[\/\\]/, '') : options.filename
|
|
|
|
|
this.file = compileOptions.filename && (
|
|
|
|
|
typeof process !== 'undefined' ? compileOptions.filename.replace(process.cwd(), '').replace(/^[\/\\]/, '') : compileOptions.filename
|
|
|
|
|
);
|
|
|
|
|
this.locate = getLocator(this.source);
|
|
|
|
|
|
|
|
|
|
this.code = new MagicString(source);
|
|
|
|
|
|
|
|
|
|
// styles
|
|
|
|
|
this.stylesheet = new Stylesheet(source, ast, options.filename, options.dev);
|
|
|
|
|
this.stylesheet = new Stylesheet(source, ast, compileOptions.filename, compileOptions.dev);
|
|
|
|
|
this.stylesheet.validate(this);
|
|
|
|
|
|
|
|
|
|
this.meta = process_meta(this, this.ast.html.children);
|
|
|
|
|
this.namespace = namespaces[this.meta.namespace] || this.meta.namespace;
|
|
|
|
|
this.componentOptions = process_component_options(this, this.ast.html.children);
|
|
|
|
|
this.namespace = namespaces[this.componentOptions.namespace] || this.componentOptions.namespace;
|
|
|
|
|
|
|
|
|
|
if (this.meta.props) {
|
|
|
|
|
if (this.componentOptions.props) {
|
|
|
|
|
this.has_reactive_assignments = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (options.customElement === true && !this.meta.tag) {
|
|
|
|
|
if (compileOptions.customElement === true && !this.componentOptions.tag) {
|
|
|
|
|
throw new Error(`No tag name specified`); // TODO better error
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.tag = options.customElement
|
|
|
|
|
? options.customElement === true
|
|
|
|
|
? this.meta.tag
|
|
|
|
|
: options.customElement as string
|
|
|
|
|
this.tag = compileOptions.customElement
|
|
|
|
|
? compileOptions.customElement === true
|
|
|
|
|
? this.componentOptions.tag
|
|
|
|
|
: compileOptions.customElement as string
|
|
|
|
|
: this.name;
|
|
|
|
|
|
|
|
|
|
this.walk_module_js();
|
|
|
|
@ -136,7 +136,7 @@ export default class Component {
|
|
|
|
|
|
|
|
|
|
this.walk_instance_js_post_template();
|
|
|
|
|
|
|
|
|
|
if (!options.customElement) this.stylesheet.reify();
|
|
|
|
|
if (!compileOptions.customElement) this.stylesheet.reify();
|
|
|
|
|
|
|
|
|
|
this.stylesheet.warnOnUnusedSelectors(stats);
|
|
|
|
|
}
|
|
|
|
@ -196,18 +196,18 @@ export default class Component {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
generate(result: string) {
|
|
|
|
|
const { options, name } = this;
|
|
|
|
|
const { format = 'esm' } = options;
|
|
|
|
|
const { compileOptions, name } = this;
|
|
|
|
|
const { format = 'esm' } = compileOptions;
|
|
|
|
|
|
|
|
|
|
const banner = `/* ${this.file ? `${this.file} ` : ``}generated by Svelte v${"__VERSION__"} */`;
|
|
|
|
|
|
|
|
|
|
const helpers = new Set();
|
|
|
|
|
|
|
|
|
|
// TODO use same regex for both
|
|
|
|
|
result = result.replace(options.generate === 'ssr' ? /(@+|#+)(\w*(?:-\w*)?)/g : /(@+)(\w*(?:-\w*)?)/g, (match: string, sigil: string, name: string) => {
|
|
|
|
|
result = result.replace(compileOptions.generate === 'ssr' ? /(@+|#+)(\w*(?:-\w*)?)/g : /(@+)(\w*(?:-\w*)?)/g, (match: string, sigil: string, name: string) => {
|
|
|
|
|
if (sigil === '@') {
|
|
|
|
|
if (internal_exports.has(name)) {
|
|
|
|
|
if (options.dev && internal_exports.has(`${name}Dev`)) name = `${name}Dev`;
|
|
|
|
|
if (compileOptions.dev && internal_exports.has(`${name}Dev`)) name = `${name}Dev`;
|
|
|
|
|
helpers.add(name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -228,10 +228,10 @@ export default class Component {
|
|
|
|
|
result,
|
|
|
|
|
format,
|
|
|
|
|
name,
|
|
|
|
|
options,
|
|
|
|
|
compileOptions,
|
|
|
|
|
this.stats,
|
|
|
|
|
banner,
|
|
|
|
|
options.sveltePath,
|
|
|
|
|
compileOptions.sveltePath,
|
|
|
|
|
importedHelpers,
|
|
|
|
|
this.imports,
|
|
|
|
|
this.vars.filter(variable => variable.module && variable.export_name).map(variable => ({
|
|
|
|
@ -252,7 +252,7 @@ export default class Component {
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const { filename } = options;
|
|
|
|
|
const { filename } = compileOptions;
|
|
|
|
|
|
|
|
|
|
// special case — the source file doesn't actually get used anywhere. we need
|
|
|
|
|
// to add an empty file to populate map.sources and map.sourcesContent
|
|
|
|
@ -281,15 +281,15 @@ export default class Component {
|
|
|
|
|
|
|
|
|
|
addString(finalChunk);
|
|
|
|
|
|
|
|
|
|
const css = options.customElement ?
|
|
|
|
|
const css = compileOptions.customElement ?
|
|
|
|
|
{ code: null, map: null } :
|
|
|
|
|
this.stylesheet.render(options.cssOutputFilename, true);
|
|
|
|
|
this.stylesheet.render(compileOptions.cssOutputFilename, true);
|
|
|
|
|
|
|
|
|
|
const js = {
|
|
|
|
|
code: compiled.toString(),
|
|
|
|
|
map: compiled.generateMap({
|
|
|
|
|
includeContent: true,
|
|
|
|
|
file: options.outputFilename,
|
|
|
|
|
file: compileOptions.outputFilename,
|
|
|
|
|
})
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
@ -355,7 +355,7 @@ export default class Component {
|
|
|
|
|
source: this.source,
|
|
|
|
|
start: pos.start,
|
|
|
|
|
end: pos.end,
|
|
|
|
|
filename: this.options.filename
|
|
|
|
|
filename: this.compileOptions.filename
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -385,7 +385,7 @@ export default class Component {
|
|
|
|
|
start,
|
|
|
|
|
end,
|
|
|
|
|
pos: pos.start,
|
|
|
|
|
filename: this.options.filename,
|
|
|
|
|
filename: this.compileOptions.filename,
|
|
|
|
|
toString: () => `${warning.message} (${start.line + 1}:${start.column})\n${frame}`,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
@ -692,7 +692,7 @@ export default class Component {
|
|
|
|
|
|
|
|
|
|
rewrite_props() {
|
|
|
|
|
const component = this;
|
|
|
|
|
const { code, instance_scope, instance_scope_map: map, meta } = this;
|
|
|
|
|
const { code, instance_scope, instance_scope_map: map, componentOptions } = this;
|
|
|
|
|
let scope = instance_scope;
|
|
|
|
|
|
|
|
|
|
const coalesced_declarations = [];
|
|
|
|
@ -718,10 +718,10 @@ export default class Component {
|
|
|
|
|
extractNames(declarator.id).forEach(name => {
|
|
|
|
|
const variable = component.var_lookup.get(name);
|
|
|
|
|
|
|
|
|
|
if (name === meta.props_object) {
|
|
|
|
|
if (name === componentOptions.props_object) {
|
|
|
|
|
if (variable.export_name) {
|
|
|
|
|
component.error(declarator, {
|
|
|
|
|
code: 'exported-meta-props',
|
|
|
|
|
code: 'exported-options-props',
|
|
|
|
|
message: `Cannot export props binding`
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
@ -1073,12 +1073,12 @@ export default class Component {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function process_meta(component, nodes) {
|
|
|
|
|
const meta: Meta = {
|
|
|
|
|
immutable: component.options.immutable || false
|
|
|
|
|
function process_component_options(component: Component, nodes) {
|
|
|
|
|
const componentOptions: ComponentOptions = {
|
|
|
|
|
immutable: component.compileOptions.immutable || false
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const node = nodes.find(node => node.name === 'svelte:meta');
|
|
|
|
|
const node = nodes.find(node => node.name === 'svelte:options');
|
|
|
|
|
|
|
|
|
|
function get_value(attribute, code, message) {
|
|
|
|
|
const { value } = attribute;
|
|
|
|
@ -1119,7 +1119,7 @@ function process_meta(component, nodes) {
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
meta.tag = tag;
|
|
|
|
|
componentOptions.tag = tag;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1145,7 +1145,7 @@ function process_meta(component, nodes) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
meta.namespace = ns;
|
|
|
|
|
componentOptions.namespace = ns;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1156,13 +1156,13 @@ function process_meta(component, nodes) {
|
|
|
|
|
|
|
|
|
|
if (typeof value !== 'boolean') component.error(attribute, { code, message });
|
|
|
|
|
|
|
|
|
|
meta.immutable = value;
|
|
|
|
|
componentOptions.immutable = value;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
component.error(attribute, {
|
|
|
|
|
code: `invalid-meta-attribute`,
|
|
|
|
|
message: `<svelte:meta> unknown attribute`
|
|
|
|
|
code: `invalid-options-attribute`,
|
|
|
|
|
message: `<svelte:options> unknown attribute`
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -1170,26 +1170,26 @@ function process_meta(component, nodes) {
|
|
|
|
|
else if (attribute.type === 'Binding') {
|
|
|
|
|
if (attribute.name !== 'props') {
|
|
|
|
|
component.error(attribute, {
|
|
|
|
|
code: `invalid-meta-binding`,
|
|
|
|
|
message: `<svelte:meta> only supports bind:props`
|
|
|
|
|
code: `invalid-options-binding`,
|
|
|
|
|
message: `<svelte:options> only supports bind:props`
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const { start, end } = attribute.expression;
|
|
|
|
|
const { name } = flattenReference(attribute.expression);
|
|
|
|
|
|
|
|
|
|
meta.props = `[✂${start}-${end}✂]`;
|
|
|
|
|
meta.props_object = name;
|
|
|
|
|
componentOptions.props = `[✂${start}-${end}✂]`;
|
|
|
|
|
componentOptions.props_object = name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else {
|
|
|
|
|
component.error(attribute, {
|
|
|
|
|
code: `invalid-meta-attribute`,
|
|
|
|
|
message: `<svelte:meta> can only have static 'tag', 'namespace' and 'immutable' attributes, or a bind:props directive`
|
|
|
|
|
code: `invalid-options-attribute`,
|
|
|
|
|
message: `<svelte:options> can only have static 'tag', 'namespace' and 'immutable' attributes, or a bind:props directive`
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return meta;
|
|
|
|
|
return componentOptions;
|
|
|
|
|
}
|
|
|
|
|