@ -12,6 +12,7 @@ import { create_fragment } from '../utils/create.js';
import { create _attribute , create _expression _metadata } from '../../nodes.js' ;
import { create _attribute , create _expression _metadata } from '../../nodes.js' ;
import { get _attribute _expression , is _expression _attribute } from '../../../utils/ast.js' ;
import { get _attribute _expression , is _expression _attribute } from '../../../utils/ast.js' ;
import { closing _tag _omitted } from '../../../../html-tree-validation.js' ;
import { closing _tag _omitted } from '../../../../html-tree-validation.js' ;
import { list } from '../../../utils/string.js' ;
// eslint-disable-next-line no-useless-escape
// eslint-disable-next-line no-useless-escape
const valid _tag _name = /^\!?[a-zA-Z]{1,}:?[a-zA-Z0-9\-]*/ ;
const valid _tag _name = /^\!?[a-zA-Z]{1,}:?[a-zA-Z0-9\-]*/ ;
@ -20,7 +21,7 @@ const valid_tag_name = /^\!?[a-zA-Z]{1,}:?[a-zA-Z0-9\-]*/;
const regex _starts _with _invalid _attr _value = /^(\/>|[\s"'=<>`])/ ;
const regex _starts _with _invalid _attr _value = /^(\/>|[\s"'=<>`])/ ;
/** @type {Map<string, Compiler.ElementLike['type']>} */
/** @type {Map<string, Compiler.ElementLike['type']>} */
const root _only _ meta_tag s = new Map ( [
const root _only _ special_element s = new Map ( [
[ 'svelte:head' , 'SvelteHead' ] ,
[ 'svelte:head' , 'SvelteHead' ] ,
[ 'svelte:options' , 'SvelteOptions' ] ,
[ 'svelte:options' , 'SvelteOptions' ] ,
[ 'svelte:window' , 'SvelteWindow' ] ,
[ 'svelte:window' , 'SvelteWindow' ] ,
@ -29,21 +30,14 @@ const root_only_meta_tags = new Map([
] ) ;
] ) ;
/** @type {Map<string, Compiler.ElementLike['type']>} */
/** @type {Map<string, Compiler.ElementLike['type']>} */
const meta_tag s = new Map ( [
const special_element s = new Map ( [
... root _only _ meta_tag s,
... root _only _ special_element s,
[ 'svelte:element' , 'SvelteElement' ] ,
[ 'svelte:element' , 'SvelteElement' ] ,
[ 'svelte:component' , 'SvelteComponent' ] ,
[ 'svelte:component' , 'SvelteComponent' ] ,
[ 'svelte:self' , 'SvelteSelf' ] ,
[ 'svelte:self' , 'SvelteSelf' ] ,
[ 'svelte:fragment' , 'SvelteFragment' ]
[ 'svelte:fragment' , 'SvelteFragment' ]
] ) ;
] ) ;
const valid _meta _tags = Array . from ( meta _tags . keys ( ) ) ;
const SELF = /^svelte:self(?=[\s/>])/ ;
const COMPONENT = /^svelte:component(?=[\s/>])/ ;
const SLOT = /^svelte:fragment(?=[\s/>])/ ;
const ELEMENT = /^svelte:element(?=[\s/>])/ ;
/** @param {Compiler.TemplateNode[]} stack */
/** @param {Compiler.TemplateNode[]} stack */
function parent _is _head ( stack ) {
function parent _is _head ( stack ) {
let i = stack . length ;
let i = stack . length ;
@ -103,7 +97,7 @@ export default function element(parser) {
const name = read _tag _name ( parser ) ;
const name = read _tag _name ( parser ) ;
if ( root _only _ meta_tag s. has ( name ) ) {
if ( root _only _ special_element s. has ( name ) ) {
if ( is _closing _tag ) {
if ( is _closing _tag ) {
if (
if (
[ 'svelte:options' , 'svelte:window' , 'svelte:body' , 'svelte:document' ] . includes ( name ) &&
[ 'svelte:options' , 'svelte:window' , 'svelte:body' , 'svelte:document' ] . includes ( name ) &&
@ -127,8 +121,8 @@ export default function element(parser) {
}
}
}
}
const type = meta_tag s. has ( name )
const type = special_element s. has ( name )
? meta_tag s. get ( name )
? special_element s. get ( name )
: regex _component _name . test ( name )
: regex _component _name . test ( name )
? 'Component'
? 'Component'
: name === 'title' && parent _is _head ( parser . stack )
: name === 'title' && parent _is _head ( parser . stack )
@ -392,48 +386,17 @@ const regex_whitespace_or_slash_or_closing_tag = /(\s|\/|>)/;
function read _tag _name ( parser ) {
function read _tag _name ( parser ) {
const start = parser . index ;
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 === 'Component' ||
fragment . type === 'SnippetBlock'
) {
legal = true ;
break ;
}
}
if ( ! legal ) {
e . svelte _self _invalid _placement ( start ) ;
}
return 'svelte:self' ;
}
if ( parser . read ( COMPONENT ) ) return 'svelte:component' ;
if ( parser . read ( ELEMENT ) ) return 'svelte:element' ;
if ( parser . read ( SLOT ) ) return 'svelte:fragment' ;
const name = parser . read _until ( regex _whitespace _or _slash _or _closing _tag ) ;
const name = parser . read _until ( regex _whitespace _or _slash _or _closing _tag ) ;
if ( special _elements . has ( name ) ) return name ;
if ( meta _tags . has ( name ) ) return name ;
const end = start + name . length ;
if ( name . startsWith ( 'svelte:' ) ) {
if ( name . startsWith ( 'svelte:' ) ) {
const list = ` ${ valid _meta _tags . slice ( 0 , - 1 ) . join ( ', ' ) } or ${ valid _meta _tags [ valid _meta _tags . length - 1 ] } ` ;
e . svelte _meta _invalid _tag ( { start , end } , list ( Array . from ( special _elements . keys ( ) ) ) ) ;
e . svelte _meta _invalid _tag ( start , list ) ;
}
}
if ( ! valid _tag _name . test ( name ) ) {
if ( ! valid _tag _name . test ( name ) ) {
e . element _invalid _tag _name ( start ) ;
e . element _invalid _tag _name ( { start , end } ) ;
}
}
return name ;
return name ;