svelte-parse
Version:
An increidbly relaxed svelte-parser
1,764 lines (1,632 loc) • 34.5 kB
text/typescript
import { test, expect } from 'vitest';
import {
SvelteElement,
SvelteComponent,
Text,
SvelteMeta,
Comment,
Node,
Point,
} from 'svast';
import { parseNode, parse } from '../src/main';
import { void_els } from '../src/void_els';
const childParser: () => [Node[], Point & { index?: number }, number] = () => [
[<Node>{ type: 'fake' }],
{ line: 1, column: 1, offset: 0, index: 0 },
0,
];
test('parses a self closing tag without attributes', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<input />`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [],
});
});
test('parses self closing elements with no whistespace after tagName', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<div/>`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'div',
selfClosing: true,
children: [],
properties: [],
});
});
test('parses a self closing tag without attributes: space before name', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `< input />`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [],
});
});
test('parses a self closing tag without attributes: space after name', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `< input />`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [],
});
});
test('parses a self closing tag without attributes: space after closeing slash', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `< input / >`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [],
});
});
test('parses a self closing component without attributes', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<HelloFriend />`,
});
expect(parsed).toEqual(<SvelteComponent>{
type: 'svelteComponent',
tagName: 'HelloFriend',
selfClosing: true,
children: [],
properties: [],
});
});
Object.keys(void_els).forEach((el) => {
test(`parses all void tags without attributes: < ${el} >`, () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<${el} >`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: el,
selfClosing: true,
children: [],
properties: [],
});
});
});
test('parses attribute values containing colons', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<a href=https://www.google.com />`,
});
expect(parsed).toEqual({
type: 'svelteElement',
tagName: 'a',
selfClosing: true,
children: [],
properties: [
{
type: 'svelteProperty',
name: 'href',
value: [
{
type: 'text',
value: 'https://www.google.com',
},
],
modifiers: [],
shorthand: 'none',
},
],
});
});
test('parses a self closing tag with shorthand boolean attribute', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<input hello />`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [
{
type: 'svelteProperty',
name: 'hello',
value: [],
shorthand: 'boolean',
modifiers: [],
},
],
});
});
test('parses a self closing tag with shorthand boolean attribute: weird spacing', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<input hello / >`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [
{
type: 'svelteProperty',
name: 'hello',
value: [],
shorthand: 'boolean',
modifiers: [],
},
],
});
});
test('parses a self closing tag with shorthand boolean attribute: no trailing space', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<input hello/>`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [
{
type: 'svelteProperty',
name: 'hello',
value: [],
shorthand: 'boolean',
modifiers: [],
},
],
});
});
test('parses a void tag with shorthand boolean attribute: no trailing space', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<input hello>`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [
{
type: 'svelteProperty',
name: 'hello',
value: [],
shorthand: 'boolean',
modifiers: [],
},
],
});
});
test('parses a self-closing tag with multiple shorthand boolean attributes: trailing space', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<input hello goodbye />`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [
{
type: 'svelteProperty',
name: 'hello',
value: [],
shorthand: 'boolean',
modifiers: [],
},
{
type: 'svelteProperty',
name: 'goodbye',
value: [],
shorthand: 'boolean',
modifiers: [],
},
],
});
});
test('parses a self-closing tag with multiple shorthand boolean attributes: weird spacing', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `< input hello goodbye / >`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [
{
type: 'svelteProperty',
name: 'hello',
value: [],
shorthand: 'boolean',
modifiers: [],
},
{
type: 'svelteProperty',
name: 'goodbye',
value: [],
shorthand: 'boolean',
modifiers: [],
},
],
});
});
test('parses a self-closing tag with multiple shorthand boolean attributes: no trailing space', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<input hello goodbye/>`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [
{
type: 'svelteProperty',
name: 'hello',
value: [],
shorthand: 'boolean',
modifiers: [],
},
{
type: 'svelteProperty',
name: 'goodbye',
value: [],
shorthand: 'boolean',
modifiers: [],
},
],
});
});
test('parses a void tag with multiple shorthand boolean attributes: no trailing space', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<input hello goodbye>`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [
{
type: 'svelteProperty',
name: 'hello',
value: [],
shorthand: 'boolean',
modifiers: [],
},
{
type: 'svelteProperty',
name: 'goodbye',
value: [],
shorthand: 'boolean',
modifiers: [],
},
],
});
});
test('parses a void tag with multiple shorthand boolean attributes: trailing space', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<input hello goodbye >`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [
{
type: 'svelteProperty',
name: 'hello',
value: [],
shorthand: 'boolean',
modifiers: [],
},
{
type: 'svelteProperty',
name: 'goodbye',
value: [],
shorthand: 'boolean',
modifiers: [],
},
],
});
});
test('parses a self-closing tag with an unquoted attribute: trailing space', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<input hello=value />`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [
{
type: 'svelteProperty',
name: 'hello',
value: [
{
type: 'text',
value: 'value',
},
],
shorthand: 'none',
modifiers: [],
},
],
});
});
test('parses a self-closing tag with an unquoted attribute: no trailing space', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<input hello=value/>`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [
{
type: 'svelteProperty',
name: 'hello',
value: [
{
type: 'text',
value: 'value',
},
],
shorthand: 'none',
modifiers: [],
},
],
});
});
test('parses a void tag with an unquoted attribute: trailing space', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<input hello=value >`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [
{
type: 'svelteProperty',
name: 'hello',
value: [
{
type: 'text',
value: 'value',
},
],
shorthand: 'none',
modifiers: [],
},
],
});
});
test('parses a self-closing tag with an unquoted attribute: no trailing space', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<input hello=value>`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [
{
type: 'svelteProperty',
name: 'hello',
value: [
{
type: 'text',
value: 'value',
},
],
shorthand: 'none',
modifiers: [],
},
],
});
});
test('parses a self-closing tag with a double-quoted attribute: trailing space', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<input hello="value" />`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [
{
type: 'svelteProperty',
name: 'hello',
value: [
{
type: 'text',
value: 'value',
},
],
shorthand: 'none',
modifiers: [],
},
],
});
});
test('parses a self-closing tag with a double-quoted attribute: no trailing space', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<input hello="value"/>`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [
{
type: 'svelteProperty',
name: 'hello',
value: [
{
type: 'text',
value: 'value',
},
],
shorthand: 'none',
modifiers: [],
},
],
});
});
test('parses a void tag with a double-quoted attribute: trailing space', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<input hello="value" >`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [
{
type: 'svelteProperty',
name: 'hello',
value: [
{
type: 'text',
value: 'value',
},
],
shorthand: 'none',
modifiers: [],
},
],
});
});
test('parses a void tag with a double-quoted attribute: no trailing space', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<input hello="value">`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [
{
type: 'svelteProperty',
name: 'hello',
value: [
{
type: 'text',
value: 'value',
},
],
shorthand: 'none',
modifiers: [],
},
],
});
});
test('parses a self-closing tag with double-quoted attributes: many values, trailing whitespace', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<input hello="value valuetwo" />`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [
{
type: 'svelteProperty',
name: 'hello',
value: [
{
type: 'text',
value: 'value',
},
{
type: 'text',
value: ' ',
},
{
type: 'text',
value: 'valuetwo',
},
],
shorthand: 'none',
modifiers: [],
},
],
});
});
test('parses a self-closing tag with double-quoted attributes: many values, no trailing whitespace', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<input hello="value valuetwo"/>`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [
{
type: 'svelteProperty',
name: 'hello',
value: [
{
type: 'text',
value: 'value',
},
{ type: 'text', value: ' ' },
{
type: 'text',
value: 'valuetwo',
},
],
shorthand: 'none',
modifiers: [],
},
],
});
});
test('parses a void tag with double-quoted attributes: many values, trailing whitespace', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<input hello="value valuetwo" >`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [
{
type: 'svelteProperty',
name: 'hello',
value: [
{
type: 'text',
value: 'value',
},
{ type: 'text', value: ' ' },
{
type: 'text',
value: 'valuetwo',
},
],
shorthand: 'none',
modifiers: [],
},
],
});
});
test('parses a void tag with double-quoted attributes: many values, no trailing whitespace', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<input hello="value valuetwo">`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [
{
type: 'svelteProperty',
name: 'hello',
value: [
{
type: 'text',
value: 'value',
},
{ type: 'text', value: ' ' },
{
type: 'text',
value: 'valuetwo',
},
],
shorthand: 'none',
modifiers: [],
},
],
});
});
test('parses a self-closing tag with a single-quoted attribute: trailing space', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<input hello='value' />`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [
{
type: 'svelteProperty',
name: 'hello',
value: [
{
type: 'text',
value: 'value',
},
],
shorthand: 'none',
modifiers: [],
},
],
});
});
test('parses a self-closing tag with a single-quoted attribute: no trailing space', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<input hello='value'/>`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [
{
type: 'svelteProperty',
name: 'hello',
value: [
{
type: 'text',
value: 'value',
},
],
shorthand: 'none',
modifiers: [],
},
],
});
});
test('parses a void tag with a single-quoted attribute: trailing space', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<input hello='value' >`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [
{
type: 'svelteProperty',
name: 'hello',
value: [
{
type: 'text',
value: 'value',
},
],
shorthand: 'none',
modifiers: [],
},
],
});
});
test('parses a void tag with a single-quoted attribute: no trailing space', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<input hello='value'>`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [
{
type: 'svelteProperty',
name: 'hello',
value: [
{
type: 'text',
value: 'value',
},
],
shorthand: 'none',
modifiers: [],
},
],
});
});
test('parses a self-closing tag with single-quoted attributes: many values, trailing whitespace', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<input hello='value valuetwo' />`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [
{
type: 'svelteProperty',
name: 'hello',
value: [
{
type: 'text',
value: 'value',
},
{ type: 'text', value: ' ' },
{
type: 'text',
value: 'valuetwo',
},
],
shorthand: 'none',
modifiers: [],
},
],
});
});
test('parses a self-closing tag with single-quoted attributes: many values, no trailing whitespace', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<input hello='value valuetwo'/>`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [
{
type: 'svelteProperty',
name: 'hello',
value: [
{
type: 'text',
value: 'value',
},
{ type: 'text', value: ' ' },
{
type: 'text',
value: 'valuetwo',
},
],
shorthand: 'none',
modifiers: [],
},
],
});
});
test('parses a void tag with single-quoted attributes: many values, trailing whitespace', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<input hello='value valuetwo' >`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [
{
type: 'svelteProperty',
name: 'hello',
value: [
{
type: 'text',
value: 'value',
},
{ type: 'text', value: ' ' },
{
type: 'text',
value: 'valuetwo',
},
],
shorthand: 'none',
modifiers: [],
},
],
});
});
test('parses a void tag with single-quoted attributes: many values, no trailing whitespace', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<input hello='value valuetwo'>`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [
{
type: 'svelteProperty',
name: 'hello',
value: [
{
type: 'text',
value: 'value',
},
{ type: 'text', value: ' ' },
{
type: 'text',
value: 'valuetwo',
},
],
shorthand: 'none',
modifiers: [],
},
],
});
});
test('parses a void tag with a directive', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<input hello:world >`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [
{
type: 'svelteDirective',
name: 'hello',
specifier: 'world',
value: [],
shorthand: 'none',
modifiers: [],
},
],
});
});
test('parses a self-closing tag with a directive', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<input hello:world />`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [
{
type: 'svelteDirective',
name: 'hello',
specifier: 'world',
value: [],
shorthand: 'none',
modifiers: [],
},
],
});
});
test('parses a self-closing tag with two directives', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<input hello:world goodbye:friends />`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [
{
type: 'svelteDirective',
name: 'hello',
specifier: 'world',
value: [],
shorthand: 'none',
modifiers: [],
},
{
type: 'svelteDirective',
name: 'goodbye',
specifier: 'friends',
value: [],
shorthand: 'none',
modifiers: [],
},
],
});
});
test('parses a tag with a directive an a directive value: double-quoted', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<input hello:world="cheese" />`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [
{
type: 'svelteDirective',
name: 'hello',
specifier: 'world',
value: [{ type: 'text', value: 'cheese' }],
shorthand: 'none',
modifiers: [],
},
],
});
});
test('parses a tag with a directive an a directive value: double-quoted, two values', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<input hello:world="cheese strings" />`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [
{
type: 'svelteDirective',
name: 'hello',
specifier: 'world',
value: [
{ type: 'text', value: 'cheese' },
{ type: 'text', value: ' ' },
{ type: 'text', value: 'strings' },
],
shorthand: 'none',
modifiers: [],
},
],
});
});
test('parses a tag with a directive an a directive value: single-quoted, two values', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<input hello:world='cheese strings' />`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [
{
type: 'svelteDirective',
name: 'hello',
specifier: 'world',
value: [
{ type: 'text', value: 'cheese' },
{ type: 'text', value: ' ' },
{ type: 'text', value: 'strings' },
],
shorthand: 'none',
modifiers: [],
},
],
});
});
test('parses a tag with a directive an a directive value: single-quoted, two values, many spaces', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<input hello:world='cheese strings' />`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [
{
type: 'svelteDirective',
name: 'hello',
specifier: 'world',
value: [
{ type: 'text', value: 'cheese' },
{ type: 'text', value: ' ' },
{ type: 'text', value: 'strings' },
],
shorthand: 'none',
modifiers: [],
},
],
});
});
test('parses a tag with a directive an a directive value: unquoted', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<input hello:world="cheese" />`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [
{
type: 'svelteDirective',
name: 'hello',
specifier: 'world',
value: [{ type: 'text', value: 'cheese' }],
shorthand: 'none',
modifiers: [],
},
],
});
});
test('parses a tag with a directive with modifiers', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<input hello:world|modifierval />`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [
{
type: 'svelteDirective',
name: 'hello',
specifier: 'world',
value: [],
shorthand: 'none',
modifiers: [{ type: 'modifier', value: 'modifierval' }],
},
],
});
});
test('parses a tag with a directive with modifier but no value', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<a on:click|preventDefault booleanAttribute/>`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'a',
selfClosing: true,
children: [],
properties: [
{
type: 'svelteDirective',
name: 'on',
specifier: 'click',
value: [],
shorthand: 'none',
modifiers: [{ type: 'modifier', value: 'preventDefault' }],
},
{
type: 'svelteProperty',
name: 'booleanAttribute',
value: [],
shorthand: 'boolean',
modifiers: [],
},
],
});
});
test('parses a tag with a directive with multiple modifiers', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<input hello:world|modifierval|modifierval2 />`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [
{
type: 'svelteDirective',
name: 'hello',
specifier: 'world',
value: [],
shorthand: 'none',
modifiers: [
{ type: 'modifier', value: 'modifierval' },
{ type: 'modifier', value: 'modifierval2' },
],
},
],
});
});
test('parses a tag with a directive with modifiers', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<input hello|modifierval />`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [
{
type: 'svelteProperty',
name: 'hello',
value: [],
shorthand: 'none',
modifiers: [{ type: 'modifier', value: 'modifierval' }],
},
],
});
});
test('parses a tag with a directive with multiple modifiers', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<input hello|modifierval|modifierval2 />`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [
{
type: 'svelteProperty',
name: 'hello',
value: [],
shorthand: 'none',
modifiers: [
{ type: 'modifier', value: 'modifierval' },
{ type: 'modifier', value: 'modifierval2' },
],
},
],
});
});
test('parses a tag with an attribute with multiple modifiers and a value', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<input hello:world|modifierval|modifierval2=someval />`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [
{
type: 'svelteDirective',
name: 'hello',
specifier: 'world',
value: [{ type: 'text', value: 'someval' }],
shorthand: 'none',
modifiers: [
{ type: 'modifier', value: 'modifierval' },
{ type: 'modifier', value: 'modifierval2' },
],
},
],
});
});
test('parses a tag with an attribute with multiple modifiers and a value: weird spacing', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `< input hello:world|modifierval|modifierval2 = someval / >`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [
{
type: 'svelteDirective',
name: 'hello',
specifier: 'world',
value: [{ type: 'text', value: 'someval' }],
shorthand: 'none',
modifiers: [
{ type: 'modifier', value: 'modifierval' },
{ type: 'modifier', value: 'modifierval2' },
],
},
],
});
});
test('parses a tag with an attribute with multiple modifiers and a value: weird spacing, double-quotes', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `< input hello:world|modifierval|modifierval2 = "someval" / >`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [
{
type: 'svelteDirective',
name: 'hello',
specifier: 'world',
value: [{ type: 'text', value: 'someval' }],
shorthand: 'none',
modifiers: [
{ type: 'modifier', value: 'modifierval' },
{ type: 'modifier', value: 'modifierval2' },
],
},
],
});
});
test('parses a tag with an attribute with multiple modifiers and a value: weird spacing and newlines', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<
input
hello:world|modifierval|modifierval2
=
"someval"
/
>`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'input',
selfClosing: true,
children: [],
properties: [
{
type: 'svelteDirective',
name: 'hello',
specifier: 'world',
value: [{ type: 'text', value: 'someval' }],
shorthand: 'none',
modifiers: [
{ type: 'modifier', value: 'modifierval' },
{ type: 'modifier', value: 'modifierval2' },
],
},
],
});
});
test('parses text', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `hail`,
});
expect(parsed).toEqual(<Text>{
type: 'text',
value: 'hail',
});
});
test('parses quoted attribute expressions with space', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<button disabled="{!first || !last}" />`,
});
expect(parsed).toEqual(<SvelteElement>{
type: 'svelteElement',
tagName: 'button',
properties: [
{
type: 'svelteProperty',
name: 'disabled',
value: [
{
type: 'svelteDynamicContent',
expression: {
type: 'svelteExpression',
value: '!first || !last',
},
},
],
shorthand: 'none',
modifiers: [],
},
],
selfClosing: true,
children: [],
});
});
test('parses svelte special elements', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<svelte:options tag={null} />`,
});
expect(parsed).toEqual(<SvelteMeta>{
type: 'svelteMeta',
tagName: 'options',
properties: [
{
type: 'svelteProperty',
name: 'tag',
value: [
{
type: 'svelteDynamicContent',
expression: {
type: 'svelteExpression',
value: 'null',
},
},
],
shorthand: 'none',
modifiers: [],
},
],
selfClosing: true,
children: [],
});
});
test('parses svelte special elements', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<svelte:options tag={null} />`,
});
expect(parsed).toEqual(<SvelteMeta>{
type: 'svelteMeta',
tagName: 'options',
properties: [
{
type: 'svelteProperty',
name: 'tag',
value: [
{
type: 'svelteDynamicContent',
expression: {
type: 'svelteExpression',
value: 'null',
},
},
],
shorthand: 'none',
modifiers: [],
},
],
selfClosing: true,
children: [],
});
});
test('parses html comments: no spaces', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<!--comment text-->`,
});
expect(parsed).toEqual(<Comment>{
type: 'comment',
value: 'comment text',
});
});
test('parses html comments: spaces and newlines', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<!--
comment text
-->`,
});
expect(parsed).toEqual(<Comment>{
type: 'comment',
value: '\n\n\n\t\tcomment text \n\t\t\n\t\t\n',
});
});
//
test('parses shorthand expressions: failing test case', () => {
//@ts-ignore
const { parsed } = parseNode({
generatePositions: false,
childParser,
value: `<Avatar alt="{initials}" {size}></Avatar>`,
});
expect(parsed).toEqual({
type: 'svelteComponent',
tagName: 'Avatar',
properties: [
{
type: 'svelteProperty',
name: 'alt',
modifiers: [],
shorthand: 'none',
value: [
{
type: 'svelteDynamicContent',
expression: {
type: 'svelteExpression',
value: 'initials',
},
},
],
},
{
type: 'svelteProperty',
name: 'size',
modifiers: [],
shorthand: 'expression',
value: [
{
type: 'svelteDynamicContent',
expression: {
type: 'svelteExpression',
value: 'size',
},
},
],
},
],
children: [{ type: 'fake' }],
selfClosing: false,
});
});