summaryrefslogtreecommitdiff
path: root/src/compiler/parse/state
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler/parse/state')
-rw-r--r--src/compiler/parse/state/fragment.ts21
-rw-r--r--src/compiler/parse/state/mustache.ts413
-rw-r--r--src/compiler/parse/state/setup.ts35
-rw-r--r--src/compiler/parse/state/tag.ts579
-rw-r--r--src/compiler/parse/state/text.ts24
5 files changed, 0 insertions, 1072 deletions
diff --git a/src/compiler/parse/state/fragment.ts b/src/compiler/parse/state/fragment.ts
deleted file mode 100644
index 97398b227..000000000
--- a/src/compiler/parse/state/fragment.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import tag from './tag.js';
-import setup from './setup.js';
-import mustache from './mustache.js';
-import text from './text.js';
-import { Parser } from '../index.js';
-
-export default function fragment(parser: Parser) {
- if (parser.html.children.length === 0 && parser.match_regex(/^---/m)) {
- return setup;
- }
-
- if (parser.match('<')) {
- return tag;
- }
-
- if (parser.match('{')) {
- return mustache;
- }
-
- return text;
-}
diff --git a/src/compiler/parse/state/mustache.ts b/src/compiler/parse/state/mustache.ts
deleted file mode 100644
index 79372d8d9..000000000
--- a/src/compiler/parse/state/mustache.ts
+++ /dev/null
@@ -1,413 +0,0 @@
-import read_context from '../read/context.js';
-import read_expression from '../read/expression.js';
-import { closing_tag_omitted } from '../utils/html.js';
-import { whitespace } from '../../utils/patterns.js';
-import { trim_start, trim_end } from '../../utils/trim.js';
-import { to_string } from '../utils/node.js';
-import { Parser } from '../index.js';
-import { TemplateNode } from '../../interfaces.js';
-
-type TODO = any;
-
-function trim_whitespace(block: TemplateNode, trim_before: boolean, trim_after: boolean) {
- if (!block.children || block.children.length === 0) return; // AwaitBlock
-
- const first_child = block.children[0];
- const last_child = block.children[block.children.length - 1];
-
- if (first_child.type === 'Text' && trim_before) {
- first_child.data = trim_start(first_child.data);
- if (!first_child.data) block.children.shift();
- }
-
- if (last_child.type === 'Text' && trim_after) {
- last_child.data = trim_end(last_child.data);
- if (!last_child.data) block.children.pop();
- }
-
- if (block.else) {
- trim_whitespace(block.else, trim_before, trim_after);
- }
-
- if (first_child.elseif) {
- trim_whitespace(first_child, trim_before, trim_after);
- }
-}
-
-export default function mustache(parser: Parser) {
- const start = parser.index;
- parser.index += 1;
-
- parser.allow_whitespace();
-
- // {/if}, {/each}, {/await} or {/key}
- if (parser.eat('/')) {
- let block = parser.current();
- let expected: TODO;
-
- if (closing_tag_omitted(block.name)) {
- block.end = start;
- parser.stack.pop();
- block = parser.current();
- }
-
- if (block.type === 'ElseBlock' || block.type === 'PendingBlock' || block.type === 'ThenBlock' || block.type === 'CatchBlock') {
- block.end = start;
- parser.stack.pop();
- block = parser.current();
-
- expected = 'await';
- }
-
- if (block.type === 'IfBlock') {
- expected = 'if';
- } else if (block.type === 'EachBlock') {
- expected = 'each';
- } else if (block.type === 'AwaitBlock') {
- expected = 'await';
- } else if (block.type === 'KeyBlock') {
- expected = 'key';
- } else {
- parser.error({
- code: 'unexpected-block-close',
- message: 'Unexpected block closing tag',
- });
- }
-
- parser.eat(expected, true);
- parser.allow_whitespace();
- parser.eat('}', true);
-
- while (block.elseif) {
- block.end = parser.index;
- parser.stack.pop();
- block = parser.current();
-
- if (block.else) {
- block.else.end = start;
- }
- }
-
- // strip leading/trailing whitespace as necessary
- const char_before = parser.template[block.start - 1];
- const char_after = parser.template[parser.index];
- const trim_before = !char_before || whitespace.test(char_before);
- const trim_after = !char_after || whitespace.test(char_after);
-
- trim_whitespace(block, trim_before, trim_after);
-
- block.end = parser.index;
- parser.stack.pop();
- } else if (parser.eat(':else')) {
- if (parser.eat('if')) {
- parser.error({
- code: 'invalid-elseif',
- message: "'elseif' should be 'else if'",
- });
- }
-
- parser.allow_whitespace();
-
- // :else if
- if (parser.eat('if')) {
- const block = parser.current();
- if (block.type !== 'IfBlock') {
- parser.error({
- code: 'invalid-elseif-placement',
- message: parser.stack.some((block) => block.type === 'IfBlock')
- ? `Expected to close ${to_string(block)} before seeing {:else if ...} block`
- : 'Cannot have an {:else if ...} block outside an {#if ...} block',
- });
- }
-
- parser.require_whitespace();
-
- const expression = read_expression(parser);
-
- parser.allow_whitespace();
- parser.eat('}', true);
-
- block.else = {
- start: parser.index,
- end: null,
- type: 'ElseBlock',
- children: [
- {
- start: parser.index,
- end: null,
- type: 'IfBlock',
- elseif: true,
- expression,
- children: [],
- },
- ],
- };
-
- parser.stack.push(block.else.children[0]);
- } else {
- // :else
- const block = parser.current();
- if (block.type !== 'IfBlock' && block.type !== 'EachBlock') {
- parser.error({
- code: 'invalid-else-placement',
- message: parser.stack.some((block) => block.type === 'IfBlock' || block.type === 'EachBlock')
- ? `Expected to close ${to_string(block)} before seeing {:else} block`
- : 'Cannot have an {:else} block outside an {#if ...} or {#each ...} block',
- });
- }
-
- parser.allow_whitespace();
- parser.eat('}', true);
-
- block.else = {
- start: parser.index,
- end: null,
- type: 'ElseBlock',
- children: [],
- };
-
- parser.stack.push(block.else);
- }
- } else if (parser.match(':then') || parser.match(':catch')) {
- const block = parser.current();
- const is_then = parser.eat(':then') || !parser.eat(':catch');
-
- if (is_then) {
- if (block.type !== 'PendingBlock') {
- parser.error({
- code: 'invalid-then-placement',
- message: parser.stack.some((block) => block.type === 'PendingBlock')
- ? `Expected to close ${to_string(block)} before seeing {:then} block`
- : 'Cannot have an {:then} block outside an {#await ...} block',
- });
- }
- } else {
- if (block.type !== 'ThenBlock' && block.type !== 'PendingBlock') {
- parser.error({
- code: 'invalid-catch-placement',
- message: parser.stack.some((block) => block.type === 'ThenBlock' || block.type === 'PendingBlock')
- ? `Expected to close ${to_string(block)} before seeing {:catch} block`
- : 'Cannot have an {:catch} block outside an {#await ...} block',
- });
- }
- }
-
- block.end = start;
- parser.stack.pop();
- const await_block = parser.current();
-
- if (!parser.eat('}')) {
- parser.require_whitespace();
- await_block[is_then ? 'value' : 'error'] = read_context(parser);
- parser.allow_whitespace();
- parser.eat('}', true);
- }
-
- const new_block: TemplateNode = {
- start,
- // @ts-ignore
- end: null,
- type: is_then ? 'ThenBlock' : 'CatchBlock',
- children: [],
- skip: false,
- };
-
- await_block[is_then ? 'then' : 'catch'] = new_block;
- parser.stack.push(new_block);
- } else if (parser.eat('#')) {
- // {#if foo}, {#each foo} or {#await foo}
- let type;
-
- if (parser.eat('if')) {
- type = 'IfBlock';
- } else if (parser.eat('each')) {
- type = 'EachBlock';
- } else if (parser.eat('await')) {
- type = 'AwaitBlock';
- } else if (parser.eat('key')) {
- type = 'KeyBlock';
- } else {
- parser.error({
- code: 'expected-block-type',
- message: 'Expected if, each, await or key',
- });
- }
-
- parser.require_whitespace();
-
- const expression = read_expression(parser);
-
- // @ts-ignore
- const block: TemplateNode =
- type === 'AwaitBlock'
- ? {
- start,
- end: null,
- type,
- expression,
- value: null,
- error: null,
- pending: {
- start: null,
- end: null,
- type: 'PendingBlock',
- children: [],
- skip: true,
- },
- then: {
- start: null,
- end: null,
- type: 'ThenBlock',
- children: [],
- skip: true,
- },
- catch: {
- start: null,
- end: null,
- type: 'CatchBlock',
- children: [],
- skip: true,
- },
- }
- : {
- start,
- end: null,
- type,
- expression,
- children: [],
- };
-
- parser.allow_whitespace();
-
- // {#each} blocks must declare a context – {#each list as item}
- if (type === 'EachBlock') {
- parser.eat('as', true);
- parser.require_whitespace();
-
- block.context = read_context(parser);
-
- parser.allow_whitespace();
-
- if (parser.eat(',')) {
- parser.allow_whitespace();
- block.index = parser.read_identifier();
- if (!block.index) {
- parser.error({
- code: 'expected-name',
- message: 'Expected name',
- });
- }
-
- parser.allow_whitespace();
- }
-
- if (parser.eat('(')) {
- parser.allow_whitespace();
-
- block.key = read_expression(parser);
- parser.allow_whitespace();
- parser.eat(')', true);
- parser.allow_whitespace();
- }
- }
-
- const await_block_shorthand = type === 'AwaitBlock' && parser.eat('then');
- if (await_block_shorthand) {
- parser.require_whitespace();
- block.value = read_context(parser);
- parser.allow_whitespace();
- }
-
- const await_block_catch_shorthand = !await_block_shorthand && type === 'AwaitBlock' && parser.eat('catch');
- if (await_block_catch_shorthand) {
- parser.require_whitespace();
- block.error = read_context(parser);
- parser.allow_whitespace();
- }
-
- parser.eat('}', true);
-
- // @ts-ignore
- parser.current().children.push(block);
- parser.stack.push(block);
-
- if (type === 'AwaitBlock') {
- let child_block;
- if (await_block_shorthand) {
- block.then.skip = false;
- child_block = block.then;
- } else if (await_block_catch_shorthand) {
- block.catch.skip = false;
- child_block = block.catch;
- } else {
- block.pending.skip = false;
- child_block = block.pending;
- }
-
- child_block.start = parser.index;
- parser.stack.push(child_block);
- }
- } else if (parser.eat('@html')) {
- // {@html content} tag
- parser.require_whitespace();
-
- const expression = read_expression(parser);
-
- parser.allow_whitespace();
- parser.eat('}', true);
-
- // @ts-ignore
- parser.current().children.push({
- start,
- end: parser.index,
- type: 'RawMustacheTag',
- expression,
- });
- } else if (parser.eat('@debug')) {
- // let identifiers;
-
- // // Implies {@debug} which indicates "debug all"
- // if (parser.read(/\s*}/)) {
- // identifiers = [];
- // } else {
- // const expression = read_expression(parser);
-
- // identifiers = expression.type === 'SequenceExpression'
- // ? expression.expressions
- // : [expression];
-
- // identifiers.forEach(node => {
- // if (node.type !== 'Identifier') {
- // parser.error({
- // code: 'invalid-debug-args',
- // message: '{@debug ...} arguments must be identifiers, not arbitrary expressions'
- // }, node.start);
- // }
- // });
-
- // parser.allow_whitespace();
- // parser.eat('}', true);
- // }
-
- // parser.current().children.push({
- // start,
- // end: parser.index,
- // type: 'DebugTag',
- // identifiers
- // });
- throw new Error('@debug not yet supported');
- } else {
- const expression = read_expression(parser);
-
- parser.allow_whitespace();
- parser.eat('}', true);
-
- // @ts-ignore
- parser.current().children.push({
- start,
- end: parser.index,
- type: 'MustacheTag',
- expression,
- });
- }
-}
diff --git a/src/compiler/parse/state/setup.ts b/src/compiler/parse/state/setup.ts
deleted file mode 100644
index f64d8c52b..000000000
--- a/src/compiler/parse/state/setup.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-// @ts-nocheck
-
-import { Parser } from '../index.js';
-
-export default function setup(parser: Parser): void {
- // TODO: Error if not at top of file? currently, we ignore / just treat as text.
- // if (parser.html.children.length > 0) {
- // parser.error({
- // code: 'unexpected-token',
- // message: 'Frontmatter scripts only supported at the top of file.',
- // });
- // }
-
- const start = parser.index;
- parser.index += 3;
- const content_start = parser.index;
- const setupScriptContent = parser.read_until(/^---/m);
- const content_end = parser.index;
- parser.eat('---', true);
- const end = parser.index;
- parser.js.push({
- type: 'Script',
- context: 'setup',
- start,
- end,
- content: setupScriptContent,
- // attributes,
- // content: {
- // start: content_start,
- // end: content_end,
- // styles,
- // },
- });
- return;
-}
diff --git a/src/compiler/parse/state/tag.ts b/src/compiler/parse/state/tag.ts
deleted file mode 100644
index c6684874c..000000000
--- a/src/compiler/parse/state/tag.ts
+++ /dev/null
@@ -1,579 +0,0 @@
-// @ts-nocheck
-
-import read_expression from '../read/expression.js';
-import read_script from '../read/script.js';
-import read_style from '../read/style.js';
-import { decode_character_references, closing_tag_omitted } from '../utils/html.js';
-import { is_void } from '../../utils/names.js';
-import { Parser } from '../index.js';
-import { Directive, DirectiveType, TemplateNode, Text } from '../../interfaces.js';
-import fuzzymatch from '../../utils/fuzzymatch.js';
-import list from '../../utils/list.js';
-
-// eslint-disable-next-line no-useless-escape
-const valid_tag_name = /^\!?[a-zA-Z]{1,}:?[a-zA-Z0-9\-]*/;
-
-const meta_tags = new Map([
- ['astro:head', 'Head'],
- // ['slot:body', 'Body'],
- // ['astro:options', 'Options'],
- // ['astro:window', 'Window'],
- // ['astro:body', 'Body'],
-]);
-
-const valid_meta_tags = Array.from(meta_tags.keys()); //.concat('astro:self', 'astro:component', 'astro:fragment');
-
-const specials = new Map([
- // Now handled as "setup" in setup.ts
- // [
- // 'script',
- // {
- // read: read_script,
- // property: 'js',
- // },
- // ],
- [
- 'style',
- {
- read: read_style,
- property: 'css',
- },
- ],
-]);
-
-const SELF = /^astro:self(?=[\s/>])/;
-const COMPONENT = /^astro:component(?=[\s/>])/;
-const SLOT = /^astro:fragment(?=[\s/>])/;
-const HEAD = /^head(?=[\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;
-}
-
-export default function tag(parser: Parser) {
- const start = parser.index++;
-
- let parent = parser.current();
-
- if (parser.eat('!--')) {
- const data = parser.read_until(/-->/);
- parser.eat('-->', true, 'comment was left open, expected -->');
-
- parser.current().children.push({
- start,
- end: parser.index,
- type: 'Comment',
- 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 === 'astro:window' || name === 'astro:body') && parser.current().children.length) {
- parser.error(
- {
- code: `invalid-${slug}-content`,
- message: `<${name}> cannot have children`,
- },
- parser.current().children[0].start
- );
- }
- } else {
- if (name in parser.meta_tags) {
- parser.error(
- {
- code: `duplicate-${slug}`,
- message: `A component can only have one <${name}> tag`,
- },
- start
- );
- }
-
- if (parser.stack.length > 1) {
- parser.error(
- {
- code: `invalid-${slug}-placement`,
- message: `<${name}> tags cannot be inside elements or blocks`,
- },
- start
- );
- }
-
- parser.meta_tags[name] = true;
- }
- }
-
- const type = meta_tags.has(name)
- ? meta_tags.get(name)
- : /[A-Z]/.test(name[0]) || name === 'astro:self' || name === 'astro:component'
- ? 'InlineComponent'
- : name === 'astro:fragment'
- ? 'SlotTemplate'
- : name === 'title' && parent_is_head(parser.stack)
- ? 'Title'
- : name === 'slot' && !parser.customElement
- ? '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(
- {
- code: 'invalid-void-content',
- message: `<${name}> is a void element and cannot have children, or a closing tag`,
- },
- start
- );
- }
-
- parser.eat('>', true);
-
- // close any elements that don't have their own closing tags, e.g. <div><p></div>
- while (parent.name !== name) {
- if (parent.type !== 'Element') {
- const message =
- parser.last_auto_closed_tag && parser.last_auto_closed_tag.tag === name
- ? `</${name}> attempted to close <${name}> that was already automatically closed by <${parser.last_auto_closed_tag.reason}>`
- : `</${name}> attempted to close an element that was not open`;
- parser.error(
- {
- code: 'invalid-closing-tag',
- message,
- },
- 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<string> = new Set();
-
- let attribute;
- while ((attribute = read_attribute(parser, unique_names))) {
- element.attributes.push(attribute);
- parser.allow_whitespace();
- }
-
- if (name === 'astro:component') {
- const index = element.attributes.findIndex((attr) => attr.type === 'Attribute' && attr.name === 'this');
- if (!~index) {
- parser.error(
- {
- code: 'missing-component-definition',
- message: "<astro:component> must have a 'this' attribute",
- },
- start
- );
- }
-
- const definition = element.attributes.splice(index, 1)[0];
- if (definition.value === true || definition.value.length !== 1 || definition.value[0].type === 'Text') {
- parser.error(
- {
- code: 'invalid-component-definition',
- message: 'invalid component definition',
- },
- definition.start
- );
- }
-
- element.expression = definition.value[0].expression;
- }
-
- // special cases – top-level <script> and <style>
- if (specials.has(name) && parser.stack.length === 1) {
- const special = specials.get(name);
-
- parser.eat('>', true);
- const content = special.read(parser, start, element.attributes);
- if (content) parser[special.property].push(content);
- return;
- }
-
- parser.current().children.push(element);
-
- const self_closing = parser.eat('/') || is_void(name);
-
- parser.eat('>', true);
-
- if (self_closing) {
- // don't push self-closing elements onto the stack
- element.end = parser.index;
- } else if (name === 'textarea') {
- // special case
- element.children = read_sequence(parser, () => parser.template.slice(parser.index, parser.index + 11) === '</textarea>');
- parser.read(/<\/textarea>/);
- element.end = parser.index;
- } else if (name === 'script' || name === 'style') {
- // special case
- const start = parser.index;
- const data = parser.read_until(new RegExp(`</${name}>`));
- const end = parser.index;
- element.children.push({ start, end, type: 'Text', data });
- parser.eat(`</${name}>`, true);
- element.end = parser.index;
- } else {
- parser.stack.push(element);
- }
-}
-
-function read_tag_name(parser: Parser) {
- const start = parser.index;
-
- if (parser.read(SELF)) {
- // check we're inside a block, otherwise this
- // will cause infinite recursion
- let i = parser.stack.length;
- let legal = false;
-
- while (i--) {
- const fragment = parser.stack[i];
- if (fragment.type === 'IfBlock' || fragment.type === 'EachBlock' || fragment.type === 'InlineComponent') {
- legal = true;
- break;
- }
- }
-
- if (!legal) {
- parser.error(
- {
- code: 'invalid-self-placement',
- message: '<astro:self> components can only exist inside {#if} blocks, {#each} blocks, or slots passed to components',
- },
- start
- );
- }
-
- return 'astro:self';
- }
-
- if (parser.read(COMPONENT)) return 'astro:component';
-
- if (parser.read(SLOT)) return 'astro:fragment';
-
- if (parser.read(HEAD)) return 'head';
-
- const name = parser.read_until(/(\s|\/|>)/);
-
- if (meta_tags.has(name)) return name;
-
- if (name.startsWith('astro:')) {
- const match = fuzzymatch(name.slice(7), valid_meta_tags);
-
- let message = `Valid <astro:...> tag names are ${list(valid_meta_tags)}`;
- if (match) message += ` (did you mean '${match}'?)`;
-
- parser.error(
- {
- code: 'invalid-tag-name',
- message,
- },
- start
- );
- }
-
- if (!valid_tag_name.test(name)) {
- parser.error(
- {
- code: 'invalid-tag-name',
- message: 'Expected valid tag name',
- },
- start
- );
- }
-
- return name;
-}
-
-function read_attribute(parser: Parser, unique_names: Set<string>) {
- const start = parser.index;
-
- function check_unique(name: string) {
- if (unique_names.has(name)) {
- parser.error(
- {
- code: 'duplicate-attribute',
- message: 'Attributes need to be unique',
- },
- start
- );
- }
- unique_names.add(name);
- }
-
- if (parser.eat('{')) {
- parser.allow_whitespace();
-
- if (parser.eat('...')) {
- const expression = read_expression(parser);
-
- parser.allow_whitespace();
- parser.eat('}', true);
-
- return {
- start,
- end: parser.index,
- type: 'Spread',
- expression,
- };
- } else {
- const value_start = parser.index;
-
- const name = parser.read_identifier();
- parser.allow_whitespace();
- parser.eat('}', true);
-
- check_unique(name);
-
- return {
- start,
- end: parser.index,
- type: 'Attribute',
- name,
- value: [
- {
- start: value_start,
- end: value_start + name.length,
- type: 'AttributeShorthand',
- expression: {
- start: value_start,
- end: value_start + name.length,
- type: 'Identifier',
- name,
- },
- },
- ],
- };
- }
- }
-
- // eslint-disable-next-line no-useless-escape
- const name = parser.read_until(/[\s=\/>"']/);
- if (!name) return null;
-
- let end = parser.index;
-
- parser.allow_whitespace();
-
- const colon_index = name.indexOf(':');
- const type = colon_index !== -1 && get_directive_type(name.slice(0, colon_index));
-
- let value: any[] | true = true;
- if (parser.eat('=')) {
- parser.allow_whitespace();
- value = read_attribute_value(parser);
- end = parser.index;
- } else if (parser.match_regex(/["']/)) {
- parser.error(
- {
- code: 'unexpected-token',
- message: 'Expected =',
- },
- parser.index
- );
- }
-
- if (type) {
- const [directive_name, ...modifiers] = name.slice(colon_index + 1).split('|');
-
- if (type === 'Binding' && directive_name !== 'this') {
- check_unique(directive_name);
- } else if (type !== 'EventHandler' && type !== 'Action') {
- check_unique(name);
- }
-
- if (type === 'Ref') {
- parser.error(
- {
- code: 'invalid-ref-directive',
- message: `The ref directive is no longer supported — use \`bind:this={${directive_name}}\` instead`,
- },
- start
- );
- }
-
- if (type === 'Class' && directive_name === '') {
- parser.error(
- {
- code: 'invalid-class-directive',
- message: 'Class binding name cannot be empty',
- },
- start + colon_index + 1
- );
- }
-
- if (value[0]) {
- if ((value as any[]).length > 1 || value[0].type === 'Text') {
- parser.error(
- {
- code: 'invalid-directive-value',
- message: 'Directive value must be a JavaScript expression enclosed in curly braces',
- },
- value[0].start
- );
- }
- }
-
- const directive: Directive = {
- start,
- end,
- type,
- name: directive_name,
- modifiers,
- expression: (value[0] && value[0].expression) || null,
- };
-
- if (type === 'Transition') {
- const direction = name.slice(0, colon_index);
- directive.intro = direction === 'in' || direction === 'transition';
- directive.outro = direction === 'out' || direction === 'transition';
- }
-
- if (!directive.expression && (type === 'Binding' || type === 'Class')) {
- directive.expression = {
- start: directive.start + colon_index + 1,
- end: directive.end,
- type: 'Identifier',
- name: directive.name,
- } as any;
- }
-
- return directive;
- }
-
- check_unique(name);
-
- return {
- start,
- end,
- type: 'Attribute',
- name,
- value,
- };
-}
-
-function get_directive_type(name: string): DirectiveType {
- if (name === 'use') return 'Action';
- if (name === 'animate') return 'Animation';
- if (name === 'bind') return 'Binding';
- if (name === 'class') return 'Class';
- if (name === 'on') return 'EventHandler';
- if (name === 'let') return 'Let';
- if (name === 'ref') return 'Ref';
- if (name === 'in' || name === 'out' || name === 'transition') return 'Transition';
-}
-
-function read_attribute_value(parser: Parser) {
- const quote_mark = parser.eat("'") ? "'" : parser.eat('"') ? '"' : null;
-
- const regex = quote_mark === "'" ? /'/ : quote_mark === '"' ? /"/ : /(\/>|[\s"'=<>`])/;
-
- const value = read_sequence(parser, () => !!parser.match_regex(regex));
-
- if (quote_mark) parser.index += 1;
- return value;
-}
-
-function read_sequence(parser: Parser, done: () => boolean): TemplateNode[] {
- let current_chunk: Text = {
- start: parser.index,
- end: null,
- type: 'Text',
- raw: '',
- data: null,
- };
-
- function flush() {
- if (current_chunk.raw) {
- current_chunk.data = decode_character_references(current_chunk.raw);
- current_chunk.end = parser.index;
- chunks.push(current_chunk);
- }
- }
-
- const chunks: TemplateNode[] = [];
-
- while (parser.index < parser.template.length) {
- const index = parser.index;
-
- if (done()) {
- flush();
- return chunks;
- } else if (parser.eat('{')) {
- flush();
-
- parser.allow_whitespace();
- const expression = read_expression(parser);
- parser.allow_whitespace();
- parser.eat('}', true);
-
- chunks.push({
- start: index,
- end: parser.index,
- type: 'MustacheTag',
- expression,
- });
-
- current_chunk = {
- start: parser.index,
- end: null,
- type: 'Text',
- raw: '',
- data: null,
- };
- } else {
- current_chunk.raw += parser.template[parser.index++];
- }
- }
-
- parser.error({
- code: 'unexpected-eof',
- message: 'Unexpected end of input',
- });
-}
diff --git a/src/compiler/parse/state/text.ts b/src/compiler/parse/state/text.ts
deleted file mode 100644
index cca83f2d4..000000000
--- a/src/compiler/parse/state/text.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-// @ts-nocheck
-
-import { decode_character_references } from '../utils/html.js';
-import { Parser } from '../index.js';
-
-export default function text(parser: Parser) {
- const start = parser.index;
-
- let data = '';
-
- while (parser.index < parser.template.length && !parser.match('---') && !parser.match('<') && !parser.match('{')) {
- data += parser.template[parser.index++];
- }
-
- const node = {
- start,
- end: parser.index,
- type: 'Text',
- raw: data,
- data: decode_character_references(data),
- };
-
- parser.current().children.push(node);
-}