basant307/AI_Governance_Project
048
1"use strict";2Object.defineProperty(exports, "__esModule", { value: true });3exports.SaxesParser = exports.EVENTS = void 0;4const ed5 = require("xmlchars/xml/1.0/ed5");5const ed2 = require("xmlchars/xml/1.1/ed2");6const NSed3 = require("xmlchars/xmlns/1.0/ed3");7var isS = ed5.isS;8var isChar10 = ed5.isChar;9var isNameStartChar = ed5.isNameStartChar;10var isNameChar = ed5.isNameChar;11var S_LIST = ed5.S_LIST;12var NAME_RE = ed5.NAME_RE;13var isChar11 = ed2.isChar;14var isNCNameStartChar = NSed3.isNCNameStartChar;15var isNCNameChar = NSed3.isNCNameChar;16var NC_NAME_RE = NSed3.NC_NAME_RE;17const XML_NAMESPACE = "http://www.w3.org/XML/1998/namespace";18const XMLNS_NAMESPACE = "http://www.w3.org/2000/xmlns/";19const rootNS = {20 // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment21 __proto__: null,22 xml: XML_NAMESPACE,23 xmlns: XMLNS_NAMESPACE,24};25const XML_ENTITIES = {26 // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment27 __proto__: null,28 amp: "&",29 gt: ">",30 lt: "<",31 quot: "\"",32 apos: "'",33};34// EOC: end-of-chunk35const EOC = -1;36const NL_LIKE = -2;37const S_BEGIN = 0; // Initial state.38const S_BEGIN_WHITESPACE = 1; // leading whitespace39const S_DOCTYPE = 2; // <!DOCTYPE40const S_DOCTYPE_QUOTE = 3; // <!DOCTYPE "//blah41const S_DTD = 4; // <!DOCTYPE "//blah" [ ...42const S_DTD_QUOTED = 5; // <!DOCTYPE "//blah" [ "foo43const S_DTD_OPEN_WAKA = 6;44const S_DTD_OPEN_WAKA_BANG = 7;45const S_DTD_COMMENT = 8; // <!--46const S_DTD_COMMENT_ENDING = 9; // <!-- blah -47const S_DTD_COMMENT_ENDED = 10; // <!-- blah --48const S_DTD_PI = 11; // <?49const S_DTD_PI_ENDING = 12; // <?hi "there" ?50const S_TEXT = 13; // general stuff51const S_ENTITY = 14; // & and such52const S_OPEN_WAKA = 15; // <53const S_OPEN_WAKA_BANG = 16; // <!...54const S_COMMENT = 17; // <!--55const S_COMMENT_ENDING = 18; // <!-- blah -56const S_COMMENT_ENDED = 19; // <!-- blah --57const S_CDATA = 20; // <![CDATA[ something58const S_CDATA_ENDING = 21; // ]59const S_CDATA_ENDING_2 = 22; // ]]60const S_PI_FIRST_CHAR = 23; // <?hi, first char61const S_PI_REST = 24; // <?hi, rest of the name62const S_PI_BODY = 25; // <?hi there63const S_PI_ENDING = 26; // <?hi "there" ?64const S_XML_DECL_NAME_START = 27; // <?xml65const S_XML_DECL_NAME = 28; // <?xml foo66const S_XML_DECL_EQ = 29; // <?xml foo=67const S_XML_DECL_VALUE_START = 30; // <?xml foo=68const S_XML_DECL_VALUE = 31; // <?xml foo="bar"69const S_XML_DECL_SEPARATOR = 32; // <?xml foo="bar"70const S_XML_DECL_ENDING = 33; // <?xml ... ?71const S_OPEN_TAG = 34; // <strong72const S_OPEN_TAG_SLASH = 35; // <strong /73const S_ATTRIB = 36; // <a74const S_ATTRIB_NAME = 37; // <a foo75const S_ATTRIB_NAME_SAW_WHITE = 38; // <a foo _76const S_ATTRIB_VALUE = 39; // <a foo=77const S_ATTRIB_VALUE_QUOTED = 40; // <a foo="bar78const S_ATTRIB_VALUE_CLOSED = 41; // <a foo="bar"79const S_ATTRIB_VALUE_UNQUOTED = 42; // <a foo=bar80const S_CLOSE_TAG = 43; // </a81const S_CLOSE_TAG_SAW_WHITE = 44; // </a >82const TAB = 9;83const NL = 0xA;84const CR = 0xD;85const SPACE = 0x20;86const BANG = 0x21;87const DQUOTE = 0x22;88const AMP = 0x26;89const SQUOTE = 0x27;90const MINUS = 0x2D;91const FORWARD_SLASH = 0x2F;92const SEMICOLON = 0x3B;93const LESS = 0x3C;94const EQUAL = 0x3D;95const GREATER = 0x3E;96const QUESTION = 0x3F;97const OPEN_BRACKET = 0x5B;98const CLOSE_BRACKET = 0x5D;99const NEL = 0x85;100const LS = 0x2028; // Line Separator101const isQuote = (c) => c === DQUOTE || c === SQUOTE;102const QUOTES = [DQUOTE, SQUOTE];103const DOCTYPE_TERMINATOR = [...QUOTES, OPEN_BRACKET, GREATER];104const DTD_TERMINATOR = [...QUOTES, LESS, CLOSE_BRACKET];105const XML_DECL_NAME_TERMINATOR = [EQUAL, QUESTION, ...S_LIST];106const ATTRIB_VALUE_UNQUOTED_TERMINATOR = [...S_LIST, GREATER, AMP, LESS];107function nsPairCheck(parser, prefix, uri) {108 switch (prefix) {109 case "xml":110 if (uri !== XML_NAMESPACE) {111 parser.fail(`xml prefix must be bound to ${XML_NAMESPACE}.`);112 }113 break;114 case "xmlns":115 if (uri !== XMLNS_NAMESPACE) {116 parser.fail(`xmlns prefix must be bound to ${XMLNS_NAMESPACE}.`);117 }118 break;119 default:120 }121 switch (uri) {122 case XMLNS_NAMESPACE:123 parser.fail(prefix === "" ?124 `the default namespace may not be set to ${uri}.` :125 `may not assign a prefix (even "xmlns") to the URI \126${XMLNS_NAMESPACE}.`);127 break;128 case XML_NAMESPACE:129 switch (prefix) {130 case "xml":131 // Assinging the XML namespace to "xml" is fine.132 break;133 case "":134 parser.fail(`the default namespace may not be set to ${uri}.`);135 break;136 default:137 parser.fail("may not assign the xml namespace to another prefix.");138 }139 break;140 default:141 }142}143function nsMappingCheck(parser, mapping) {144 for (const local of Object.keys(mapping)) {145 nsPairCheck(parser, local, mapping[local]);146 }147}148const isNCName = (name) => NC_NAME_RE.test(name);149const isName = (name) => NAME_RE.test(name);150const FORBIDDEN_START = 0;151const FORBIDDEN_BRACKET = 1;152const FORBIDDEN_BRACKET_BRACKET = 2;153/**154 * The list of supported events.155 */156exports.EVENTS = [157 "xmldecl",158 "text",159 "processinginstruction",160 "doctype",161 "comment",162 "opentagstart",163 "attribute",164 "opentag",165 "closetag",166 "cdata",167 "error",168 "end",169 "ready",170];171const EVENT_NAME_TO_HANDLER_NAME = {172 xmldecl: "xmldeclHandler",173 text: "textHandler",174 processinginstruction: "piHandler",175 doctype: "doctypeHandler",176 comment: "commentHandler",177 opentagstart: "openTagStartHandler",178 attribute: "attributeHandler",179 opentag: "openTagHandler",180 closetag: "closeTagHandler",181 cdata: "cdataHandler",182 error: "errorHandler",183 end: "endHandler",184 ready: "readyHandler",185};186// eslint-disable-next-line @typescript-eslint/ban-types187class SaxesParser {188 /**189 * @param opt The parser options.190 */191 constructor(opt) {192 this.opt = opt !== null && opt !== void 0 ? opt : {};193 this.fragmentOpt = !!this.opt.fragment;194 const xmlnsOpt = this.xmlnsOpt = !!this.opt.xmlns;195 this.trackPosition = this.opt.position !== false;196 this.fileName = this.opt.fileName;197 if (xmlnsOpt) {198 // This is the function we use to perform name checks on PIs and entities.199 // When namespaces are used, colons are not allowed in PI target names or200 // entity names. So the check depends on whether namespaces are used. See:201 //202 // https://www.w3.org/XML/xml-names-19990114-errata.html203 // NE08204 //205 this.nameStartCheck = isNCNameStartChar;206 this.nameCheck = isNCNameChar;207 this.isName = isNCName;208 // eslint-disable-next-line @typescript-eslint/unbound-method209 this.processAttribs = this.processAttribsNS;210 // eslint-disable-next-line @typescript-eslint/unbound-method211 this.pushAttrib = this.pushAttribNS;212 // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment213 this.ns = Object.assign({ __proto__: null }, rootNS);214 const additional = this.opt.additionalNamespaces;215 if (additional != null) {216 nsMappingCheck(this, additional);217 Object.assign(this.ns, additional);218 }219 }220 else {221 this.nameStartCheck = isNameStartChar;222 this.nameCheck = isNameChar;223 this.isName = isName;224 // eslint-disable-next-line @typescript-eslint/unbound-method225 this.processAttribs = this.processAttribsPlain;226 // eslint-disable-next-line @typescript-eslint/unbound-method227 this.pushAttrib = this.pushAttribPlain;228 }229 //230 // The order of the members in this table needs to correspond to the state231 // numbers given to the states that correspond to the methods being recorded232 // here.233 //234 this.stateTable = [235 /* eslint-disable @typescript-eslint/unbound-method */236 this.sBegin,237 this.sBeginWhitespace,238 this.sDoctype,239 this.sDoctypeQuote,240 this.sDTD,241 this.sDTDQuoted,242 this.sDTDOpenWaka,243 this.sDTDOpenWakaBang,244 this.sDTDComment,245 this.sDTDCommentEnding,246 this.sDTDCommentEnded,247 this.sDTDPI,248 this.sDTDPIEnding,249 this.sText,250 this.sEntity,251 this.sOpenWaka,252 this.sOpenWakaBang,253 this.sComment,254 this.sCommentEnding,255 this.sCommentEnded,256 this.sCData,257 this.sCDataEnding,258 this.sCDataEnding2,259 this.sPIFirstChar,260 this.sPIRest,261 this.sPIBody,262 this.sPIEnding,263 this.sXMLDeclNameStart,264 this.sXMLDeclName,265 this.sXMLDeclEq,266 this.sXMLDeclValueStart,267 this.sXMLDeclValue,268 this.sXMLDeclSeparator,269 this.sXMLDeclEnding,270 this.sOpenTag,271 this.sOpenTagSlash,272 this.sAttrib,273 this.sAttribName,274 this.sAttribNameSawWhite,275 this.sAttribValue,276 this.sAttribValueQuoted,277 this.sAttribValueClosed,278 this.sAttribValueUnquoted,279 this.sCloseTag,280 this.sCloseTagSawWhite,281 /* eslint-enable @typescript-eslint/unbound-method */282 ];283 this._init();284 }285 /**286 * Indicates whether or not the parser is closed. If ``true``, wait for287 * the ``ready`` event to write again.288 */289 get closed() {290 return this._closed;291 }292 _init() {293 var _a;294 this.openWakaBang = "";295 this.text = "";296 this.name = "";297 this.piTarget = "";298 this.entity = "";299 this.q = null;300 this.tags = [];301 this.tag = null;302 this.topNS = null;303 this.chunk = "";304 this.chunkPosition = 0;305 this.i = 0;306 this.prevI = 0;307 this.carriedFromPrevious = undefined;308 this.forbiddenState = FORBIDDEN_START;309 this.attribList = [];310 // The logic is organized so as to minimize the need to check311 // this.opt.fragment while parsing.312 const { fragmentOpt } = this;313 this.state = fragmentOpt ? S_TEXT : S_BEGIN;314 // We want these to be all true if we are dealing with a fragment.315 this.reportedTextBeforeRoot = this.reportedTextAfterRoot = this.closedRoot =316 this.sawRoot = fragmentOpt;317 // An XML declaration is intially possible only when parsing whole318 // documents.319 this.xmlDeclPossible = !fragmentOpt;320 this.xmlDeclExpects = ["version"];321 this.entityReturnState = undefined;322 let { defaultXMLVersion } = this.opt;323 if (defaultXMLVersion === undefined) {324 if (this.opt.forceXMLVersion === true) {325 throw new Error("forceXMLVersion set but defaultXMLVersion is not set");326 }327 defaultXMLVersion = "1.0";328 }329 this.setXMLVersion(defaultXMLVersion);330 this.positionAtNewLine = 0;331 this.doctype = false;332 this._closed = false;333 this.xmlDecl = {334 version: undefined,335 encoding: undefined,336 standalone: undefined,337 };338 this.line = 1;339 this.column = 0;340 this.ENTITIES = Object.create(XML_ENTITIES);341 (_a = this.readyHandler) === null || _a === void 0 ? void 0 : _a.call(this);342 }343 /**344 * The stream position the parser is currently looking at. This field is345 * zero-based.346 *347 * This field is not based on counting Unicode characters but is to be348 * interpreted as a plain index into a JavaScript string.349 */350 get position() {351 return this.chunkPosition + this.i;352 }353 /**354 * The column number of the next character to be read by the parser. *355 * This field is zero-based. (The first column in a line is 0.)356 *357 * This field reports the index at which the next character would be in the358 * line if the line were represented as a JavaScript string. Note that this359 * *can* be different to a count based on the number of *Unicode characters*360 * due to how JavaScript handles astral plane characters.361 *362 * See [[column]] for a number that corresponds to a count of Unicode363 * characters.364 */365 get columnIndex() {366 return this.position - this.positionAtNewLine;367 }368 /**369 * Set an event listener on an event. The parser supports one handler per370 * event type. If you try to set an event handler over an existing handler,371 * the old handler is silently overwritten.372 *373 * @param name The event to listen to.374 *375 * @param handler The handler to set.376 */377 on(name, handler) {378 // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access379 this[EVENT_NAME_TO_HANDLER_NAME[name]] = handler;380 }381 /**382 * Unset an event handler.383 *384 * @parma name The event to stop listening to.385 */386 off(name) {387 // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access388 this[EVENT_NAME_TO_HANDLER_NAME[name]] = undefined;389 }390 /**391 * Make an error object. The error object will have a message that contains392 * the ``fileName`` option passed at the creation of the parser. If position393 * tracking was turned on, it will also have line and column number394 * information.395 *396 * @param message The message describing the error to report.397 *398 * @returns An error object with a properly formatted message.399 */400 makeError(message) {401 var _a;402 let msg = (_a = this.fileName) !== null && _a !== void 0 ? _a : "";403 if (this.trackPosition) {404 if (msg.length > 0) {405 msg += ":";406 }407 msg += `${this.line}:${this.column}`;408 }409 if (msg.length > 0) {410 msg += ": ";411 }412 return new Error(msg + message);413 }414 /**415 * Report a parsing error. This method is made public so that client code may416 * check for issues that are outside the scope of this project and can report417 * errors.418 *419 * @param message The error to report.420 *421 * @returns this422 */423 fail(message) {424 const err = this.makeError(message);425 const handler = this.errorHandler;426 if (handler === undefined) {427 throw err;428 }429 else {430 handler(err);431 }432 return this;433 }434 /**435 * Write a XML data to the parser.436 *437 * @param chunk The XML data to write.438 *439 * @returns this440 */441 // We do need object for the type here. Yes, it often causes problems442 // but not in this case.443 write(chunk) {444 if (this.closed) {445 return this.fail("cannot write after close; assign an onready handler.");446 }447 let end = false;448 if (chunk === null) {449 // We cannot return immediately because carriedFromPrevious may need450 // processing.451 end = true;452 chunk = "";453 }454 else if (typeof chunk === "object") {455 chunk = chunk.toString();456 }457 // We checked if performing a pre-decomposition of the string into an array458 // of single complete characters (``Array.from(chunk)``) would be faster459 // than the current repeated calls to ``charCodeAt``. As of August 2018, it460 // isn't. (There may be Node-specific code that would perform faster than461 // ``Array.from`` but don't want to be dependent on Node.)462 if (this.carriedFromPrevious !== undefined) {463 // The previous chunk had char we must carry over.464 chunk = `${this.carriedFromPrevious}${chunk}`;465 this.carriedFromPrevious = undefined;466 }467 let limit = chunk.length;468 const lastCode = chunk.charCodeAt(limit - 1);469 if (!end &&470 // A trailing CR or surrogate must be carried over to the next471 // chunk.472 (lastCode === CR || (lastCode >= 0xD800 && lastCode <= 0xDBFF))) {473 // The chunk ends with a character that must be carried over. We cannot474 // know how to handle it until we get the next chunk or the end of the475 // stream. So save it for later.476 this.carriedFromPrevious = chunk[limit - 1];477 limit--;478 chunk = chunk.slice(0, limit);479 }480 const { stateTable } = this;481 this.chunk = chunk;482 this.i = 0;483 while (this.i < limit) {484 // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument485 stateTable[this.state].call(this);486 }487 this.chunkPosition += limit;488 return end ? this.end() : this;489 }490 /**491 * Close the current stream. Perform final well-formedness checks and reset492 * the parser tstate.493 *494 * @returns this495 */496 close() {497 return this.write(null);498 }499 /**500 * Get a single code point out of the current chunk. This updates the current501 * position if we do position tracking.502 *503 * This is the algorithm to use for XML 1.0.504 *505 * @returns The character read.506 */507 getCode10() {508 const { chunk, i } = this;509 this.prevI = i;510 // Yes, we do this instead of doing this.i++. Doing it this way, we do not511 // read this.i again, which is a bit faster.512 this.i = i + 1;513 if (i >= chunk.length) {514 return EOC;515 }516 // Using charCodeAt and handling the surrogates ourselves is faster517 // than using codePointAt.518 const code = chunk.charCodeAt(i);519 this.column++;520 if (code < 0xD800) {521 if (code >= SPACE || code === TAB) {522 return code;523 }524 switch (code) {525 case NL:526 this.line++;527 this.column = 0;528 this.positionAtNewLine = this.position;529 return NL;530 case CR:531 // We may get NaN if we read past the end of the chunk, which is fine.532 if (chunk.charCodeAt(i + 1) === NL) {533 // A \r\n sequence is converted to \n so we have to skip over the534 // next character. We already know it has a size of 1 so ++ is fine535 // here.536 this.i = i + 2;537 }538 // Otherwise, a \r is just converted to \n, so we don't have to skip539 // ahead.540 // In either case, \r becomes \n.541 this.line++;542 this.column = 0;543 this.positionAtNewLine = this.position;544 return NL_LIKE;545 default:546 // If we get here, then code < SPACE and it is not NL CR or TAB.547 this.fail("disallowed character.");548 return code;549 }550 }551 if (code > 0xDBFF) {552 // This is a specialized version of isChar10 that takes into account553 // that in this context code > 0xDBFF and code <= 0xFFFF. So it does not554 // test cases that don't need testing.555 if (!(code >= 0xE000 && code <= 0xFFFD)) {556 this.fail("disallowed character.");557 }558 return code;559 }560 const final = 0x10000 + ((code - 0xD800) * 0x400) +561 (chunk.charCodeAt(i + 1) - 0xDC00);562 this.i = i + 2;563 // This is a specialized version of isChar10 that takes into account that in564 // this context necessarily final >= 0x10000.565 if (final > 0x10FFFF) {566 this.fail("disallowed character.");567 }568 return final;569 }570 /**571 * Get a single code point out of the current chunk. This updates the current572 * position if we do position tracking.573 *574 * This is the algorithm to use for XML 1.1.575 *576 * @returns {number} The character read.577 */578 getCode11() {579 const { chunk, i } = this;580 this.prevI = i;581 // Yes, we do this instead of doing this.i++. Doing it this way, we do not582 // read this.i again, which is a bit faster.583 this.i = i + 1;584 if (i >= chunk.length) {585 return EOC;586 }587 // Using charCodeAt and handling the surrogates ourselves is faster588 // than using codePointAt.589 const code = chunk.charCodeAt(i);590 this.column++;591 if (code < 0xD800) {592 if ((code > 0x1F && code < 0x7F) || (code > 0x9F && code !== LS) ||593 code === TAB) {594 return code;595 }596 switch (code) {597 case NL: // 0xA598 this.line++;599 this.column = 0;600 this.positionAtNewLine = this.position;601 return NL;602 case CR: { // 0xD603 // We may get NaN if we read past the end of the chunk, which is604 // fine.605 const next = chunk.charCodeAt(i + 1);606 if (next === NL || next === NEL) {607 // A CR NL or CR NEL sequence is converted to NL so we have to skip608 // over the next character. We already know it has a size of 1.609 this.i = i + 2;610 }611 // Otherwise, a CR is just converted to NL, no skip.612 }613 /* yes, fall through */614 case NEL: // 0x85615 case LS: // Ox2028616 this.line++;617 this.column = 0;618 this.positionAtNewLine = this.position;619 return NL_LIKE;620 default:621 this.fail("disallowed character.");622 return code;623 }624 }625 if (code > 0xDBFF) {626 // This is a specialized version of isCharAndNotRestricted that takes into627 // account that in this context code > 0xDBFF and code <= 0xFFFF. So it628 // does not test cases that don't need testing.629 if (!(code >= 0xE000 && code <= 0xFFFD)) {630 this.fail("disallowed character.");631 }632 return code;633 }634 const final = 0x10000 + ((code - 0xD800) * 0x400) +635 (chunk.charCodeAt(i + 1) - 0xDC00);636 this.i = i + 2;637 // This is a specialized version of isCharAndNotRestricted that takes into638 // account that in this context necessarily final >= 0x10000.639 if (final > 0x10FFFF) {640 this.fail("disallowed character.");641 }642 return final;643 }644 /**645 * Like ``getCode`` but with the return value normalized so that ``NL`` is646 * returned for ``NL_LIKE``.647 */648 getCodeNorm() {649 const c = this.getCode();650 return c === NL_LIKE ? NL : c;651 }652 unget() {653 this.i = this.prevI;654 this.column--;655 }656 /**657 * Capture characters into a buffer until encountering one of a set of658 * characters.659 *660 * @param chars An array of codepoints. Encountering a character in the array661 * ends the capture. (``chars`` may safely contain ``NL``.)662 *663 * @return The character code that made the capture end, or ``EOC`` if we hit664 * the end of the chunk. The return value cannot be NL_LIKE: NL is returned665 * instead.666 */667 captureTo(chars) {668 let { i: start } = this;669 const { chunk } = this;670 // eslint-disable-next-line no-constant-condition671 while (true) {672 const c = this.getCode();673 const isNLLike = c === NL_LIKE;674 const final = isNLLike ? NL : c;675 if (final === EOC || chars.includes(final)) {676 this.text += chunk.slice(start, this.prevI);677 return final;678 }679 if (isNLLike) {680 this.text += `${chunk.slice(start, this.prevI)}\n`;681 start = this.i;682 }683 }684 }685 /**686 * Capture characters into a buffer until encountering a character.687 *688 * @param char The codepoint that ends the capture. **NOTE ``char`` MAY NOT689 * CONTAIN ``NL``.** Passing ``NL`` will result in buggy behavior.690 *691 * @return ``true`` if we ran into the character. Otherwise, we ran into the692 * end of the current chunk.693 */694 captureToChar(char) {695 let { i: start } = this;696 const { chunk } = this;697 // eslint-disable-next-line no-constant-condition698 while (true) {699 let c = this.getCode();700 switch (c) {701 case NL_LIKE:702 this.text += `${chunk.slice(start, this.prevI)}\n`;703 start = this.i;704 c = NL;705 break;706 case EOC:707 this.text += chunk.slice(start);708 return false;709 default:710 }711 if (c === char) {712 this.text += chunk.slice(start, this.prevI);713 return true;714 }715 }716 }717 /**718 * Capture characters that satisfy ``isNameChar`` into the ``name`` field of719 * this parser.720 *721 * @return The character code that made the test fail, or ``EOC`` if we hit722 * the end of the chunk. The return value cannot be NL_LIKE: NL is returned723 * instead.724 */725 captureNameChars() {726 const { chunk, i: start } = this;727 // eslint-disable-next-line no-constant-condition728 while (true) {729 const c = this.getCode();730 if (c === EOC) {731 this.name += chunk.slice(start);732 return EOC;733 }734 // NL is not a name char so we don't have to test specifically for it.735 if (!isNameChar(c)) {736 this.name += chunk.slice(start, this.prevI);737 return c === NL_LIKE ? NL : c;738 }739 }740 }741 /**742 * Skip white spaces.743 *744 * @return The character that ended the skip, or ``EOC`` if we hit745 * the end of the chunk. The return value cannot be NL_LIKE: NL is returned746 * instead.747 */748 skipSpaces() {749 // eslint-disable-next-line no-constant-condition750 while (true) {751 const c = this.getCodeNorm();752 if (c === EOC || !isS(c)) {753 return c;754 }755 }756 }757 setXMLVersion(version) {758 this.currentXMLVersion = version;759 /* eslint-disable @typescript-eslint/unbound-method */760 if (version === "1.0") {761 this.isChar = isChar10;762 this.getCode = this.getCode10;763 }764 else {765 this.isChar = isChar11;766 this.getCode = this.getCode11;767 }768 /* eslint-enable @typescript-eslint/unbound-method */769 }770 // STATE ENGINE METHODS771 // This needs to be a state separate from S_BEGIN_WHITESPACE because we want772 // to be sure never to come back to this state later.773 sBegin() {774 // We are essentially peeking at the first character of the chunk. Since775 // S_BEGIN can be in effect only when we start working on the first chunk,776 // the index at which we must look is necessarily 0. Note also that the777 // following test does not depend on decoding surrogates.778 // If the initial character is 0xFEFF, ignore it.779 if (this.chunk.charCodeAt(0) === 0xFEFF) {780 this.i++;781 this.column++;782 }783 this.state = S_BEGIN_WHITESPACE;784 }785 sBeginWhitespace() {786 // We need to know whether we've encountered spaces or not because as soon787 // as we run into a space, an XML declaration is no longer possible. Rather788 // than slow down skipSpaces even in places where we don't care whether it789 // skipped anything or not, we check whether prevI is equal to the value of790 // i from before we skip spaces.791 const iBefore = this.i;792 const c = this.skipSpaces();793 if (this.prevI !== iBefore) {794 this.xmlDeclPossible = false;795 }796 switch (c) {797 case LESS:798 this.state = S_OPEN_WAKA;799 // We could naively call closeText but in this state, it is not normal800 // to have text be filled with any data.801 if (this.text.length !== 0) {802 throw new Error("no-empty text at start");803 }804 break;805 case EOC:806 break;807 default:808 this.unget();809 this.state = S_TEXT;810 this.xmlDeclPossible = false;811 }812 }813 sDoctype() {814 var _a;815 const c = this.captureTo(DOCTYPE_TERMINATOR);816 switch (c) {817 case GREATER: {818 (_a = this.doctypeHandler) === null || _a === void 0 ? void 0 : _a.call(this, this.text);819 this.text = "";820 this.state = S_TEXT;821 this.doctype = true; // just remember that we saw it.822 break;823 }824 case EOC:825 break;826 default:827 this.text += String.fromCodePoint(c);828 if (c === OPEN_BRACKET) {829 this.state = S_DTD;830 }831 else if (isQuote(c)) {832 this.state = S_DOCTYPE_QUOTE;833 this.q = c;834 }835 }836 }837 sDoctypeQuote() {838 const q = this.q;839 if (this.captureToChar(q)) {840 this.text += String.fromCodePoint(q);841 this.q = null;842 this.state = S_DOCTYPE;843 }844 }845 sDTD() {846 const c = this.captureTo(DTD_TERMINATOR);847 if (c === EOC) {848 return;849 }850 this.text += String.fromCodePoint(c);851 if (c === CLOSE_BRACKET) {852 this.state = S_DOCTYPE;853 }854 else if (c === LESS) {855 this.state = S_DTD_OPEN_WAKA;856 }857 else if (isQuote(c)) {858 this.state = S_DTD_QUOTED;859 this.q = c;860 }861 }862 sDTDQuoted() {863 const q = this.q;864 if (this.captureToChar(q)) {865 this.text += String.fromCodePoint(q);866 this.state = S_DTD;867 this.q = null;868 }869 }870 sDTDOpenWaka() {871 const c = this.getCodeNorm();872 this.text += String.fromCodePoint(c);873 switch (c) {874 case BANG:875 this.state = S_DTD_OPEN_WAKA_BANG;876 this.openWakaBang = "";877 break;878 case QUESTION:879 this.state = S_DTD_PI;880 break;881 default:882 this.state = S_DTD;883 }884 }885 sDTDOpenWakaBang() {886 const char = String.fromCodePoint(this.getCodeNorm());887 const owb = this.openWakaBang += char;888 this.text += char;889 if (owb !== "-") {890 this.state = owb === "--" ? S_DTD_COMMENT : S_DTD;891 this.openWakaBang = "";892 }893 }894 sDTDComment() {895 if (this.captureToChar(MINUS)) {896 this.text += "-";897 this.state = S_DTD_COMMENT_ENDING;898 }899 }900 sDTDCommentEnding() {901 const c = this.getCodeNorm();902 this.text += String.fromCodePoint(c);903 this.state = c === MINUS ? S_DTD_COMMENT_ENDED : S_DTD_COMMENT;904 }905 sDTDCommentEnded() {906 const c = this.getCodeNorm();907 this.text += String.fromCodePoint(c);908 if (c === GREATER) {909 this.state = S_DTD;910 }911 else {912 this.fail("malformed comment.");913 // <!-- blah -- bloo --> will be recorded as914 // a comment of " blah -- bloo "915 this.state = S_DTD_COMMENT;916 }917 }918 sDTDPI() {919 if (this.captureToChar(QUESTION)) {920 this.text += "?";921 this.state = S_DTD_PI_ENDING;922 }923 }924 sDTDPIEnding() {925 const c = this.getCodeNorm();926 this.text += String.fromCodePoint(c);927 if (c === GREATER) {928 this.state = S_DTD;929 }930 }931 sText() {932 //933 // We did try a version of saxes where the S_TEXT state was split in two934 // states: one for text inside the root element, and one for text935 // outside. This was avoiding having to test this.tags.length to decide936 // what implementation to actually use.937 //938 // Peformance testing on gigabyte-size files did not show any advantage to939 // using the two states solution instead of the current one. Conversely, it940 // made the code a bit more complicated elsewhere. For instance, a comment941 // can appear before the root element so when a comment ended it was942 // necessary to determine whether to return to the S_TEXT state or to the943 // new text-outside-root state.944 //945 if (this.tags.length !== 0) {946 this.handleTextInRoot();947 }948 else {949 this.handleTextOutsideRoot();950 }951 }952 sEntity() {953 // This is essentially a specialized version of captureToChar(SEMICOLON...)954 let { i: start } = this;955 const { chunk } = this;956 // eslint-disable-next-line no-labels, no-restricted-syntax957 loop: 958 // eslint-disable-next-line no-constant-condition959 while (true) {960 switch (this.getCode()) {961 case NL_LIKE:962 this.entity += `${chunk.slice(start, this.prevI)}\n`;963 start = this.i;964 break;965 case SEMICOLON: {966 const { entityReturnState } = this;967 const entity = this.entity + chunk.slice(start, this.prevI);968 this.state = entityReturnState;969 let parsed;970 if (entity === "") {971 this.fail("empty entity name.");972 parsed = "&;";973 }974 else {975 parsed = this.parseEntity(entity);976 this.entity = "";977 }978 if (entityReturnState !== S_TEXT || this.textHandler !== undefined) {979 this.text += parsed;980 }981 // eslint-disable-next-line no-labels982 break loop;983 }984 case EOC:985 this.entity += chunk.slice(start);986 // eslint-disable-next-line no-labels987 break loop;988 default:989 }990 }991 }992 sOpenWaka() {993 // Reminder: a state handler is called with at least one character994 // available in the current chunk. So the first call to get code inside of995 // a state handler cannot return ``EOC``. That's why we don't test996 // for it.997 const c = this.getCode();998 // either a /, ?, !, or text is coming next.999 if (isNameStartChar(c)) {1000 this.state = S_OPEN_TAG;1001 this.unget();1002 this.xmlDeclPossible = false;1003 }1004 else {1005 switch (c) {1006 case FORWARD_SLASH:1007 this.state = S_CLOSE_TAG;1008 this.xmlDeclPossible = false;1009 break;1010 case BANG:1011 this.state = S_OPEN_WAKA_BANG;1012 this.openWakaBang = "";1013 this.xmlDeclPossible = false;1014 break;1015 case QUESTION:1016 this.state = S_PI_FIRST_CHAR;1017 break;1018 default:1019 this.fail("disallowed character in tag name");1020 this.state = S_TEXT;1021 this.xmlDeclPossible = false;1022 }1023 }1024 }1025 sOpenWakaBang() {1026 this.openWakaBang += String.fromCodePoint(this.getCodeNorm());1027 switch (this.openWakaBang) {1028 case "[CDATA[":1029 if (!this.sawRoot && !this.reportedTextBeforeRoot) {1030 this.fail("text data outside of root node.");1031 this.reportedTextBeforeRoot = true;1032 }1033 if (this.closedRoot && !this.reportedTextAfterRoot) {1034 this.fail("text data outside of root node.");1035 this.reportedTextAfterRoot = true;1036 }1037 this.state = S_CDATA;1038 this.openWakaBang = "";1039 break;1040 case "--":1041 this.state = S_COMMENT;1042 this.openWakaBang = "";1043 break;1044 case "DOCTYPE":1045 this.state = S_DOCTYPE;1046 if (this.doctype || this.sawRoot) {1047 this.fail("inappropriately located doctype declaration.");1048 }1049 this.openWakaBang = "";1050 break;1051 default:1052 // 7 happens to be the maximum length of the string that can possibly1053 // match one of the cases above.1054 if (this.openWakaBang.length >= 7) {1055 this.fail("incorrect syntax.");1056 }1057 }1058 }1059 sComment() {1060 if (this.captureToChar(MINUS)) {1061 this.state = S_COMMENT_ENDING;1062 }1063 }1064 sCommentEnding() {1065 var _a;1066 const c = this.getCodeNorm();1067 if (c === MINUS) {1068 this.state = S_COMMENT_ENDED;1069 (_a = this.commentHandler) === null || _a === void 0 ? void 0 : _a.call(this, this.text);1070 this.text = "";1071 }1072 else {1073 this.text += `-${String.fromCodePoint(c)}`;1074 this.state = S_COMMENT;1075 }1076 }1077 sCommentEnded() {1078 const c = this.getCodeNorm();1079 if (c !== GREATER) {1080 this.fail("malformed comment.");1081 // <!-- blah -- bloo --> will be recorded as1082 // a comment of " blah -- bloo "1083 this.text += `--${String.fromCodePoint(c)}`;1084 this.state = S_COMMENT;1085 }1086 else {1087 this.state = S_TEXT;1088 }1089 }1090 sCData() {1091 if (this.captureToChar(CLOSE_BRACKET)) {1092 this.state = S_CDATA_ENDING;1093 }1094 }1095 sCDataEnding() {1096 const c = this.getCodeNorm();1097 if (c === CLOSE_BRACKET) {1098 this.state = S_CDATA_ENDING_2;1099 }1100 else {1101 this.text += `]${String.fromCodePoint(c)}`;1102 this.state = S_CDATA;1103 }1104 }1105 sCDataEnding2() {1106 var _a;1107 const c = this.getCodeNorm();1108 switch (c) {1109 case GREATER: {1110 (_a = this.cdataHandler) === null || _a === void 0 ? void 0 : _a.call(this, this.text);1111 this.text = "";1112 this.state = S_TEXT;1113 break;1114 }1115 case CLOSE_BRACKET:1116 this.text += "]";1117 break;1118 default:1119 this.text += `]]${String.fromCodePoint(c)}`;1120 this.state = S_CDATA;1121 }1122 }1123 // We need this separate state to check the first character fo the pi target1124 // with this.nameStartCheck which allows less characters than this.nameCheck.1125 sPIFirstChar() {1126 const c = this.getCodeNorm();1127 // This is first because in the case where the file is well-formed this is1128 // the branch taken. We optimize for well-formedness.1129 if (this.nameStartCheck(c)) {1130 this.piTarget += String.fromCodePoint(c);1131 this.state = S_PI_REST;1132 }1133 else if (c === QUESTION || isS(c)) {1134 this.fail("processing instruction without a target.");1135 this.state = c === QUESTION ? S_PI_ENDING : S_PI_BODY;1136 }1137 else {1138 this.fail("disallowed character in processing instruction name.");1139 this.piTarget += String.fromCodePoint(c);1140 this.state = S_PI_REST;1141 }1142 }1143 sPIRest() {1144 // Capture characters into a piTarget while ``this.nameCheck`` run on the1145 // character read returns true.1146 const { chunk, i: start } = this;1147 // eslint-disable-next-line no-constant-condition1148 while (true) {1149 const c = this.getCodeNorm();1150 if (c === EOC) {1151 this.piTarget += chunk.slice(start);1152 return;1153 }1154 // NL cannot satisfy this.nameCheck so we don't have to test specifically1155 // for it.1156 if (!this.nameCheck(c)) {1157 this.piTarget += chunk.slice(start, this.prevI);1158 const isQuestion = c === QUESTION;1159 if (isQuestion || isS(c)) {1160 if (this.piTarget === "xml") {1161 if (!this.xmlDeclPossible) {1162 this.fail("an XML declaration must be at the start of the document.");1163 }1164 this.state = isQuestion ? S_XML_DECL_ENDING : S_XML_DECL_NAME_START;1165 }1166 else {1167 this.state = isQuestion ? S_PI_ENDING : S_PI_BODY;1168 }1169 }1170 else {1171 this.fail("disallowed character in processing instruction name.");1172 this.piTarget += String.fromCodePoint(c);1173 }1174 break;1175 }1176 }1177 }1178 sPIBody() {1179 if (this.text.length === 0) {1180 const c = this.getCodeNorm();1181 if (c === QUESTION) {1182 this.state = S_PI_ENDING;1183 }1184 else if (!isS(c)) {1185 this.text = String.fromCodePoint(c);1186 }1187 }1188 // The question mark character is not valid inside any of the XML1189 // declaration name/value pairs.1190 else if (this.captureToChar(QUESTION)) {1191 this.state = S_PI_ENDING;1192 }1193 }1194 sPIEnding() {1195 var _a;1196 const c = this.getCodeNorm();1197 if (c === GREATER) {1198 const { piTarget } = this;1199 if (piTarget.toLowerCase() === "xml") {1200 this.fail("the XML declaration must appear at the start of the document.");