ecmarkup
Version:
Custom element definitions and core utilities for markup that specifies ECMAScript and related technologies.
108 lines (107 loc) • 3.73 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.printText = printText;
const line_builder_1 = require("./line-builder");
const entities = require('../../entities-processed.json');
function isBadNumericReference(codePoint) {
// https://html.spec.whatwg.org/multipage/parsing.html#numeric-character-reference-end-state
if (
// NULL character
!codePoint ||
// out of range
codePoint > 0x10ffff ||
// surrogate
(0xd800 <= codePoint && codePoint <= 0xdfff) ||
// noncharacter
(0xfdd0 <= codePoint && codePoint <= 0xfdef) ||
(codePoint & 0xfffe) === 0xfffe ||
// control character (but without exceptions for tab/line feed/form feed/space)
(0 <= codePoint && codePoint <= 0x1f) ||
(0x7f <= codePoint && codePoint <= 0x9f)) {
return true;
}
return false;
}
function printText(text, indent, commonIndent = '') {
const output = new line_builder_1.LineBuilder(indent);
if (text === '') {
return output;
}
text = text.replace(/&(?:[a-zA-Z0-9]+|#[Xx]([0-9a-fA-F]+)|#([0-9]+));?/g, (m, hex, decimal) => {
if (hex || decimal) {
// pass through bad references,
// normalize '&' and '<' into named references,
// and transform everything else
const codePoint = parseInt(hex || decimal, hex ? 16 : 10);
if (isBadNumericReference(codePoint)) {
return m;
}
const ch = String.fromCodePoint(codePoint);
if (/\p{White_Space}|\p{DI}|\p{gc=M}|\p{gc=C}/u.test(ch)) {
return m;
}
if (ch === '&') {
return '&';
}
else if (ch === '<') {
return '<';
}
return ch;
}
// entities[m] is null if the entity expands to '&', '<', or a string which has blank/control/etc characters
if ({}.hasOwnProperty.call(entities, m) && entities[m] !== null) {
return entities[m];
}
const lower = m.toLowerCase();
if (lower === '<' || lower === '&') {
return lower;
}
else if (lower === '<' || lower === '&') {
return lower + ';';
}
return m;
});
const leadingSpace = text[0] === ' ' || text[0] === '\t';
const trailingSpace = text[text.length - 1] === ' ' || text[text.length - 1] === '\t';
const lines = text.split('\n').map((l, i) => {
var _a;
if (i === 0 || commonIndent === '' || !l.startsWith(commonIndent)) {
return l.trim();
}
const withoutIndent = l.substring(commonIndent.length);
const moreIndent = (_a = withoutIndent.match(/^ +/)) === null || _a === void 0 ? void 0 : _a[0];
if (moreIndent) {
return { indent: moreIndent, line: l.trim() };
}
return l.trim();
});
if (leadingSpace) {
output.appendText(' ');
}
if (lines.length === 1) {
if (lines[0] !== '') {
output.appendText(lines[0]);
if (trailingSpace) {
output.appendText(' ');
}
}
return output;
}
for (let i = 0; i < lines.length; ++i) {
const line = lines[i];
if (typeof line === 'string') {
output.appendText(line);
}
else {
output.last = line.indent;
output.appendText(line.line);
}
if (i < lines.length - 1) {
output.linebreak();
}
}
if (trailingSpace && output.last !== '') {
output.appendText(' ');
}
return output;
}
;