update options.customElement/<svelte:options tag='...'> handling (#2025)

pull/2162/head
Conduitry 6 years ago
parent 27ec345f31
commit 1e1784adaf

@ -119,16 +119,15 @@ export default class Component {
this.componentOptions = process_component_options(this, this.ast.html.children);
this.namespace = namespaces[this.componentOptions.namespace] || this.componentOptions.namespace;
if (compileOptions.customElement === true && !this.componentOptions.tag) {
throw new Error(`No tag name specified`); // TODO better error
if (compileOptions.customElement) {
this.tag = compileOptions.customElement.tag || this.componentOptions.tag;
if (!this.tag) {
throw new Error(`Cannot compile to a custom element without specifying a tag name via options.customElement or <svelte:options>`);
}
} else {
this.tag = this.name;
}
this.tag = compileOptions.customElement
? compileOptions.customElement === true
? this.componentOptions.tag
: compileOptions.customElement as string
: this.name;
this.walk_module_js();
this.walk_instance_js_pre_template();

@ -3,7 +3,7 @@ import Stats from '../Stats';
import parse from '../parse/index';
import renderDOM from './render-dom/index';
import renderSSR from './render-ssr/index';
import { CompileOptions, Ast, Warning } from '../interfaces';
import { CompileOptions, Ast, Warning, CustomElementOptions } from '../interfaces';
import Component from './Component';
import fuzzymatch from '../utils/fuzzymatch';
@ -41,6 +41,10 @@ function validate_options(options: CompileOptions, warnings: Warning[]) {
throw new Error(`options.name must be a valid identifier (got '${name}')`);
}
if ('customElement' in options) {
options.customElement = normalize_customElement_option(options.customElement);
}
if (name && /^[a-z]/.test(name)) {
const message = `options.name should be capitalised`;
warnings.push({
@ -52,6 +56,34 @@ function validate_options(options: CompileOptions, warnings: Warning[]) {
}
}
const valid_customElement_options = ['tag'];
function normalize_customElement_option(customElement: boolean | string | CustomElementOptions) {
if (typeof customElement === 'boolean') {
return customElement ? {} : null;
} else if (typeof customElement === 'string') {
customElement = { tag: customElement };
} else if (typeof customElement === 'object') {
Object.keys(customElement).forEach(key => {
if (valid_customElement_options.indexOf(key) === -1) {
const match = fuzzymatch(key, valid_customElement_options);
let message = `Unrecognized option 'customElement.${key}'`;
if (match) message += ` (did you mean 'customElement.${match}'?)`;
throw new Error(message);
}
});
} else {
throw new Error(`options.customElement must be a boolean, a string or an object`);
}
if ('tag' in customElement && !/^[a-zA-Z][a-zA-Z0-9]*-[a-zA-Z0-9-]+$/.test(customElement.tag)) {
throw new Error(`options.customElement tag name must be two or more words joined by the '-' character`);
}
return customElement;
}
function get_name(filename) {
if (!filename) return null;
const parts = filename.split(/[\/\\]/);

@ -52,7 +52,7 @@ export interface CompileOptions {
immutable?: boolean;
hydratable?: boolean;
legacy?: boolean;
customElement?: CustomElementOptions | true;
customElement?: CustomElementOptions;
css?: boolean;
preserveComments?: boolean | false;
@ -65,7 +65,6 @@ export interface Visitor {
export interface CustomElementOptions {
tag?: string;
props?: string[];
}
export interface AppendTarget {

@ -9,7 +9,7 @@ import error from '../utils/error';
interface ParserOptions {
filename?: string;
bind?: boolean;
customElement?: CustomElementOptions | true;
customElement?: CustomElementOptions;
}
type ParserState = (parser: Parser) => (ParserState | void);
@ -17,7 +17,7 @@ type ParserState = (parser: Parser) => (ParserState | void);
export class Parser {
readonly template: string;
readonly filename?: string;
readonly customElement: CustomElementOptions | true;
readonly customElement: CustomElementOptions;
index = 0;
stack: Array<Node> = [];

Loading…
Cancel
Save