11import { type CompilerError , compile } from '../../src'
2+ import { isValidHTMLNesting } from '../../src/htmlNesting'
23
34describe ( 'validate html nesting' , ( ) => {
45 it ( 'should warn with p > div' , ( ) => {
@@ -17,4 +18,185 @@ describe('validate html nesting', () => {
1718 } )
1819 expect ( err ) . toBeUndefined ( )
1920 } )
21+
22+ // #13318
23+ it ( 'should not warn when parent tag is template' , ( ) => {
24+ let err : CompilerError | undefined
25+ compile ( `<template><tr/></template>` , {
26+ onWarn : e => ( err = e ) ,
27+ } )
28+ expect ( err ) . toBeUndefined ( )
29+ } )
30+ } )
31+
32+ /**
33+ * Copied from https://github.com/MananTank/validate-html-nesting
34+ * with ISC license
35+ */
36+ describe ( 'isValidHTMLNesting' , ( ) => {
37+ test ( 'form' , ( ) => {
38+ // invalid
39+ expect ( isValidHTMLNesting ( 'form' , 'form' ) ) . toBe ( false )
40+
41+ // valid
42+ expect ( isValidHTMLNesting ( 'form' , 'div' ) ) . toBe ( true )
43+ expect ( isValidHTMLNesting ( 'form' , 'input' ) ) . toBe ( true )
44+ expect ( isValidHTMLNesting ( 'form' , 'select' ) ) . toBe ( true )
45+ expect ( isValidHTMLNesting ( 'form' , 'button' ) ) . toBe ( true )
46+ expect ( isValidHTMLNesting ( 'form' , 'label' ) ) . toBe ( true )
47+ expect ( isValidHTMLNesting ( 'form' , 'h1' ) ) . toBe ( true )
48+ } )
49+
50+ test ( 'p' , ( ) => {
51+ // invalid
52+ expect ( isValidHTMLNesting ( 'p' , 'p' ) ) . toBe ( false )
53+ expect ( isValidHTMLNesting ( 'p' , 'div' ) ) . toBe ( false )
54+ expect ( isValidHTMLNesting ( 'p' , 'hr' ) ) . toBe ( false )
55+ expect ( isValidHTMLNesting ( 'p' , 'blockquote' ) ) . toBe ( false )
56+ expect ( isValidHTMLNesting ( 'p' , 'pre' ) ) . toBe ( false )
57+
58+ // valid
59+ expect ( isValidHTMLNesting ( 'p' , 'a' ) ) . toBe ( true )
60+ expect ( isValidHTMLNesting ( 'p' , 'span' ) ) . toBe ( true )
61+ expect ( isValidHTMLNesting ( 'p' , 'abbr' ) ) . toBe ( true )
62+ expect ( isValidHTMLNesting ( 'p' , 'button' ) ) . toBe ( true )
63+ expect ( isValidHTMLNesting ( 'p' , 'b' ) ) . toBe ( true )
64+ expect ( isValidHTMLNesting ( 'p' , 'i' ) ) . toBe ( true )
65+ expect ( isValidHTMLNesting ( 'p' , 'input' ) ) . toBe ( true )
66+ expect ( isValidHTMLNesting ( 'p' , 'label' ) ) . toBe ( true )
67+ } )
68+
69+ test ( 'a' , ( ) => {
70+ // invalid
71+ expect ( isValidHTMLNesting ( 'a' , 'a' ) ) . toBe ( false )
72+
73+ // valid
74+ expect ( isValidHTMLNesting ( 'a' , 'div' ) ) . toBe ( true )
75+ expect ( isValidHTMLNesting ( 'a' , 'span' ) ) . toBe ( true )
76+ } )
77+
78+ test ( 'button' , ( ) => {
79+ // invalid
80+ expect ( isValidHTMLNesting ( 'button' , 'button' ) ) . toBe ( false )
81+
82+ // valid
83+ expect ( isValidHTMLNesting ( 'button' , 'div' ) ) . toBe ( true )
84+ expect ( isValidHTMLNesting ( 'button' , 'span' ) ) . toBe ( true )
85+ } )
86+
87+ test ( 'table' , ( ) => {
88+ // invalid
89+ expect ( isValidHTMLNesting ( 'table' , 'tr' ) ) . toBe ( false )
90+ expect ( isValidHTMLNesting ( 'table' , 'table' ) ) . toBe ( false )
91+ expect ( isValidHTMLNesting ( 'table' , 'td' ) ) . toBe ( false )
92+
93+ // valid
94+ expect ( isValidHTMLNesting ( 'table' , 'thead' ) ) . toBe ( true )
95+ expect ( isValidHTMLNesting ( 'table' , 'tbody' ) ) . toBe ( true )
96+ expect ( isValidHTMLNesting ( 'table' , 'tfoot' ) ) . toBe ( true )
97+ expect ( isValidHTMLNesting ( 'table' , 'caption' ) ) . toBe ( true )
98+ expect ( isValidHTMLNesting ( 'table' , 'colgroup' ) ) . toBe ( true )
99+ } )
100+
101+ test ( 'td' , ( ) => {
102+ // valid
103+ expect ( isValidHTMLNesting ( 'td' , 'span' ) ) . toBe ( true )
104+ expect ( isValidHTMLNesting ( 'tr' , 'td' ) ) . toBe ( true )
105+
106+ // invalid
107+ expect ( isValidHTMLNesting ( 'td' , 'td' ) ) . toBe ( false )
108+ expect ( isValidHTMLNesting ( 'div' , 'td' ) ) . toBe ( false )
109+ } )
110+
111+ test ( 'tbody' , ( ) => {
112+ // invalid
113+ expect ( isValidHTMLNesting ( 'tbody' , 'td' ) ) . toBe ( false )
114+
115+ // valid
116+ expect ( isValidHTMLNesting ( 'tbody' , 'tr' ) ) . toBe ( true )
117+ } )
118+
119+ test ( 'tr' , ( ) => {
120+ // invalid
121+ expect ( isValidHTMLNesting ( 'tr' , 'tr' ) ) . toBe ( false )
122+ expect ( isValidHTMLNesting ( 'table' , 'tr' ) ) . toBe ( false )
123+
124+ // valid
125+ expect ( isValidHTMLNesting ( 'tbody' , 'tr' ) ) . toBe ( true )
126+ expect ( isValidHTMLNesting ( 'thead' , 'tr' ) ) . toBe ( true )
127+ expect ( isValidHTMLNesting ( 'tfoot' , 'tr' ) ) . toBe ( true )
128+ expect ( isValidHTMLNesting ( 'tr' , 'td' ) ) . toBe ( true )
129+ expect ( isValidHTMLNesting ( 'tr' , 'th' ) ) . toBe ( true )
130+ } )
131+
132+ test ( 'li' , ( ) => {
133+ // invalid
134+ expect ( isValidHTMLNesting ( 'li' , 'li' ) ) . toBe ( false )
135+ // valid
136+ expect ( isValidHTMLNesting ( 'li' , 'div' ) ) . toBe ( true )
137+ expect ( isValidHTMLNesting ( 'li' , 'ul' ) ) . toBe ( true )
138+ } )
139+
140+ test ( 'headings' , ( ) => {
141+ // invalid
142+ expect ( isValidHTMLNesting ( 'h1' , 'h1' ) ) . toBe ( false )
143+ expect ( isValidHTMLNesting ( 'h2' , 'h1' ) ) . toBe ( false )
144+ expect ( isValidHTMLNesting ( 'h3' , 'h1' ) ) . toBe ( false )
145+ expect ( isValidHTMLNesting ( 'h1' , 'h6' ) ) . toBe ( false )
146+
147+ // valid
148+ expect ( isValidHTMLNesting ( 'h1' , 'div' ) ) . toBe ( true )
149+ } )
150+
151+ describe ( 'SVG' , ( ) => {
152+ test ( 'svg' , ( ) => {
153+ // invalid non-svg tags as children
154+ expect ( isValidHTMLNesting ( 'svg' , 'div' ) ) . toBe ( false )
155+ expect ( isValidHTMLNesting ( 'svg' , 'img' ) ) . toBe ( false )
156+ expect ( isValidHTMLNesting ( 'svg' , 'p' ) ) . toBe ( false )
157+ expect ( isValidHTMLNesting ( 'svg' , 'h2' ) ) . toBe ( false )
158+ expect ( isValidHTMLNesting ( 'svg' , 'span' ) ) . toBe ( false )
159+
160+ // valid non-svg tags as children
161+ expect ( isValidHTMLNesting ( 'svg' , 'a' ) ) . toBe ( true )
162+ expect ( isValidHTMLNesting ( 'svg' , 'textarea' ) ) . toBe ( true )
163+ expect ( isValidHTMLNesting ( 'svg' , 'input' ) ) . toBe ( true )
164+ expect ( isValidHTMLNesting ( 'svg' , 'select' ) ) . toBe ( true )
165+
166+ // valid svg tags as children
167+ expect ( isValidHTMLNesting ( 'svg' , 'g' ) ) . toBe ( true )
168+ expect ( isValidHTMLNesting ( 'svg' , 'ellipse' ) ) . toBe ( true )
169+ expect ( isValidHTMLNesting ( 'svg' , 'feOffset' ) ) . toBe ( true )
170+ } )
171+
172+ test ( 'foreignObject' , ( ) => {
173+ // valid
174+ expect ( isValidHTMLNesting ( 'foreignObject' , 'g' ) ) . toBe ( true )
175+ expect ( isValidHTMLNesting ( 'foreignObject' , 'div' ) ) . toBe ( true )
176+ expect ( isValidHTMLNesting ( 'foreignObject' , 'a' ) ) . toBe ( true )
177+ expect ( isValidHTMLNesting ( 'foreignObject' , 'textarea' ) ) . toBe ( true )
178+ } )
179+
180+ test ( 'g' , ( ) => {
181+ // valid
182+ expect ( isValidHTMLNesting ( 'g' , 'div' ) ) . toBe ( true )
183+ expect ( isValidHTMLNesting ( 'g' , 'p' ) ) . toBe ( true )
184+ expect ( isValidHTMLNesting ( 'g' , 'a' ) ) . toBe ( true )
185+ expect ( isValidHTMLNesting ( 'g' , 'textarea' ) ) . toBe ( true )
186+ expect ( isValidHTMLNesting ( 'g' , 'g' ) ) . toBe ( true )
187+ } )
188+
189+ test ( 'dl' , ( ) => {
190+ // valid
191+ expect ( isValidHTMLNesting ( 'dl' , 'dt' ) ) . toBe ( true )
192+ expect ( isValidHTMLNesting ( 'dl' , 'dd' ) ) . toBe ( true )
193+ expect ( isValidHTMLNesting ( 'dl' , 'div' ) ) . toBe ( true )
194+ expect ( isValidHTMLNesting ( 'div' , 'dt' ) ) . toBe ( true )
195+ expect ( isValidHTMLNesting ( 'div' , 'dd' ) ) . toBe ( true )
196+
197+ // invalid
198+ expect ( isValidHTMLNesting ( 'span' , 'dt' ) ) . toBe ( false )
199+ expect ( isValidHTMLNesting ( 'span' , 'dd' ) ) . toBe ( false )
200+ } )
201+ } )
20202} )
0 commit comments