UNPKG

typesxml

Version:

Open source XML library written in TypeScript

257 lines 9.71 kB
"use strict"; /******************************************************************************* * Copyright (c) 2023-2026 Maxprograms. * * This program and the accompanying materials * are made available under the terms of the Eclipse License 1.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/org/documents/epl-v10.html * * Contributors: * Maxprograms - initial API and implementation *******************************************************************************/ Object.defineProperty(exports, "__esModule", { value: true }); exports.XMLUtils = void 0; class XMLUtils { static SPACES = ' \t\r\n'; static cleanString(text) { let result = XMLUtils.replaceAll(text, '&', '&amp;'); result = XMLUtils.replaceAll(result, '<', '&lt;'); return XMLUtils.replaceAll(result, '>', '&gt;'); } static unquote(text) { return XMLUtils.replaceAll(text, '"', '&quot;'); } static normalizeLines(text) { let result = XMLUtils.replaceAll(text, '\r\n', '\n'); return XMLUtils.replaceAll(result, '\r', '\n'); } static isXmlSpace(char) { return this.SPACES.includes(char); } static hasParameterEntity(text) { let index = text.indexOf('%'); if (index === -1) { return false; } let length = text.length; for (let i = index + 1; i < length; i++) { let c = text.charAt(i); if (this.isXmlSpace(c)) { return false; } if (c === ';') { return true; } } return false; } static normalizeSpaces(text) { return String(text).replaceAll(/\s+/g, ' '); } static replaceAll(text, search, replacement) { return String(text).split(search).join(replacement); } static escapeRegExpChars(text) { let result = ''; let length = text.length; for (let i = 0; i < length; i++) { let c = text.charAt(i); if ('[]{}()^$?*+.'.includes(c)) { result += '\\'; } result += c; } return result; } static validXml10Chars(text) { let result = ''; for (let i = 0; i < text.length;) { const codePoint = text.codePointAt(i); if (XMLUtils.isValidXml10Char(codePoint)) { result += String.fromCodePoint(codePoint); } i += codePoint > 0xFFFF ? 2 : 1; } return result; } static isValidXml10Char(c) { // From XML 1.0 spec valid chars: // #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] // any Unicode character, excluding the surrogate blocks, FFFE, and FFFF. return c === 0x9 || c == 0xA || c === 0xD || (c >= 0x20 && c <= 0xD7FF) || (c >= 0xE000 && c <= 0xFFFD) || (c >= 0x10000 && c <= 0x10FFFF); } static validXml11Chars(text) { let result = ''; for (let i = 0; i < text.length;) { const codePoint = text.codePointAt(i); if (XMLUtils.isValidXml11Char(codePoint)) { result += String.fromCodePoint(codePoint); } i += codePoint > 0xFFFF ? 2 : 1; } return result; } static isValidXmlChar(version, codePoint) { return version === '1.1' ? XMLUtils.isValidXml11Char(codePoint) : XMLUtils.isValidXml10Char(codePoint); } static ensureValidXmlCodePoint(version, codePoint, context) { if (!XMLUtils.isValidXmlChar(version, codePoint)) { const hex = codePoint.toString(16).toUpperCase().padStart(4, '0'); throw new Error('Malformed XML document: forbidden character U+' + hex + ' in ' + context); } } static ensureValidXmlCharacters(version, text, context) { for (let i = 0; i < text.length;) { const codePoint = text.codePointAt(i); XMLUtils.ensureValidXmlCodePoint(version, codePoint, context); i += codePoint > 0xFFFF ? 2 : 1; } } static isValidXml11Char(c) { // From XML 1.1 spec valid chars: // [#x1-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] // any Unicode character, excluding the surrogate blocks, FFFE, and FFFF. return (c >= 0x1 && c <= 0xD7FF) || (c >= 0xE000 && c <= 0xFFFD) || (c >= 0x10000 && c <= 0x10FFFF); } static lookingAt(search, text, start) { let length = search.length; if (length + start > text.length) { return false; } for (let i = 0; i < length; i++) { if (text[start + i] !== search[i]) { return false; } } return true; } static isValidXMLName(name) { if (name.length === 0) { return false; } // XML 1.0 spec: Names must start with a letter, underscore, or colon const firstChar = name.charAt(0); if (!XMLUtils.isNameStartChar(firstChar)) { return false; } // Check remaining characters for (let i = 1; i < name.length; i++) { const char = name.charAt(i); if (!XMLUtils.isNameChar(char)) { return false; } } return true; } static isNameStartChar(char) { // XML 1.0 spec: NameStartChar const code = char.codePointAt(0); if (code === undefined) { return false; } return (char === ':' || char === '_' || (code >= 0x41 && code <= 0x5A) || // [A-Z] (code >= 0x61 && code <= 0x7A) || // [a-z] (code >= 0xC0 && code <= 0xD6) || // [#xC0-#xD6] (code >= 0xD8 && code <= 0xF6) || // [#xD8-#xF6] (excludes #xD7) (code >= 0xF8 && code <= 0x2FF) || // [#xF8-#x2FF] (code >= 0x370 && code <= 0x37D) || // [#x370-#x37D] (code >= 0x37F && code <= 0x1FFF) || // [#x37F-#x1FFF] (code >= 0x200C && code <= 0x200D) || // [#x200C-#x200D] (code >= 0x2070 && code <= 0x218F) || // [#x2070-#x218F] (code >= 0x2C00 && code <= 0x2FEF) || // [#x2C00-#x2FEF] (code >= 0x3001 && code <= 0xD7FF) || // [#x3001-#xD7FF] (code >= 0xF900 && code <= 0xFDCF) || // [#xF900-#xFDCF] (code >= 0xFDF0 && code <= 0xFFFD) || // [#xFDF0-#xFFFD] (code >= 0x10000 && code <= 0xEFFFF) // [#x10000-#xEFFFF] ); } static isNameChar(char) { // XML 1.0 spec: NameChar includes NameStartChar plus additional characters const code = char.codePointAt(0); if (code === undefined) { return false; } // First check if it's a valid NameStartChar if (XMLUtils.isNameStartChar(char)) { return true; } // Additional characters allowed in names (but not at the start) return (char === '-' || char === '.' || (code >= 0x30 && code <= 0x39) || // [0-9] code === 0xB7 || // #xB7 (code >= 0x0300 && code <= 0x036F) || // [#x0300-#x036F] (code >= 0x203F && code <= 0x2040) // [#x203F-#x2040] ); } static isValidNCName(name) { if (name.length === 0) { return false; } // NCName cannot contain colons (Non-Colonized Name) if (name.includes(':')) { return false; } // NCName must start with a letter or underscore (no colon allowed) const firstChar = name.charAt(0); if (!XMLUtils.isNCNameStartChar(firstChar)) { return false; } // Check remaining characters for (let i = 1; i < name.length; i++) { const char = name.charAt(i); if (!XMLUtils.isNameChar(char)) { return false; } } return true; } static isNCNameStartChar(char) { // Same as NameStartChar but without colon const code = char.codePointAt(0); if (code === undefined) { return false; } return (char === '_' || (code >= 0x41 && code <= 0x5A) || // [A-Z] (code >= 0x61 && code <= 0x7A) || // [a-z] (code >= 0xC0 && code <= 0xD6) || // [#xC0-#xD6] (code >= 0xD8 && code <= 0xF6) || // [#xD8-#xF6] (excludes #xD7) (code >= 0xF8 && code <= 0x2FF) || // [#xF8-#x2FF] (code >= 0x370 && code <= 0x37D) || // [#x370-#x37D] (code >= 0x37F && code <= 0x1FFF) || // [#x37F-#x1FFF] (code >= 0x200C && code <= 0x200D) || // [#x200C-#x200D] (code >= 0x2070 && code <= 0x218F) || // [#x2070-#x218F] (code >= 0x2C00 && code <= 0x2FEF) || // [#x2C00-#x2FEF] (code >= 0x3001 && code <= 0xD7FF) || // [#x3001-#xD7FF] (code >= 0xF900 && code <= 0xFDCF) || // [#xF900-#xFDCF] (code >= 0xFDF0 && code <= 0xFFFD) || // [#xFDF0-#xFFFD] (code >= 0x10000 && code <= 0xEFFFF) // [#x10000-#xEFFFF] ); } static isValidNMTOKEN(token) { if (token.length === 0) { return false; } // NMTOKEN can contain name characters but doesn't need to start with letter for (let i = 0; i < token.length; i++) { const char = token.charAt(i); if (!XMLUtils.isNameChar(char)) { return false; } } return true; } } exports.XMLUtils = XMLUtils; //# sourceMappingURL=XMLUtils.js.map