Merge pull request #2809 from mrkishi/closing-tags

Allow end tag omission in blocks
pull/3538/head
Rich Harris 5 years ago committed by GitHub
commit 961021a73b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,5 +1,6 @@
import read_context from '../read/context';
import read_expression from '../read/expression';
import { closing_tag_omitted } from '../utils/html';
import { whitespace } from '../../utils/patterns';
import { trim_start, trim_end } from '../../utils/trim';
import { Parser } from '../index';
@ -41,6 +42,12 @@ export default function mustache(parser: Parser) {
let block = parser.current();
let expected;
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();

@ -1,7 +1,7 @@
import read_expression from '../read/expression';
import read_script from '../read/script';
import read_style from '../read/style';
import { decode_character_references } from '../utils/html';
import { decode_character_references, closing_tag_omitted } from '../utils/html';
import { is_void } from '../../utils/names';
import { Parser } from '../index';
import { Directive, DirectiveType, Node, Text } from '../../interfaces';
@ -42,31 +42,6 @@ const SELF = /^svelte:self(?=[\s\/>])/;
// eslint-disable-next-line no-useless-escape
const COMPONENT = /^svelte:component(?=[\s\/>])/;
// based on http://developers.whatwg.org/syntax.html#syntax-tag-omission
const disallowed_contents = new Map([
['li', new Set(['li'])],
['dt', new Set(['dt', 'dd'])],
['dd', new Set(['dt', 'dd'])],
[
'p',
new Set(
'address article aside blockquote div dl fieldset footer form h1 h2 h3 h4 h5 h6 header hgroup hr main menu nav ol p pre section table ul'.split(
' '
)
),
],
['rt', new Set(['rt', 'rp'])],
['rp', new Set(['rt', 'rp'])],
['optgroup', new Set(['optgroup'])],
['option', new Set(['option', 'optgroup'])],
['thead', new Set(['tbody', 'tfoot'])],
['tbody', new Set(['tbody', 'tfoot'])],
['tfoot', new Set(['tbody'])],
['tr', new Set(['tr', 'tbody'])],
['td', new Set(['td', 'th', 'tr'])],
['th', new Set(['td', 'th', 'tr'])],
]);
function parent_is_head(stack) {
let i = stack.length;
while (i--) {
@ -176,13 +151,9 @@ export default function tag(parser: Parser) {
parser.stack.pop();
return;
} else if (disallowed_contents.has(parent.name)) {
// can this be a child of the parent element, or does it implicitly
// close it, like `<li>one<li>two`?
if (disallowed_contents.get(parent.name).has(name)) {
parent.end = start;
parser.stack.pop();
}
} else if (closing_tag_omitted(parent.name, name)) {
parent.end = start;
parser.stack.pop();
}
const unique_names: Set<string> = new Set();

@ -112,3 +112,40 @@ function validate_code(code: number) {
return NUL;
}
// based on http://developers.whatwg.org/syntax.html#syntax-tag-omission
const disallowed_contents = new Map([
['li', new Set(['li'])],
['dt', new Set(['dt', 'dd'])],
['dd', new Set(['dt', 'dd'])],
[
'p',
new Set(
'address article aside blockquote div dl fieldset footer form h1 h2 h3 h4 h5 h6 header hgroup hr main menu nav ol p pre section table ul'.split(
' '
)
),
],
['rt', new Set(['rt', 'rp'])],
['rp', new Set(['rt', 'rp'])],
['optgroup', new Set(['optgroup'])],
['option', new Set(['option', 'optgroup'])],
['thead', new Set(['tbody', 'tfoot'])],
['tbody', new Set(['tbody', 'tfoot'])],
['tfoot', new Set(['tbody'])],
['tr', new Set(['tr', 'tbody'])],
['td', new Set(['td', 'th', 'tr'])],
['th', new Set(['td', 'th', 'tr'])],
]);
// can this be a child of the parent element, or does it implicitly
// close it, like `<li>one<li>two`?
export function closing_tag_omitted(current: string, next?: string) {
if (disallowed_contents.has(current)) {
if (!next || disallowed_contents.get(current).has(next)) {
return true;
}
}
return false;
}

@ -0,0 +1,7 @@
<ul>
<li>a
{#if true}
<li>b
{/if}
<li>c
</ul>

@ -0,0 +1,94 @@
{
"html": {
"start": 0,
"end": 51,
"type": "Fragment",
"children": [
{
"start": 0,
"end": 51,
"type": "Element",
"name": "ul",
"attributes": [],
"children": [
{
"start": 4,
"end": 6,
"type": "Text",
"raw": "\n\t",
"data": "\n\t"
},
{
"start": 6,
"end": 40,
"type": "Element",
"name": "li",
"attributes": [],
"children": [
{
"start": 10,
"end": 13,
"type": "Text",
"raw": "a\n\t",
"data": "a\n\t"
},
{
"start": 13,
"end": 38,
"type": "IfBlock",
"expression": {
"type": "Literal",
"start": 18,
"end": 22,
"value": true,
"raw": "true"
},
"children": [
{
"start": 26,
"end": 33,
"type": "Element",
"name": "li",
"attributes": [],
"children": [
{
"start": 30,
"end": 33,
"type": "Text",
"raw": "b\n\t",
"data": "b\n\t"
}
]
}
]
},
{
"start": 38,
"end": 40,
"type": "Text",
"raw": "\n\t",
"data": "\n\t"
}
]
},
{
"start": 40,
"end": 46,
"type": "Element",
"name": "li",
"attributes": [],
"children": [
{
"start": 44,
"end": 46,
"type": "Text",
"raw": "c\n",
"data": "c\n"
}
]
}
]
}
]
}
}
Loading…
Cancel
Save