diff --git a/src/compiler/parse/state/tag.ts b/src/compiler/parse/state/tag.ts index 7233a7670a..8fde01f952 100644 --- a/src/compiler/parse/state/tag.ts +++ b/src/compiler/parse/state/tag.ts @@ -1,603 +1,567 @@ -import { Directive, DirectiveType, TemplateNode, Text } from '../../interfaces'; import { extract_svelte_ignore } from '../../utils/extract_svelte_ignore'; import fuzzymatch from '../../utils/fuzzymatch'; import { is_void } from '../../../shared/utils/names'; import parser_errors from '../errors'; -import { Parser } from '../index'; import read_expression from '../read/expression'; import read_script from '../read/script'; import read_style from '../read/style'; import { closing_tag_omitted, decode_character_references } from '../utils/html'; - // eslint-disable-next-line no-useless-escape const valid_tag_name = /^\!?[a-zA-Z]{1,}:?[a-zA-Z0-9\-]*/; - /** Invalid attribute characters if the attribute is not surrounded by quotes */ const regex_starts_with_invalid_attr_value = /^(\/>|[\s"'=<>`])/; - const meta_tags = new Map([ - ['svelte:head', 'Head'], - ['svelte:options', 'Options'], - ['svelte:window', 'Window'], - ['svelte:document', 'Document'], - ['svelte:body', 'Body'] + ['svelte:head', 'Head'], + ['svelte:options', 'Options'], + ['svelte:window', 'Window'], + ['svelte:document', 'Document'], + ['svelte:body', 'Body'] ]); - -const valid_meta_tags = Array.from(meta_tags.keys()).concat( - 'svelte:self', - 'svelte:component', - 'svelte:fragment', - 'svelte:element' -); - +const valid_meta_tags = Array.from(meta_tags.keys()).concat('svelte:self', 'svelte:component', 'svelte:fragment', 'svelte:element'); const specials = new Map([ - [ - 'script', - { - read: read_script, - property: 'js' - } - ], - [ - 'style', - { - read: read_style, - property: 'css' - } - ] + [ + 'script', + { + read: read_script, + property: 'js' + } + ], + [ + 'style', + { + read: read_style, + property: 'css' + } + ] ]); - const SELF = /^svelte:self(?=[\s/>])/; const COMPONENT = /^svelte:component(?=[\s/>])/; const SLOT = /^svelte:fragment(?=[\s/>])/; const ELEMENT = /^svelte:element(?=[\s/>])/; - function parent_is_head(stack) { - let i = stack.length; - while (i--) { - const { type } = stack[i]; - if (type === 'Head') return true; - if (type === 'Element' || type === 'InlineComponent') return false; - } - return false; + let i = stack.length; + while (i--) { + const { type } = stack[i]; + if (type === 'Head') + return true; + if (type === 'Element' || type === 'InlineComponent') + return false; + } + return false; } - const regex_closing_textarea_tag = /^<\/textarea(\s[^>]*)?>/i; const regex_closing_comment = /-->/; const regex_capital_letter = /[A-Z]/; -export default function tag(parser: Parser) { - const start = parser.index++; - - let parent = parser.current(); - - if (parser.eat('!--')) { - const data = parser.read_until(regex_closing_comment); - parser.eat('-->', true, parser_errors.unclosed_comment); - - parser.current().children.push({ - start, - end: parser.index, - type: 'Comment', - data, - ignores: extract_svelte_ignore(data) - }); - - return; - } - - const is_closing_tag = parser.eat('/'); - - const name = read_tag_name(parser); - - if (meta_tags.has(name)) { - const slug = meta_tags.get(name).toLowerCase(); - if (is_closing_tag) { - if ( - (name === 'svelte:window' || name === 'svelte:body') && - parser.current().children.length - ) { - parser.error( - parser_errors.invalid_element_content(slug, name), - parser.current().children[0].start - ); - } - } else { - if (name in parser.meta_tags) { - parser.error(parser_errors.duplicate_element(slug, name), start); - } - - if (parser.stack.length > 1) { - parser.error(parser_errors.invalid_element_placement(slug, name), start); - } - - parser.meta_tags[name] = true; - } - } - - const type = meta_tags.has(name) - ? meta_tags.get(name) - : regex_capital_letter.test(name[0]) || name === 'svelte:self' || name === 'svelte:component' - ? 'InlineComponent' - : name === 'svelte:fragment' - ? 'SlotTemplate' - : name === 'title' && parent_is_head(parser.stack) - ? 'Title' - : name === 'slot' - ? 'Slot' - : 'Element'; - - const element: TemplateNode = { - start, - end: null, // filled in later - type, - name, - attributes: [], - children: [] - }; - - parser.allow_whitespace(); - - if (is_closing_tag) { - if (is_void(name)) { - parser.error(parser_errors.invalid_void_content(name), start); - } - - parser.eat('>', true); - - // close any elements that don't have their own closing tags, e.g.