|
|
@ -23,7 +23,7 @@ import getObject from '../utils/getObject';
|
|
|
|
import deindent from '../utils/deindent';
|
|
|
|
import deindent from '../utils/deindent';
|
|
|
|
import globalWhitelist from '../utils/globalWhitelist';
|
|
|
|
import globalWhitelist from '../utils/globalWhitelist';
|
|
|
|
|
|
|
|
|
|
|
|
type Options = {
|
|
|
|
type ComponentOptions = {
|
|
|
|
namespace?: string;
|
|
|
|
namespace?: string;
|
|
|
|
tag?: string;
|
|
|
|
tag?: string;
|
|
|
|
immutable?: boolean;
|
|
|
|
immutable?: boolean;
|
|
|
@ -45,13 +45,13 @@ export default class Component {
|
|
|
|
source: string;
|
|
|
|
source: string;
|
|
|
|
code: MagicString;
|
|
|
|
code: MagicString;
|
|
|
|
name: string;
|
|
|
|
name: string;
|
|
|
|
options: CompileOptions;
|
|
|
|
compileOptions: CompileOptions;
|
|
|
|
fragment: Fragment;
|
|
|
|
fragment: Fragment;
|
|
|
|
module_scope: Scope;
|
|
|
|
module_scope: Scope;
|
|
|
|
instance_scope: Scope;
|
|
|
|
instance_scope: Scope;
|
|
|
|
instance_scope_map: WeakMap<Node, Scope>;
|
|
|
|
instance_scope_map: WeakMap<Node, Scope>;
|
|
|
|
|
|
|
|
|
|
|
|
optionsTag: Options;
|
|
|
|
componentOptions: ComponentOptions;
|
|
|
|
namespace: string;
|
|
|
|
namespace: string;
|
|
|
|
tag: string;
|
|
|
|
tag: string;
|
|
|
|
|
|
|
|
|
|
|
@ -90,7 +90,7 @@ export default class Component {
|
|
|
|
ast: Ast,
|
|
|
|
ast: Ast,
|
|
|
|
source: string,
|
|
|
|
source: string,
|
|
|
|
name: string,
|
|
|
|
name: string,
|
|
|
|
options: CompileOptions,
|
|
|
|
compileOptions: CompileOptions,
|
|
|
|
stats: Stats
|
|
|
|
stats: Stats
|
|
|
|
) {
|
|
|
|
) {
|
|
|
|
this.name = this.getUniqueName(name);
|
|
|
|
this.name = this.getUniqueName(name);
|
|
|
@ -98,34 +98,34 @@ export default class Component {
|
|
|
|
this.stats = stats;
|
|
|
|
this.stats = stats;
|
|
|
|
this.ast = ast;
|
|
|
|
this.ast = ast;
|
|
|
|
this.source = source;
|
|
|
|
this.source = source;
|
|
|
|
this.options = options;
|
|
|
|
this.compileOptions = compileOptions;
|
|
|
|
|
|
|
|
|
|
|
|
this.file = options.filename && (
|
|
|
|
this.file = compileOptions.filename && (
|
|
|
|
typeof process !== 'undefined' ? options.filename.replace(process.cwd(), '').replace(/^[\/\\]/, '') : options.filename
|
|
|
|
typeof process !== 'undefined' ? compileOptions.filename.replace(process.cwd(), '').replace(/^[\/\\]/, '') : compileOptions.filename
|
|
|
|
);
|
|
|
|
);
|
|
|
|
this.locate = getLocator(this.source);
|
|
|
|
this.locate = getLocator(this.source);
|
|
|
|
|
|
|
|
|
|
|
|
this.code = new MagicString(source);
|
|
|
|
this.code = new MagicString(source);
|
|
|
|
|
|
|
|
|
|
|
|
// styles
|
|
|
|
// 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.stylesheet.validate(this);
|
|
|
|
|
|
|
|
|
|
|
|
this.optionsTag = process_options_tag(this, this.ast.html.children);
|
|
|
|
this.componentOptions = process_component_options(this, this.ast.html.children);
|
|
|
|
this.namespace = namespaces[this.optionsTag.namespace] || this.optionsTag.namespace;
|
|
|
|
this.namespace = namespaces[this.componentOptions.namespace] || this.componentOptions.namespace;
|
|
|
|
|
|
|
|
|
|
|
|
if (this.optionsTag.props) {
|
|
|
|
if (this.componentOptions.props) {
|
|
|
|
this.has_reactive_assignments = true;
|
|
|
|
this.has_reactive_assignments = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (options.customElement === true && !this.optionsTag.tag) {
|
|
|
|
if (compileOptions.customElement === true && !this.componentOptions.tag) {
|
|
|
|
throw new Error(`No tag name specified`); // TODO better error
|
|
|
|
throw new Error(`No tag name specified`); // TODO better error
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
this.tag = options.customElement
|
|
|
|
this.tag = compileOptions.customElement
|
|
|
|
? options.customElement === true
|
|
|
|
? compileOptions.customElement === true
|
|
|
|
? this.optionsTag.tag
|
|
|
|
? this.componentOptions.tag
|
|
|
|
: options.customElement as string
|
|
|
|
: compileOptions.customElement as string
|
|
|
|
: this.name;
|
|
|
|
: this.name;
|
|
|
|
|
|
|
|
|
|
|
|
this.walk_module_js();
|
|
|
|
this.walk_module_js();
|
|
|
@ -135,7 +135,7 @@ export default class Component {
|
|
|
|
|
|
|
|
|
|
|
|
this.walk_instance_js_post_template();
|
|
|
|
this.walk_instance_js_post_template();
|
|
|
|
|
|
|
|
|
|
|
|
if (!options.customElement) this.stylesheet.reify();
|
|
|
|
if (!compileOptions.customElement) this.stylesheet.reify();
|
|
|
|
|
|
|
|
|
|
|
|
this.stylesheet.warnOnUnusedSelectors(stats);
|
|
|
|
this.stylesheet.warnOnUnusedSelectors(stats);
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -195,18 +195,18 @@ export default class Component {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
generate(result: string) {
|
|
|
|
generate(result: string) {
|
|
|
|
const { options, name } = this;
|
|
|
|
const { compileOptions, name } = this;
|
|
|
|
const { format = 'esm' } = options;
|
|
|
|
const { format = 'esm' } = compileOptions;
|
|
|
|
|
|
|
|
|
|
|
|
const banner = `/* ${this.file ? `${this.file} ` : ``}generated by Svelte v${"__VERSION__"} */`;
|
|
|
|
const banner = `/* ${this.file ? `${this.file} ` : ``}generated by Svelte v${"__VERSION__"} */`;
|
|
|
|
|
|
|
|
|
|
|
|
const helpers = new Set();
|
|
|
|
const helpers = new Set();
|
|
|
|
|
|
|
|
|
|
|
|
// TODO use same regex for both
|
|
|
|
// 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 (sigil === '@') {
|
|
|
|
if (internal_exports.has(name)) {
|
|
|
|
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);
|
|
|
|
helpers.add(name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -227,10 +227,10 @@ export default class Component {
|
|
|
|
result,
|
|
|
|
result,
|
|
|
|
format,
|
|
|
|
format,
|
|
|
|
name,
|
|
|
|
name,
|
|
|
|
options,
|
|
|
|
compileOptions,
|
|
|
|
this.stats,
|
|
|
|
this.stats,
|
|
|
|
banner,
|
|
|
|
banner,
|
|
|
|
options.sveltePath,
|
|
|
|
compileOptions.sveltePath,
|
|
|
|
importedHelpers,
|
|
|
|
importedHelpers,
|
|
|
|
this.imports,
|
|
|
|
this.imports,
|
|
|
|
this.vars.filter(variable => variable.module && variable.export_name).map(variable => ({
|
|
|
|
this.vars.filter(variable => variable.module && variable.export_name).map(variable => ({
|
|
|
@ -251,7 +251,7 @@ export default class Component {
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const { filename } = options;
|
|
|
|
const { filename } = compileOptions;
|
|
|
|
|
|
|
|
|
|
|
|
// special case — the source file doesn't actually get used anywhere. we need
|
|
|
|
// 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
|
|
|
|
// to add an empty file to populate map.sources and map.sourcesContent
|
|
|
@ -280,15 +280,15 @@ export default class Component {
|
|
|
|
|
|
|
|
|
|
|
|
addString(finalChunk);
|
|
|
|
addString(finalChunk);
|
|
|
|
|
|
|
|
|
|
|
|
const css = options.customElement ?
|
|
|
|
const css = compileOptions.customElement ?
|
|
|
|
{ code: null, map: null } :
|
|
|
|
{ code: null, map: null } :
|
|
|
|
this.stylesheet.render(options.cssOutputFilename, true);
|
|
|
|
this.stylesheet.render(compileOptions.cssOutputFilename, true);
|
|
|
|
|
|
|
|
|
|
|
|
const js = {
|
|
|
|
const js = {
|
|
|
|
code: compiled.toString(),
|
|
|
|
code: compiled.toString(),
|
|
|
|
map: compiled.generateMap({
|
|
|
|
map: compiled.generateMap({
|
|
|
|
includeContent: true,
|
|
|
|
includeContent: true,
|
|
|
|
file: options.outputFilename,
|
|
|
|
file: compileOptions.outputFilename,
|
|
|
|
})
|
|
|
|
})
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
@ -354,7 +354,7 @@ export default class Component {
|
|
|
|
source: this.source,
|
|
|
|
source: this.source,
|
|
|
|
start: pos.start,
|
|
|
|
start: pos.start,
|
|
|
|
end: pos.end,
|
|
|
|
end: pos.end,
|
|
|
|
filename: this.options.filename
|
|
|
|
filename: this.compileOptions.filename
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -384,7 +384,7 @@ export default class Component {
|
|
|
|
start,
|
|
|
|
start,
|
|
|
|
end,
|
|
|
|
end,
|
|
|
|
pos: pos.start,
|
|
|
|
pos: pos.start,
|
|
|
|
filename: this.options.filename,
|
|
|
|
filename: this.compileOptions.filename,
|
|
|
|
toString: () => `${warning.message} (${start.line + 1}:${start.column})\n${frame}`,
|
|
|
|
toString: () => `${warning.message} (${start.line + 1}:${start.column})\n${frame}`,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -691,7 +691,7 @@ export default class Component {
|
|
|
|
|
|
|
|
|
|
|
|
rewrite_props() {
|
|
|
|
rewrite_props() {
|
|
|
|
const component = this;
|
|
|
|
const component = this;
|
|
|
|
const { code, instance_scope, instance_scope_map: map, optionsTag } = this;
|
|
|
|
const { code, instance_scope, instance_scope_map: map, componentOptions } = this;
|
|
|
|
let scope = instance_scope;
|
|
|
|
let scope = instance_scope;
|
|
|
|
|
|
|
|
|
|
|
|
const coalesced_declarations = [];
|
|
|
|
const coalesced_declarations = [];
|
|
|
@ -717,7 +717,7 @@ export default class Component {
|
|
|
|
extractNames(declarator.id).forEach(name => {
|
|
|
|
extractNames(declarator.id).forEach(name => {
|
|
|
|
const variable = component.var_lookup.get(name);
|
|
|
|
const variable = component.var_lookup.get(name);
|
|
|
|
|
|
|
|
|
|
|
|
if (name === optionsTag.props_object) {
|
|
|
|
if (name === componentOptions.props_object) {
|
|
|
|
if (variable.export_name) {
|
|
|
|
if (variable.export_name) {
|
|
|
|
component.error(declarator, {
|
|
|
|
component.error(declarator, {
|
|
|
|
code: 'exported-options-props',
|
|
|
|
code: 'exported-options-props',
|
|
|
@ -1072,9 +1072,9 @@ export default class Component {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function process_options_tag(component, nodes) {
|
|
|
|
function process_component_options(component: Component, nodes) {
|
|
|
|
const optionsTag: Options = {
|
|
|
|
const componentOptions: ComponentOptions = {
|
|
|
|
immutable: component.options.immutable || false
|
|
|
|
immutable: component.compileOptions.immutable || false
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const node = nodes.find(node => node.name === 'svelte:options');
|
|
|
|
const node = nodes.find(node => node.name === 'svelte:options');
|
|
|
@ -1118,7 +1118,7 @@ function process_options_tag(component, nodes) {
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
optionsTag.tag = tag;
|
|
|
|
componentOptions.tag = tag;
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -1144,7 +1144,7 @@ function process_options_tag(component, nodes) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
optionsTag.namespace = ns;
|
|
|
|
componentOptions.namespace = ns;
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -1155,7 +1155,7 @@ function process_options_tag(component, nodes) {
|
|
|
|
|
|
|
|
|
|
|
|
if (typeof value !== 'boolean') component.error(attribute, { code, message });
|
|
|
|
if (typeof value !== 'boolean') component.error(attribute, { code, message });
|
|
|
|
|
|
|
|
|
|
|
|
optionsTag.immutable = value;
|
|
|
|
componentOptions.immutable = value;
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
default:
|
|
|
@ -1177,8 +1177,8 @@ function process_options_tag(component, nodes) {
|
|
|
|
const { start, end } = attribute.expression;
|
|
|
|
const { start, end } = attribute.expression;
|
|
|
|
const { name } = flattenReference(attribute.expression);
|
|
|
|
const { name } = flattenReference(attribute.expression);
|
|
|
|
|
|
|
|
|
|
|
|
optionsTag.props = `[✂${start}-${end}✂]`;
|
|
|
|
componentOptions.props = `[✂${start}-${end}✂]`;
|
|
|
|
optionsTag.props_object = name;
|
|
|
|
componentOptions.props_object = name;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
else {
|
|
|
|
else {
|
|
|
@ -1190,5 +1190,5 @@ function process_options_tag(component, nodes) {
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return optionsTag;
|
|
|
|
return componentOptions;
|
|
|
|
}
|
|
|
|
}
|
|
|
|