From 8ceff7ba8a929601bd2bdb94099099423f536ad1 Mon Sep 17 00:00:00 2001 From: Simon Holthausen Date: Thu, 11 May 2023 14:07:26 +0200 Subject: [PATCH] Convert src/compiler/parse/state/tag.ts to JavaScript --- src/compiler/parse/state/tag.ts | 1082 +++++++++++++++---------------- 1 file changed, 523 insertions(+), 559 deletions(-) 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.

- while (parent.name !== name) { - if (parent.type !== 'Element') { - const error = - parser.last_auto_closed_tag && parser.last_auto_closed_tag.tag === name - ? parser_errors.invalid_closing_tag_autoclosed(name, parser.last_auto_closed_tag.reason) - : parser_errors.invalid_closing_tag_unopened(name); - parser.error(error, start); - } - - parent.end = start; - parser.stack.pop(); - - parent = parser.current(); - } - - parent.end = parser.index; - parser.stack.pop(); - - if (parser.last_auto_closed_tag && parser.stack.length < parser.last_auto_closed_tag.depth) { - parser.last_auto_closed_tag = null; - } - - return; - } else if (closing_tag_omitted(parent.name, name)) { - parent.end = start; - parser.stack.pop(); - parser.last_auto_closed_tag = { - tag: parent.name, - reason: name, - depth: parser.stack.length - }; - } - - const unique_names: Set = new Set(); - - let attribute; - while ((attribute = read_attribute(parser, unique_names))) { - element.attributes.push(attribute); - parser.allow_whitespace(); - } - - if (name === 'svelte:component') { - const index = element.attributes.findIndex( - (attr) => attr.type === 'Attribute' && attr.name === 'this' - ); - if (index === -1) { - parser.error(parser_errors.missing_component_definition, start); - } - - const definition = element.attributes.splice(index, 1)[0]; - if ( - definition.value === true || - definition.value.length !== 1 || - definition.value[0].type === 'Text' - ) { - parser.error(parser_errors.invalid_component_definition, definition.start); - } - - element.expression = definition.value[0].expression; - } - - if (name === 'svelte:element') { - const index = element.attributes.findIndex( - (attr) => attr.type === 'Attribute' && attr.name === 'this' - ); - if (index === -1) { - parser.error(parser_errors.missing_element_definition, start); - } - - const definition = element.attributes.splice(index, 1)[0]; - if (definition.value === true) { - parser.error(parser_errors.invalid_element_definition, definition.start); - } - element.tag = definition.value[0].data || definition.value[0].expression; - } - - // special cases – top-level