Lint and format src/compiler/parse/utils/html.js

pull/8569/head
Simon Holthausen 3 years ago
parent 2c471b88a2
commit 2c541f66c1

@ -1,7 +1,7 @@
import entities from './entities.js'; import entities from './entities.js';
const windows_1252 = [ const windows_1252 = [
8364, 129, 8218, 402, 8222, 8230, 8224, 8225, 710, 8240, 352, 8249, 338, 141, 381, 143, 144, 8216, 8364, 129, 8218, 402, 8222, 8230, 8224, 8225, 710, 8240, 352, 8249, 338, 141, 381, 143, 144, 8216,
8217, 8220, 8221, 8226, 8211, 8212, 732, 8482, 353, 8250, 339, 157, 382, 376 8217, 8220, 8221, 8226, 8211, 8212, 732, 8482, 353, 8250, 339, 157, 382, 376
]; ];
/** /**
@ -9,22 +9,24 @@ const windows_1252 = [
* @param {boolean} is_attribute_value * @param {boolean} is_attribute_value
*/ */
function reg_exp_entity(entity_name, is_attribute_value) { function reg_exp_entity(entity_name, is_attribute_value) {
// https://html.spec.whatwg.org/multipage/parsing.html#named-character-reference-state // https://html.spec.whatwg.org/multipage/parsing.html#named-character-reference-state
// doesn't decode the html entity which not ends with ; and next character is =, number or alphabet in attribute value. // doesn't decode the html entity which not ends with ; and next character is =, number or alphabet in attribute value.
if (is_attribute_value && !entity_name.endsWith(';')) { if (is_attribute_value && !entity_name.endsWith(';')) {
return `${entity_name}\\b(?!=)`; return `${entity_name}\\b(?!=)`;
} }
return entity_name; return entity_name;
} }
/** /**
* @param {boolean} is_attribute_value * @param {boolean} is_attribute_value
*/ */
function get_entity_pattern(is_attribute_value) { function get_entity_pattern(is_attribute_value) {
const reg_exp_num = '#(?:x[a-fA-F\\d]+|\\d+)(?:;)?'; const reg_exp_num = '#(?:x[a-fA-F\\d]+|\\d+)(?:;)?';
const reg_exp_entities = Object.keys(entities).map((entity_name) => reg_exp_entity(entity_name, is_attribute_value)); const reg_exp_entities = Object.keys(entities).map((entity_name) =>
const entity_pattern = new RegExp(`&(${reg_exp_num}|${reg_exp_entities.join('|')})`, 'g'); reg_exp_entity(entity_name, is_attribute_value)
return entity_pattern; );
const entity_pattern = new RegExp(`&(${reg_exp_num}|${reg_exp_entities.join('|')})`, 'g');
return entity_pattern;
} }
const entity_pattern_content = get_entity_pattern(false); const entity_pattern_content = get_entity_pattern(false);
const entity_pattern_attr_value = get_entity_pattern(true); const entity_pattern_attr_value = get_entity_pattern(true);
@ -34,24 +36,22 @@ const entity_pattern_attr_value = get_entity_pattern(true);
* @param {boolean} is_attribute_value * @param {boolean} is_attribute_value
*/ */
export function decode_character_references(html, is_attribute_value) { export function decode_character_references(html, is_attribute_value) {
const entity_pattern = is_attribute_value ? entity_pattern_attr_value : entity_pattern_content; const entity_pattern = is_attribute_value ? entity_pattern_attr_value : entity_pattern_content;
return html.replace(entity_pattern, (match, entity) => { return html.replace(entity_pattern, (match, entity) => {
let code; let code;
// Handle named entities // Handle named entities
if (entity[0] !== '#') { if (entity[0] !== '#') {
code = entities[entity]; code = entities[entity];
} } else if (entity[1] === 'x') {
else if (entity[1] === 'x') { code = parseInt(entity.substring(2), 16);
code = parseInt(entity.substring(2), 16); } else {
} code = parseInt(entity.substring(1), 10);
else { }
code = parseInt(entity.substring(1), 10); if (!code) {
} return match;
if (!code) { }
return match; return String.fromCodePoint(validate_code(code));
} });
return String.fromCodePoint(validate_code(code));
});
} }
const NUL = 0; const NUL = 0;
// some code points are verboten. If we were inserting HTML, the browser would replace the illegal // some code points are verboten. If we were inserting HTML, the browser would replace the illegal
@ -64,60 +64,64 @@ const NUL = 0;
* @param {number} code * @param {number} code
*/ */
function validate_code(code) { function validate_code(code) {
// line feed becomes generic whitespace // line feed becomes generic whitespace
if (code === 10) { if (code === 10) {
return 32; return 32;
} }
// ASCII range. (Why someone would use HTML entities for ASCII characters I don't know, but...) // ASCII range. (Why someone would use HTML entities for ASCII characters I don't know, but...)
if (code < 128) { if (code < 128) {
return code; return code;
} }
// code points 128-159 are dealt with leniently by browsers, but they're incorrect. We need // code points 128-159 are dealt with leniently by browsers, but they're incorrect. We need
// to correct the mistake or we'll end up with missing € signs and so on // to correct the mistake or we'll end up with missing € signs and so on
if (code <= 159) { if (code <= 159) {
return windows_1252[code - 128]; return windows_1252[code - 128];
} }
// basic multilingual plane // basic multilingual plane
if (code < 55296) { if (code < 55296) {
return code; return code;
} }
// UTF-16 surrogate halves // UTF-16 surrogate halves
if (code <= 57343) { if (code <= 57343) {
return NUL; return NUL;
} }
// rest of the basic multilingual plane // rest of the basic multilingual plane
if (code <= 65535) { if (code <= 65535) {
return code; return code;
} }
// supplementary multilingual plane 0x10000 - 0x1ffff // supplementary multilingual plane 0x10000 - 0x1ffff
if (code >= 65536 && code <= 131071) { if (code >= 65536 && code <= 131071) {
return code; return code;
} }
// supplementary ideographic plane 0x20000 - 0x2ffff // supplementary ideographic plane 0x20000 - 0x2ffff
if (code >= 131072 && code <= 196607) { if (code >= 131072 && code <= 196607) {
return code; return code;
} }
return NUL; return NUL;
} }
// based on http://developers.whatwg.org/syntax.html#syntax-tag-omission // based on http://developers.whatwg.org/syntax.html#syntax-tag-omission
const disallowed_contents = new Map([ const disallowed_contents = new Map([
['li', new Set(['li'])], ['li', new Set(['li'])],
['dt', new Set(['dt', 'dd'])], ['dt', new Set(['dt', 'dd'])],
['dd', new Set(['dt', 'dd'])], ['dd', new Set(['dt', 'dd'])],
[ [
'p', '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(' ')) 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'])], ['rt', new Set(['rt', 'rp'])],
['tbody', new Set(['tbody', 'tfoot'])], ['rp', new Set(['rt', 'rp'])],
['tfoot', new Set(['tbody'])], ['optgroup', new Set(['optgroup'])],
['tr', new Set(['tr', 'tbody'])], ['option', new Set(['option', 'optgroup'])],
['td', new Set(['td', 'th', 'tr'])], ['thead', new Set(['tbody', 'tfoot'])],
['th', new Set(['td', 'th', 'tr'])] ['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 // can this be a child of the parent element, or does it implicitly
// close it, like `<li>one<li>two`? // close it, like `<li>one<li>two`?
@ -127,14 +131,10 @@ const disallowed_contents = new Map([
* @param {string} next * @param {string} next
*/ */
export function closing_tag_omitted(current, next) { export function closing_tag_omitted(current, next) {
if (disallowed_contents.has(current)) { if (disallowed_contents.has(current)) {
if (!next || disallowed_contents.get(current).has(next)) { if (!next || disallowed_contents.get(current).has(next)) {
return true; return true;
} }
} }
return false; return false;
} }

Loading…
Cancel
Save