@ -2,13 +2,14 @@
* Map of elements that have certain elements that are not allowed inside them , in the sense that they will auto - close the parent / ancestor element .
* Map of elements that have certain elements that are not allowed inside them , in the sense that they will auto - close the parent / ancestor element .
* Theoretically one could take advantage of it but most of the time it will just result in confusing behavior and break when SSR ' d .
* Theoretically one could take advantage of it but most of the time it will just result in confusing behavior and break when SSR ' d .
* There are more elements that are invalid inside other elements , but they 're not auto-closed and so don' t break SSR and are therefore not listed here .
* There are more elements that are invalid inside other elements , but they 're not auto-closed and so don' t break SSR and are therefore not listed here .
* @ type { Record < string , { direct : string [ ] } | { descendant : string [ ] } > }
* @ type { Record < string , { direct : string [ ] } | { descendant : string [ ] ; reset _by ? : string [ ] } > }
* /
* /
const autoclosing _children = {
const autoclosing _children = {
// based on http://developers.whatwg.org/syntax.html#syntax-tag-omission
// based on http://developers.whatwg.org/syntax.html#syntax-tag-omission
li : { direct : [ 'li' ] } ,
li : { direct : [ 'li' ] } ,
dt : { descendant : [ 'dt' , 'dd' ] } ,
// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dt#technical_summary
dd : { descendant : [ 'dt' , 'dd' ] } ,
dt : { descendant : [ 'dt' , 'dd' ] , reset _by : [ 'dl' ] } ,
dd : { descendant : [ 'dt' , 'dd' ] , reset _by : [ 'dl' ] } ,
p : {
p : {
descendant : [
descendant : [
'address' ,
'address' ,
@ -75,7 +76,7 @@ export function closing_tag_omitted(current, next) {
/ * *
/ * *
* Map of elements that have certain elements that are not allowed inside them , in the sense that the browser will somehow repair the HTML .
* Map of elements that have certain elements that are not allowed inside them , in the sense that the browser will somehow repair the HTML .
* There are more elements that are invalid inside other elements , but they 're not repaired and so don' t break SSR and are therefore not listed here .
* There are more elements that are invalid inside other elements , but they 're not repaired and so don' t break SSR and are therefore not listed here .
* @ type { Record < string , { direct : string [ ] } | { descendant : string [ ] ; only? : string [ ] } | { only : string [ ] } > }
* @ type { Record < string , { direct : string [ ] } | { descendant : string [ ] ; reset_by ? : string [ ] ; only? : string [ ] } | { only : string [ ] } > }
* /
* /
const disallowed _children = {
const disallowed _children = {
... autoclosing _children ,
... autoclosing _children ,
@ -137,12 +138,24 @@ const disallowed_children = {
* Returns false if the tag is not allowed inside the ancestor tag ( which is grandparent and above ) such that it will result
* Returns false if the tag is not allowed inside the ancestor tag ( which is grandparent and above ) such that it will result
* in the browser repairing the HTML , which will likely result in an error during hydration .
* in the browser repairing the HTML , which will likely result in an error during hydration .
* @ param { string } tag
* @ param { string } tag
* @ param { string } ancestor Must not be the parent , but higher up the tree
* @ param { string [] } ancestors All nodes starting with the parent , up until the ancestor , which means two entries minimum
* @ returns { boolean }
* @ returns { boolean }
* /
* /
export function is _tag _valid _with _ancestor ( tag , ancestor ) {
export function is _tag _valid _with _ancestor ( tag , ancestors ) {
const disallowed = disallowed _children [ ancestor ] ;
const target = ancestors [ ancestors . length - 1 ] ;
return ! disallowed || ( 'descendant' in disallowed ? ! disallowed . descendant . includes ( tag ) : true ) ;
const disallowed = disallowed _children [ target ] ;
if ( ! disallowed ) return true ;
if ( 'reset_by' in disallowed && disallowed . reset _by ) {
for ( let i = ancestors . length - 2 ; i >= 0 ; i -- ) {
// A reset means that forbidden descendants are allowed again
if ( disallowed . reset _by . includes ( ancestors [ i ] ) ) {
return true ;
}
}
}
return 'descendant' in disallowed ? ! disallowed . descendant . includes ( tag ) : true ;
}
}
/ * *
/ * *