diff --git a/src/compile/Component.ts b/src/compile/Component.ts index 03f3196fd8..af16c8ebec 100644 --- a/src/compile/Component.ts +++ b/src/compile/Component.ts @@ -103,6 +103,12 @@ export default class Component { options: CompileOptions; fragment: Fragment; + meta: { + namespace?: string; + tag?: string; + immutable?: boolean; + }; + customElement: CustomElementOptions; tag: string; @@ -231,20 +237,14 @@ export default class Component { this.walkJs(); this.name = this.alias(name); + const meta = process_meta(this, this.ast.html.children); + this.namespace = meta.namespace; + if (options.customElement === true) { this.customElement = { - tag: null, + tag: meta.tag, props: [] // TODO!!! }; - - // find tag - const meta = this.ast.html.children.find(node => node.name === 'svelte:meta'); - if (meta) { - const tag_attribute = meta.attributes.find(a => a.name === 'tag'); - if (tag_attribute) { - this.customElement.tag = tag_attribute.value[0].data; - } - } } else { this.customElement = options.customElement; } @@ -582,3 +582,69 @@ export default class Component { this.javascript = a !== b ? `[✂${a}-${b}✂]` : ''; } } + +type Meta = { + namespace?: string; + tag?: string; + immutable?: boolean; +}; + +function process_meta(component, nodes) { + const meta: Meta = {}; + const node = nodes.find(node => node.name === 'svelte:meta'); + + if (node) { + node.attributes.forEach(attribute => { + if (attribute.type !== 'Attribute') { + // TODO implement bindings on + component.error(attribute, { + code: `invalid-meta-attribute`, + message: ` can only have 'tag' and 'namespace' attributes` + }); + } + + const { name, value } = attribute; + + if (value.length > 1 || (value[0] && value[0].type !== 'Text')) { + component.error(attribute, { + code: `invalid-meta-attribute`, + message: ` cannot have dynamic attributes` + }); + } + + const { data } = value[0]; + + switch (name) { + case 'tag': + case 'namespace': + if (!data) { + component.error(attribute, { + code: `invalid-meta-attribute`, + message: ` ${name} attribute must have a string value` + }); + } + + meta[name] = data; + break; + + case 'immutable': + if (data && (data !== 'true' && data !== 'false')) { + component.error(attribute, { + code: `invalid-meta-attribute`, + message: ` immutable attribute must be true or false` + }); + } + + meta.immutable = data !== 'false'; + + default: + component.error(attribute, { + code: `invalid-meta-attribute`, + message: ` unknown attribute` + }); + } + }); + } + + return meta; +} \ No newline at end of file diff --git a/src/compile/nodes/Meta.ts b/src/compile/nodes/Meta.ts index 6477ba4fcd..7e93b8d0d9 100644 --- a/src/compile/nodes/Meta.ts +++ b/src/compile/nodes/Meta.ts @@ -2,5 +2,4 @@ import Node from './shared/Node'; export default class Meta extends Node { type: 'Meta'; - data: string; } \ No newline at end of file diff --git a/src/compile/render-dom/wrappers/Fragment.ts b/src/compile/render-dom/wrappers/Fragment.ts index a766fd002a..56c7e2d6f0 100644 --- a/src/compile/render-dom/wrappers/Fragment.ts +++ b/src/compile/render-dom/wrappers/Fragment.ts @@ -29,6 +29,7 @@ const wrappers = { Head, IfBlock, InlineComponent, + Meta: null, MustacheTag, RawMustacheTag, Slot, diff --git a/src/parse/state/tag.ts b/src/parse/state/tag.ts index e6c17120a2..8464fe5eef 100644 --- a/src/parse/state/tag.ts +++ b/src/parse/state/tag.ts @@ -13,6 +13,7 @@ const validTagName = /^\!?[a-zA-Z]{1,}:?[a-zA-Z0-9\-]*/; const metaTags = new Map([ ['svelte:document', 'Document'], ['svelte:window', 'Window'], + ['svelte:meta', 'Meta'], ['svelte:head', 'Head'] ]);