diff --git a/NOTICE.md b/NOTICE.md index b7d508d..b5f6876 100644 --- a/NOTICE.md +++ b/NOTICE.md @@ -112,7 +112,7 @@ terms and conditions of the component's license. | [`@pkgr/core`](https://github.com/un-ts/pkgr) | MIT | | [`@protobuf-ts/runtime-rpc`](https://github.com/timostamm/protobuf-ts) | Apache-2.0 | | [`@protobuf-ts/runtime`](https://github.com/timostamm/protobuf-ts) | (Apache-2.0 AND BSD-3-Clause) | -| [`@sinclair/typebox`](https://github.com/sinclairzx81/typebox-legacy) | MIT | +| [`@sinclair/typebox`](https://github.com/sinclairzx81/sinclair-typebox) | MIT | | [`@sinonjs/commons`](https://github.com/sinonjs/commons) | BSD-3-Clause | | [`@sinonjs/fake-timers`](https://github.com/sinonjs/fake-timers) | BSD-3-Clause | | [`@types/babel__core`](https://github.com/DefinitelyTyped/DefinitelyTyped) | MIT | @@ -378,6 +378,7 @@ terms and conditions of the component's license. | [`wordwrap`](https://github.com/substack/node-wordwrap) | MIT | | [`wrap-ansi`](https://github.com/chalk/wrap-ansi) | MIT | | [`write-file-atomic`](https://github.com/npm/write-file-atomic) | ISC | +| [`xml-naming`](https://github.com/NaturalIntelligence/xml-naming) | MIT | | [`y18n`](https://github.com/yargs/y18n) | ISC | | [`yallist`](https://github.com/isaacs/yallist) | ISC | | [`yargs-parser`](https://github.com/yargs/yargs-parser) | ISC | diff --git a/dist/index.js b/dist/index.js index e2d681b..54e3734 100644 --- a/dist/index.js +++ b/dist/index.js @@ -41728,7 +41728,7 @@ module.exports = { version: packageJson.version } /***/ ((module) => { "use strict"; -module.exports = /*#__PURE__*/JSON.parse('{"name":"@actions/cache","version":"6.0.0","description":"Actions cache lib","keywords":["github","actions","cache"],"homepage":"https://github.com/actions/toolkit/tree/main/packages/cache","license":"MIT","type":"module","main":"lib/cache.js","types":"lib/cache.d.ts","exports":{".":{"types":"./lib/cache.d.ts","import":"./lib/cache.js"}},"directories":{"lib":"lib","test":"__tests__"},"files":["lib","!.DS_Store"],"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/actions/toolkit.git","directory":"packages/cache"},"scripts":{"audit-moderate":"npm install && npm audit --json --audit-level=moderate > audit.json","test":"echo \\"Error: run tests from root\\" && exit 1","tsc":"tsc && cp src/internal/shared/package-version.cjs lib/internal/shared/"},"bugs":{"url":"https://github.com/actions/toolkit/issues"},"dependencies":{"@actions/core":"^3.0.0","@actions/exec":"^3.0.0","@actions/glob":"^0.6.1","@actions/http-client":"^4.0.0","@actions/io":"^3.0.0","@azure/core-rest-pipeline":"^1.22.0","@azure/storage-blob":"^12.30.0","@protobuf-ts/runtime-rpc":"^2.11.1","semver":"^7.7.3"},"devDependencies":{"@protobuf-ts/plugin":"^2.9.4","@types/node":"^25.1.0","@types/semver":"^7.7.1","typescript":"^5.2.2"},"overrides":{"uri-js":"npm:uri-js-replace@^1.0.1","node-fetch":"^3.3.2"}}'); +module.exports = /*#__PURE__*/JSON.parse('{"name":"@actions/cache","version":"6.0.1","description":"Actions cache lib","keywords":["github","actions","cache"],"homepage":"https://github.com/actions/toolkit/tree/main/packages/cache","license":"MIT","type":"module","main":"lib/cache.js","types":"lib/cache.d.ts","exports":{".":{"types":"./lib/cache.d.ts","import":"./lib/cache.js"}},"directories":{"lib":"lib","test":"__tests__"},"files":["lib","!.DS_Store"],"publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/actions/toolkit.git","directory":"packages/cache"},"scripts":{"audit-moderate":"npm install && npm audit --json --audit-level=moderate > audit.json","test":"echo \\"Error: run tests from root\\" && exit 1","tsc":"tsc && cp src/internal/shared/package-version.cjs lib/internal/shared/"},"bugs":{"url":"https://github.com/actions/toolkit/issues"},"dependencies":{"@actions/core":"^3.0.1","@actions/exec":"^3.0.0","@actions/glob":"^0.6.1","@actions/http-client":"^4.0.1","@actions/io":"^3.0.2","@azure/core-rest-pipeline":"^1.23.0","@azure/storage-blob":"^12.31.0","@protobuf-ts/runtime-rpc":"^2.11.1","semver":"^7.7.4"},"devDependencies":{"@protobuf-ts/plugin":"^2.11.1","@types/node":"^25.6.0","@types/semver":"^7.7.1","typescript":"^5.9.3"},"overrides":{"uri-js":"npm:uri-js-replace@^1.0.1","node-fetch":"^3.3.2"}}'); /***/ }) @@ -52046,13 +52046,13 @@ class Sanitizer { message: value.message, }; } - if (key === "headers") { + if (key === "headers" && object_isObject(value)) { return this.sanitizeHeaders(value); } - else if (key === "url") { + else if (key === "url" && typeof value === "string") { return this.sanitizeUrl(value); } - else if (key === "query") { + else if (key === "query" && object_isObject(value)) { return this.sanitizeQuery(value); } else if (key === "body") { @@ -52623,6 +52623,68 @@ function logPolicy_logPolicy(options = {}) { }; } //# sourceMappingURL=logPolicy.js.map +;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/policies/redirectPolicy.js +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * The programmatic identifier of the redirectPolicy. + */ +const redirectPolicyName = "redirectPolicy"; +/** + * Methods that are allowed to follow redirects 301 and 302 + */ +const allowedRedirect = ["GET", "HEAD"]; +/** + * A policy to follow Location headers from the server in order + * to support server-side redirection. + * In the browser, this policy is not used. + * @param options - Options to control policy behavior. + */ +function redirectPolicy_redirectPolicy(options = {}) { + const { maxRetries = 20, allowCrossOriginRedirects = false } = options; + return { + name: redirectPolicyName, + async sendRequest(request, next) { + const response = await next(request); + return handleRedirect(next, response, maxRetries, allowCrossOriginRedirects); + }, + }; +} +async function handleRedirect(next, response, maxRetries, allowCrossOriginRedirects, currentRetries = 0) { + const { request, status, headers } = response; + const locationHeader = headers.get("location"); + if (locationHeader && + (status === 300 || + (status === 301 && allowedRedirect.includes(request.method)) || + (status === 302 && allowedRedirect.includes(request.method)) || + (status === 303 && request.method === "POST") || + status === 307) && + currentRetries < maxRetries) { + const url = new URL(locationHeader, request.url); + // Only follow redirects to the same origin by default. + if (!allowCrossOriginRedirects) { + const originalUrl = new URL(request.url); + if (url.origin !== originalUrl.origin) { + log_logger.verbose(`Skipping cross-origin redirect from ${originalUrl.origin} to ${url.origin}.`); + return response; + } + } + request.url = url.toString(); + // POST request with Status code 303 should be converted into a + // redirected GET request if the redirect url is present in the location header + if (status === 303) { + request.method = "GET"; + request.headers.delete("Content-Length"); + delete request.body; + } + request.headers.delete("Authorization"); + const res = await next(request); + return handleRedirect(next, res, maxRetries, allowCrossOriginRedirects, currentRetries + 1); + } + return response; +} +//# sourceMappingURL=redirectPolicy.js.map ;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/util/userAgentPlatform.js // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. @@ -52640,15 +52702,14 @@ function getHeaderName() { async function userAgentPlatform_setPlatformSpecificData(map) { if (process && process.versions) { const osInfo = `${os.type()} ${os.release()}; ${os.arch()}`; - const versions = process.versions; - if (versions.bun) { - map.set("Bun", `${versions.bun} (${osInfo})`); + if (process.versions.bun) { + map.set("Bun", `${process.versions.bun} (${osInfo})`); } - else if (versions.deno) { - map.set("Deno", `${versions.deno} (${osInfo})`); + else if (process.versions.deno) { + map.set("Deno", `${process.versions.deno} (${osInfo})`); } - else if (versions.node) { - map.set("Node", `${versions.node} (${osInfo})`); + else if (process.versions.node) { + map.set("Node", `${process.versions.node} (${osInfo})`); } } } @@ -52955,7 +53016,7 @@ function isSystemError(err) { ;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/constants.js // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -const constants_SDK_VERSION = "0.3.3"; +const constants_SDK_VERSION = "0.3.5"; const constants_DEFAULT_RETRY_POLICY_COUNT = 3; //# sourceMappingURL=constants.js.map ;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/policies/retryPolicy.js @@ -52965,6 +53026,7 @@ const constants_DEFAULT_RETRY_POLICY_COUNT = 3; + const retryPolicyLogger = createClientLogger("ts-http-runtime retryPolicy"); /** * The programmatic identifier of the retryPolicy. @@ -52995,11 +53057,11 @@ function retryPolicy_retryPolicy(strategies, options = { maxRetries: constants_D // RestErrors are valid targets for the retry strategies. // If none of the retry strategies can work with them, they will be thrown later in this policy. // If the received error is not a RestError, it is immediately thrown. - responseError = e; - if (!e || responseError.name !== "RestError") { + if (!restError_isRestError(e)) { throw e; } - response = responseError.response; + responseError = e; + response = e.response; } if (request.abortSignal?.aborted) { logger.error(`Retry ${retryCount}: Request aborted.`); @@ -53400,16 +53462,15 @@ function setProxyAgentOnRequest(request, cachedAgents, proxyUrl) { if (request.tlsSettings) { log_logger.warning("TLS settings are not supported in combination with custom Proxy, certificates provided to the client will be ignored."); } - const headers = request.headers.toJSON(); if (isInsecure) { if (!cachedAgents.httpProxyAgent) { - cachedAgents.httpProxyAgent = new http_proxy_agent_dist.HttpProxyAgent(proxyUrl, { headers }); + cachedAgents.httpProxyAgent = new http_proxy_agent_dist.HttpProxyAgent(proxyUrl); } request.agent = cachedAgents.httpProxyAgent; } else { if (!cachedAgents.httpsProxyAgent) { - cachedAgents.httpsProxyAgent = new dist.HttpsProxyAgent(proxyUrl, { headers }); + cachedAgents.httpsProxyAgent = new dist.HttpsProxyAgent(proxyUrl); } request.agent = cachedAgents.httpsProxyAgent; } @@ -53461,13 +53522,13 @@ function typeGuards_isBinaryBody(body) { (body instanceof Uint8Array || typeGuards_isReadableStream(body) || typeof body === "function" || - body instanceof Blob)); + (typeof Blob !== "undefined" && body instanceof Blob))); } function typeGuards_isReadableStream(x) { return isNodeReadableStream(x) || isWebReadableStream(x); } -function isBlob(x) { - return typeof x.stream === "function"; +function typeGuards_isBlob(x) { + return typeof Blob !== "undefined" && x instanceof Blob; } //# sourceMappingURL=typeGuards.js.map ;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/util/concat.js @@ -53511,7 +53572,7 @@ function toStream(source) { if (source instanceof Uint8Array) { return external_stream_namespaceObject.Readable.from(Buffer.from(source)); } - else if (isBlob(source)) { + else if (typeGuards_isBlob(source)) { return ensureNodeStream(source.stream()); } else { @@ -53561,7 +53622,7 @@ function getLength(source) { if (source instanceof Uint8Array) { return source.byteLength; } - else if (isBlob(source)) { + else if (typeGuards_isBlob(source)) { // if was created using createFile then -1 means we have an unknown size return source.size === -1 ? undefined : source.size; } @@ -54090,9 +54151,14 @@ async function sendRequest_sendRequest(method, url, pipeline, options = {}, cust * @returns returns the content-type */ function getRequestContentType(options = {}) { - return (options.contentType ?? - options.headers?.["content-type"] ?? - getContentType(options.body)); + if (options.contentType) { + return options.contentType; + } + const headerContentType = options.headers?.["content-type"]; + if (typeof headerContentType === "string") { + return headerContentType; + } + return getContentType(options.body); } /** * Function to determine the content-type of a body @@ -54107,6 +54173,9 @@ function getContentType(body) { if (ArrayBuffer.isView(body)) { return "application/octet-stream"; } + if (isBlob(body) && body.type) { + return body.type; + } if (typeof body === "string") { try { JSON.parse(body); @@ -54157,9 +54226,15 @@ function getRequestBody(body, contentType = "") { if (typeof FormData !== "undefined" && body instanceof FormData) { return { body }; } + if (isBlob(body)) { + return { body }; + } if (isReadableStream(body)) { return { body }; } + if (typeof body === "function") { + return { body: body }; + } if (ArrayBuffer.isView(body)) { return { body: body instanceof Uint8Array ? body : JSON.stringify(body) }; } @@ -54349,8 +54424,6 @@ function statusCodeToNumber(statusCode) { - - //# sourceMappingURL=index.js.map ;// CONCATENATED MODULE: ./node_modules/@azure/core-rest-pipeline/dist/esm/pipeline.js // Copyright (c) Microsoft Corporation. @@ -54547,59 +54620,6 @@ function throttlingRetryPolicy(options = {}) { }; } //# sourceMappingURL=throttlingRetryPolicy.js.map -;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/policies/redirectPolicy.js -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT License. -/** - * The programmatic identifier of the redirectPolicy. - */ -const redirectPolicyName = "redirectPolicy"; -/** - * Methods that are allowed to follow redirects 301 and 302 - */ -const allowedRedirect = ["GET", "HEAD"]; -/** - * A policy to follow Location headers from the server in order - * to support server-side redirection. - * In the browser, this policy is not used. - * @param options - Options to control policy behavior. - */ -function redirectPolicy_redirectPolicy(options = {}) { - const { maxRetries = 20 } = options; - return { - name: redirectPolicyName, - async sendRequest(request, next) { - const response = await next(request); - return handleRedirect(next, response, maxRetries); - }, - }; -} -async function handleRedirect(next, response, maxRetries, currentRetries = 0) { - const { request, status, headers } = response; - const locationHeader = headers.get("location"); - if (locationHeader && - (status === 300 || - (status === 301 && allowedRedirect.includes(request.method)) || - (status === 302 && allowedRedirect.includes(request.method)) || - (status === 303 && request.method === "POST") || - status === 307) && - currentRetries < maxRetries) { - const url = new URL(locationHeader, request.url); - request.url = url.toString(); - // POST request with Status code 303 should be converted into a - // redirected GET request if the redirect url is present in the location header - if (status === 303) { - request.method = "GET"; - request.headers.delete("Content-Length"); - delete request.body; - } - request.headers.delete("Authorization"); - const res = await next(request); - return handleRedirect(next, res, maxRetries, currentRetries + 1); - } - return response; -} -//# sourceMappingURL=redirectPolicy.js.map ;// CONCATENATED MODULE: ./node_modules/@typespec/ts-http-runtime/dist/esm/policies/tlsPolicy.js // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. @@ -54712,7 +54732,7 @@ async function util_userAgentPlatform_setPlatformSpecificData(map) { ;// CONCATENATED MODULE: ./node_modules/@azure/core-rest-pipeline/dist/esm/constants.js // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -const esm_constants_SDK_VERSION = "1.22.2"; +const esm_constants_SDK_VERSION = "1.22.3"; const esm_constants_DEFAULT_RETRY_POLICY_COUNT = 3; //# sourceMappingURL=constants.js.map ;// CONCATENATED MODULE: ./node_modules/@azure/core-rest-pipeline/dist/esm/util/userAgent.js @@ -54811,7 +54831,7 @@ async function computeSha256Hash(content, encoding) { //# sourceMappingURL=internal.js.map -;// CONCATENATED MODULE: ./node_modules/@azure/core-util/node_modules/@azure/abort-controller/dist/esm/AbortError.js +;// CONCATENATED MODULE: ./node_modules/@azure/abort-controller/dist/esm/AbortError.js // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. /** @@ -54839,7 +54859,7 @@ class AbortError_AbortError extends Error { } } //# sourceMappingURL=AbortError.js.map -;// CONCATENATED MODULE: ./node_modules/@azure/core-util/node_modules/@azure/abort-controller/dist/esm/index.js +;// CONCATENATED MODULE: ./node_modules/@azure/abort-controller/dist/esm/index.js // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. @@ -59430,6 +59450,7 @@ function convertHttpClient(requestPolicyClient) { + //# sourceMappingURL=index.js.map ;// CONCATENATED MODULE: ./node_modules/path-expression-matcher/src/Expression.js /** @@ -60235,20 +60256,349 @@ class Matcher { return this._view; } } +;// CONCATENATED MODULE: ./node_modules/fast-xml-builder/src/util.js + + +function safeComment(val) { + return String(val) + .replace(/--/g, '- -') // -- is illegal anywhere in comment content + .replace(/--/g, '- -') // handle the scenario when 2 consiucative dashes appears + .replace(/-$/, '- '); // trailing - would form -- with the closing --> +} + +function safeCdata(val) { + return String(val).replace(/\]\]>/g, ']]]]>') +} + +function escapeAttribute(val) { + return String(val).replace(/"/g, '"').replace(/'/g, ''') +} +;// CONCATENATED MODULE: ./node_modules/xml-naming/src/index.js +/** + * xml-naming + * Validates XML Name productions as defined in the XML 1.0 and 1.1 specifications. + * Covers: Name, NCName, QName, NMToken, NMTokens + * + * XML 1.0 spec: https://www.w3.org/TR/xml/#NT-Name + * XML 1.1 spec: https://www.w3.org/TR/xml11/#NT-NameStartChar + * XML NS spec: https://www.w3.org/TR/xml-names/#NT-NCName + */ + +// --------------------------------------------------------------------------- +// Character class strings — XML 1.0 +// +// NameStartChar ::= ":" | [A-Z] | "_" | [a-z] +// | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] +// | [#x370-#x37D] | [#x37F-#x1FFF] <- split to exclude #x0487 +// | [#x200C-#x200D] +// | [#x2070-#x218F] | [#x2C00-#x2FEF] +// | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] +// +// NameChar ::= NameStartChar | "-" | "." | [0-9] +// | #xB7 | [#x0300-#x036F] | [#x203F-#x2040] +// +// Note: \u0487 (Combining Cyrillic Millions Sign) was added in Unicode 4.0, +// after XML 1.0 was defined against Unicode 2.0. It falls inside the range +// \u037F-\u1FFF but must be excluded. We split that range into +// \u037F-\u0486 and \u0488-\u1FFF to exclude it explicitly. +// --------------------------------------------------------------------------- + +const nameStartChar10 = + ':A-Za-z_' + + '\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF' + + '\u0370-\u037D' + + '\u037F-\u0486\u0488-\u1FFF' + // split to exclude \u0487 + '\u200C-\u200D' + + '\u2070-\u218F' + + '\u2C00-\u2FEF' + + '\u3001-\uD7FF' + + '\uF900-\uFDCF' + + '\uFDF0-\uFFFD'; + +const nameChar10 = + nameStartChar10 + + '\\-\\.\\d' + + '\u00B7' + + '\u0300-\u036F' + + '\u203F-\u2040'; + +// --------------------------------------------------------------------------- +// Character class strings — XML 1.1 +// +// Differences from XML 1.0: +// +// NameStartChar: +// 1.0 has split ranges: \u00C0-\u00D6, \u00D8-\u00F6, \u00F8-\u02FF +// 1.1 merges them into: \u00C0-\u02FF +// (\u00D7 x and \u00F7 / are division symbols, excluded in both versions) +// +// 1.0 tops out at \uFFFD (BMP only) +// 1.1 adds \u{10000}-\u{EFFFF} (supplementary planes) +// These require the /u flag on the RegExp — see buildRegexes below. +// +// NameChar: +// 1.1 adds \u0487 (Combining Cyrillic Millions Sign, added in Unicode 4.0) +// --------------------------------------------------------------------------- + +const nameStartChar11 = + ':A-Za-z_' + + '\u00C0-\u02FF' + // merged — 1.0 had three split ranges here + '\u0370-\u037D' + + '\u037F-\u0486\u0488-\u1FFF' + // split to exclude \u0487 (combining mark, never a NameStartChar) + '\u200C-\u200D' + + '\u2070-\u218F' + + '\u2C00-\u2FEF' + + '\u3001-\uD7FF' + + '\uF900-\uFDCF' + + '\uFDF0-\uFFFD' + + '\u{10000}-\u{EFFFF}'; // supplementary planes — REQUIRES /u flag on RegExp + +const nameChar11 = + nameStartChar11 + + '\\-\\.\\d' + + '\u00B7' + + '\u0300-\u036F' + + '\u0487' + // Combining Cyrillic Millions Sign — valid in 1.1, not 1.0 + '\u203F-\u2040'; + +// --------------------------------------------------------------------------- +// Regex builders +// +// XML 1.0 regexes: no flags — BMP only, standard JS regex behaviour. +// XML 1.1 regexes: /u flag — required for \u{10000}-\u{EFFFF} to match actual +// supplementary code points rather than lone surrogates (which are illegal XML). +// --------------------------------------------------------------------------- + +const buildRegexes = (startChar, char, flags = '') => { + const ncStart = startChar.replace(':', ''); + const ncChar = char.replace(':', ''); + const ncNamePat = `[${ncStart}][${ncChar}]*`; + + return { + name: new RegExp(`^[${startChar}][${char}]*$`, flags), + ncName: new RegExp(`^${ncNamePat}$`, flags), + qName: new RegExp(`^${ncNamePat}(?::${ncNamePat})?$`, flags), + nmToken: new RegExp(`^[${char}]+$`, flags), + nmTokens: new RegExp(`^[${char}]+(?:\\s+[${char}]+)*$`, flags), + }; +}; + +const regexes10 = buildRegexes(nameStartChar10, nameChar10); // no /u — BMP only +const regexes11 = buildRegexes(nameStartChar11, nameChar11, 'u'); // /u — enables \u{10000}-\u{EFFFF} + +const getRegexes = (xmlVersion = '1.0') => + xmlVersion === '1.1' ? regexes11 : regexes10; + +// --------------------------------------------------------------------------- +// Boolean validators +// --------------------------------------------------------------------------- + +/** + * Returns true if the string is a valid XML Name. + * Colons are allowed anywhere (Name production). + * Used for: DOCTYPE entity names, notation names, DTD element declarations. + */ +const src_name = (str, { xmlVersion = '1.0' } = {}) => + getRegexes(xmlVersion).name.test(str); + +/** + * Returns true if the string is a valid NCName (Non-Colonized Name). + * Colons are not permitted. + * Used for: namespace prefixes, local names, SVG id attributes. + */ +const ncName = (str, { xmlVersion = '1.0' } = {}) => + getRegexes(xmlVersion).ncName.test(str); + +/** + * Returns true if the string is a valid QName (Qualified Name). + * Allows exactly one colon as a prefix separator: prefix:localName. + * Used for: element and attribute names in namespace-aware XML/SVG. + */ +const qName = (str, { xmlVersion = '1.0' } = {}) => + getRegexes(xmlVersion).qName.test(str); + +/** + * Returns true if the string is a valid NMToken. + * Like Name but no restriction on the first character. + * Used for: DTD NMTOKEN attribute values. + */ +const nmToken = (str, { xmlVersion = '1.0' } = {}) => + getRegexes(xmlVersion).nmToken.test(str); + +/** + * Returns true if the string is a valid NMTokens value. + * A whitespace-separated list of NMToken values. + * Used for: DTD NMTOKENS attribute values. + */ +const nmTokens = (str, { xmlVersion = '1.0' } = {}) => + getRegexes(xmlVersion).nmTokens.test(str); + +// --------------------------------------------------------------------------- +// Diagnostic validator +// --------------------------------------------------------------------------- + +const PRODUCTIONS = (/* unused pure expression or super */ null && (['name', 'ncName', 'qName', 'nmToken', 'nmTokens'])); + +/** + * Validates a string against a named production and returns a detailed result. + * + * @param {string} str + * @param {'name'|'ncName'|'qName'|'nmToken'|'nmTokens'} production + * @param {{ xmlVersion?: '1.0'|'1.1' }} [opts] + * @returns {{ valid: boolean, production: string, input: string, reason?: string, position?: number }} + */ +const validate = (str, production, { xmlVersion = '1.0' } = {}) => { + if (!PRODUCTIONS.includes(production)) { + throw new TypeError( + `Unknown production "${production}". Must be one of: ${PRODUCTIONS.join(', ')}` + ); + } + + const validators = { name: src_name, ncName, qName, nmToken, nmTokens }; + const isValid = validators[production](str, { xmlVersion }); + + if (isValid) return { valid: true, production, input: str }; + + let reason = 'Does not match the production rules'; + let position; + + if (str.length === 0) { + reason = 'Input is empty'; + } else if (production === 'ncName' && str.includes(':')) { + position = str.indexOf(':'); + reason = 'Colon is not allowed in NCName'; + } else if (production === 'qName' && str.startsWith(':')) { + reason = 'QName cannot start with a colon'; + position = 0; + } else if (production === 'qName' && str.endsWith(':')) { + reason = 'QName cannot end with a colon'; + position = str.length - 1; + } else if (production === 'qName' && (str.match(/:/g) || []).length > 1) { + reason = 'QName can have at most one colon'; + position = str.lastIndexOf(':'); + } else if ( + ['name', 'ncName', 'qName'].includes(production) && + !/^[:A-Za-z_\u00C0-\uFFFD]/.test(str[0]) + ) { + reason = `First character "${str[0]}" is not a valid NameStartChar`; + position = 0; + } else { + for (let i = 0; i < str.length; i++) { + if (!/[\w\-\\.:\u00B7\u00C0-\uFFFD]/.test(str[i])) { + reason = `Character "${str[i]}" at position ${i} is not a valid NameChar`; + position = i; + break; + } + } + } + + return { valid: false, production, input: str, reason, position }; +}; + +// --------------------------------------------------------------------------- +// Batch validator +// --------------------------------------------------------------------------- + +/** + * Validates an array of strings against a named production. + * + * @param {string[]} strings + * @param {'name'|'ncName'|'qName'|'nmToken'|'nmTokens'} production + * @param {{ xmlVersion?: '1.0'|'1.1' }} [opts] + * @returns {Array<{ valid: boolean, production: string, input: string, reason?: string, position?: number }>} + */ +const validateAll = (strings, production, opts = {}) => + strings.map(str => validate(str, production, opts)); + +// --------------------------------------------------------------------------- +// Sanitizer +// --------------------------------------------------------------------------- + +/** + * Transforms an invalid string into the nearest valid XML name for the given production. + * + * @param {string} str + * @param {'name'|'ncName'|'qName'|'nmToken'|'nmTokens'} production + * @param {{ replacement?: string }} [opts] + * @returns {string} + */ +const sanitize = (str, production = 'name', { replacement = '_' } = {}) => { + if (!str) return replacement; + + let result = str; + + // Strip colons for NCName + if (production === 'ncName') { + result = result.replace(/:/g, ''); + } + + // Replace illegal characters + result = result.replace(/[^\w\-\.:\u00B7\u00C0-\uFFFD]/g, replacement); + + // Fix invalid start character for Name / NCName / QName + if (production !== 'nmToken' && production !== 'nmTokens') { + if (/^[\-\.\d]/.test(result)) { + result = replacement + result; + } + } + + return result || replacement; +}; ;// CONCATENATED MODULE: ./node_modules/fast-xml-builder/src/orderedJs2Xml.js + + const EOL = "\n"; /** - * - * @param {array} jArray - * @param {any} options - * @returns + * Detect XML version from the first element of the ordered array input. + * The first element must be a ?xml processing instruction with a version attribute. + * Returns '1.0' if not found. + * + * @param {array} jArray + * @param {object} options + */ +function detectXmlVersionFromArray(jArray, options) { + if (!Array.isArray(jArray) || jArray.length === 0) return '1.0'; + const first = jArray[0]; + const firstKey = propName(first); + if (firstKey === '?xml') { + const attrs = first[':@']; + if (attrs) { + const versionKey = options.attributeNamePrefix + 'version'; + if (attrs[versionKey]) return attrs[versionKey]; + } + } + return '1.0'; +} + +/** + * Resolve a tag or attribute name through sanitizeName if configured. + * Validation via xml-naming's qName is performed first; the sanitizeName + * callback is invoked only when the name is invalid. If sanitizeName is + * false (default), no validation occurs and the name is used as-is. + * + * @param {string} name - raw name from the JS object + * @param {boolean} isAttribute - true when resolving an attribute name + * @param {object} options + * @param {Matcher} matcher - current matcher state (readonly from callback perspective) + * @param {string} xmlVersion - '1.0' or '1.1', forwarded to xml-naming + */ +function resolveTagName(name, isAttribute, options, matcher, xmlVersion) { + if (!options.sanitizeName) return name; + if (qName(name, { xmlVersion })) return name; + return options.sanitizeName(name, { isAttribute, matcher: matcher.readOnly() }); +} + +/** + * @param {array} jArray + * @param {any} options + * @returns */ function toXml(jArray, options) { let indentation = ""; - if (options.format && options.indentBy.length > 0) { + if (options.format) { indentation = EOL; } @@ -60265,13 +60615,16 @@ function toXml(jArray, options) { } } + // Detect XML version for use in name validation + const xmlVersion = detectXmlVersionFromArray(jArray, options); + // Initialize matcher for path tracking const matcher = new Matcher(); - return arrToStr(jArray, options, indentation, matcher, stopNodeExpressions); + return arrToStr(jArray, options, indentation, matcher, stopNodeExpressions, xmlVersion); } -function arrToStr(arr, options, indentation, matcher, stopNodeExpressions) { +function arrToStr(arr, options, indentation, matcher, stopNodeExpressions, xmlVersion) { let xmlStr = ""; let isPreviousElementTag = false; @@ -60291,20 +60644,32 @@ function arrToStr(arr, options, indentation, matcher, stopNodeExpressions) { for (let i = 0; i < arr.length; i++) { const tagObj = arr[i]; - const tagName = propName(tagObj); - if (tagName === undefined) continue; + const rawTagName = propName(tagObj); + if (rawTagName === undefined) continue; + + // Special names are exempt from sanitizeName: internal conventions and PI tags + // are not user-supplied XML element names. + const isSpecialName = rawTagName === options.textNodeName + || rawTagName === options.cdataPropName + || rawTagName === options.commentPropName + || rawTagName[0] === '?'; + + // Resolve tag name (may transform it; may throw for invalid names) + const tagName = isSpecialName + ? rawTagName + : resolveTagName(rawTagName, false, options, matcher, xmlVersion); // Extract attributes from ":@" property const attrValues = extractAttributeValues(tagObj[":@"], options); - // Push tag to matcher WITH attributes + // Push resolved tag to matcher WITH attributes matcher.push(tagName, attrValues); // Check if this is a stop node using Expression matching const isStopNode = checkStopNode(matcher, stopNodeExpressions); if (tagName === options.textNodeName) { - let tagText = tagObj[tagName]; + let tagText = tagObj[rawTagName]; if (!isStopNode) { tagText = options.tagValueProcessor(tagName, tagText); tagText = replaceEntitiesValue(tagText, options); @@ -60320,27 +60685,25 @@ function arrToStr(arr, options, indentation, matcher, stopNodeExpressions) { if (isPreviousElementTag) { xmlStr += indentation; } - const val = tagObj[tagName][0][options.textNodeName]; - const safeVal = String(val).replace(/\]\]>/g, ']]]]>'); + const val = tagObj[rawTagName][0][options.textNodeName]; + const safeVal = safeCdata(val); xmlStr += ``; isPreviousElementTag = false; matcher.pop(); continue; } else if (tagName === options.commentPropName) { - const val = tagObj[tagName][0][options.textNodeName] - const safeVal = String(val) - .replace(/--/g, '- -') // -- is illegal anywhere in comment content - .replace(/-$/, '- '); // trailing - would form -- with the closing --> + const val = tagObj[rawTagName][0][options.textNodeName]; + const safeVal = safeComment(val); xmlStr += indentation + ``; isPreviousElementTag = true; matcher.pop(); continue; } else if (tagName[0] === "?") { - const attStr = attr_to_str(tagObj[":@"], options, isStopNode); + const attStr = attr_to_str(tagObj[":@"], options, isStopNode, matcher, xmlVersion); const tempInd = tagName === "?xml" ? "" : indentation; - let piTextNodeName = tagObj[tagName][0][options.textNodeName]; - piTextNodeName = piTextNodeName.length !== 0 ? " " + piTextNodeName : ""; //remove extra spacing - xmlStr += tempInd + `<${tagName}${piTextNodeName}${attStr}?>`; + // Text node content on PI/XML declaration tags is intentionally ignored. + // Only attributes are valid on these tags per the XML spec. + xmlStr += tempInd + `<${tagName}${attStr}?>`; isPreviousElementTag = true; matcher.pop(); continue; @@ -60352,16 +60715,15 @@ function arrToStr(arr, options, indentation, matcher, stopNodeExpressions) { } // Pass isStopNode to attr_to_str so attributes are also not processed for stopNodes - const attStr = attr_to_str(tagObj[":@"], options, isStopNode); + const attStr = attr_to_str(tagObj[":@"], options, isStopNode, matcher, xmlVersion); const tagStart = indentation + `<${tagName}${attStr}`; // If this is a stopNode, get raw content without processing let tagValue; if (isStopNode) { - tagValue = orderedJs2Xml_getRawContent(tagObj[tagName], options); + tagValue = orderedJs2Xml_getRawContent(tagObj[rawTagName], options); } else { - - tagValue = arrToStr(tagObj[tagName], options, newIdentation, matcher, stopNodeExpressions); + tagValue = arrToStr(tagObj[rawTagName], options, newIdentation, matcher, stopNodeExpressions, xmlVersion); } if (options.unpairedTags.indexOf(tagName) !== -1) { @@ -60405,7 +60767,7 @@ function extractAttributeValues(attrMap, options) { const cleanAttrName = attr.startsWith(options.attributeNamePrefix) ? attr.substr(options.attributeNamePrefix.length) : attr; - attrValues[cleanAttrName] = attrMap[attr]; + attrValues[cleanAttrName] = escapeAttribute(attrMap[attr]); hasAttrs = true; } @@ -60443,9 +60805,7 @@ function orderedJs2Xml_getRawContent(arr, options) { // Processing instruction - skip for stopNodes continue; } else if (tagName) { - // Nested tags within stopNode - // Recursively get raw content and reconstruct the tag - // For stopNodes, we don't process attributes either + // Nested tags within stopNode — no sanitizeName, content is raw const attStr = attr_to_str_raw(item[":@"], options); const nestedContent = orderedJs2Xml_getRawContent(item[tagName], options); @@ -60472,7 +60832,7 @@ function attr_to_str_raw(attrMap, options) { if (attrVal === true && options.suppressBooleanAttributes) { attrStr += ` ${attr.substr(options.attributeNamePrefix.length)}`; } else { - attrStr += ` ${attr.substr(options.attributeNamePrefix.length)}="${attrVal}"`; + attrStr += ` ${attr.substr(options.attributeNamePrefix.length)}="${escapeAttribute(attrVal)}"`; } } } @@ -60488,13 +60848,23 @@ function propName(obj) { } } -function attr_to_str(attrMap, options, isStopNode) { +/** + * Build attribute string, resolving attribute names through sanitizeName when configured. + * Accepts matcher so the callback has path context. + */ +function attr_to_str(attrMap, options, isStopNode, matcher, xmlVersion) { let attrStr = ""; if (attrMap && !options.ignoreAttributes) { for (let attr in attrMap) { if (!Object.prototype.hasOwnProperty.call(attrMap, attr)) continue; - let attrVal; + // Strip prefix to get the clean XML attribute name, then optionally sanitize it + const cleanAttrName = attr.substr(options.attributeNamePrefix.length); + const resolvedAttrName = isStopNode + ? cleanAttrName // stopNodes are raw — skip sanitizeName for attr names too + : resolveTagName(cleanAttrName, true, options, matcher, xmlVersion); + + let attrVal; if (isStopNode) { // For stopNodes, use raw value without any processing attrVal = attrMap[attr]; @@ -60505,9 +60875,9 @@ function attr_to_str(attrMap, options, isStopNode) { } if (attrVal === true && options.suppressBooleanAttributes) { - attrStr += ` ${attr.substr(options.attributeNamePrefix.length)}`; + attrStr += ` ${resolvedAttrName}`; } else { - attrStr += ` ${attr.substr(options.attributeNamePrefix.length)}="${attrVal}"`; + attrStr += ` ${resolvedAttrName}="${escapeAttribute(attrVal)}"`; } } } @@ -60534,14 +60904,6 @@ function replaceEntitiesValue(textValue, options) { } return textValue; } - -function cdataVal(val) { - -} - -function commentVal(val) { - -} ;// CONCATENATED MODULE: ./node_modules/fast-xml-builder/src/ignoreAttributes.js function getIgnoreAttributesFn(ignoreAttributes) { if (typeof ignoreAttributes === 'function') { @@ -60568,6 +60930,8 @@ function getIgnoreAttributesFn(ignoreAttributes) { + + const defaultOptions = { attributeNamePrefix: '@_', attributesGroupName: false, @@ -60601,7 +60965,11 @@ const defaultOptions = { // transformAttributeName: false, oneListGroup: false, maxNestedTags: 100, - jPath: true // When true, callbacks receive string jPath; when false, receive Matcher instance + jPath: true, // When true, callbacks receive string jPath; when false, receive Matcher instance + sanitizeName: false // false = allow all names as-is (default, backward-compatible). + // Set to a function (name, { isAttribute, matcher }) => string to + // validate/sanitize tag and attribute names. Throw inside the function + // to reject an invalid name. }; function Builder(options) { @@ -60658,6 +61026,44 @@ function Builder(options) { } } +/** + * Detect XML version from the ?xml declaration at the root of a plain-object input. + * Checks both attributesGroupName and flat attribute forms. + * Returns '1.0' if no declaration is found. + */ +function detectXmlVersionFromObj(jObj, options) { + const decl = jObj['?xml']; + if (decl && typeof decl === 'object') { + // attributesGroupName path e.g. { '$$': { '@_version': '1.1' } } + if (options.attributesGroupName && decl[options.attributesGroupName]) { + const v = decl[options.attributesGroupName][options.attributeNamePrefix + 'version']; + if (v) return v; + } + // flat attribute path e.g. { '@_version': '1.1' } + const v = decl[options.attributeNamePrefix + 'version']; + if (v) return v; + } + return '1.0'; +} + +/** + * Resolve a tag or attribute name through sanitizeName if configured. + * Validation via xml-naming's qName is performed first; the sanitizeName + * callback is invoked only when the name is invalid. If sanitizeName is + * false (default), no validation occurs and the name is used as-is. + * + * @param {string} name - raw name from the JS object + * @param {boolean} isAttribute - true when resolving an attribute name + * @param {object} options + * @param {Matcher} matcher - current matcher state (readonly from callback perspective) + * @param {string} xmlVersion - '1.0' or '1.1', forwarded to xml-naming + */ +function fxb_resolveTagName(name, isAttribute, options, matcher, xmlVersion) { + if (!options.sanitizeName) return name; + if (qName(name, { xmlVersion })) return name; + return options.sanitizeName(name, { isAttribute, matcher: matcher.readOnly() }); +} + Builder.prototype.build = function (jObj) { if (this.options.preserveOrder) { return toXml(jObj, this.options); @@ -60669,11 +61075,12 @@ Builder.prototype.build = function (jObj) { } // Initialize matcher for path tracking const matcher = new Matcher(); - return this.j2x(jObj, 0, matcher).val; + const xmlVersion = detectXmlVersionFromObj(jObj, this.options); + return this.j2x(jObj, 0, matcher, xmlVersion).val; } }; -Builder.prototype.j2x = function (jObj, level, matcher) { +Builder.prototype.j2x = function (jObj, level, matcher, xmlVersion) { let attrStr = ''; let val = ''; if (this.options.maxNestedTags && matcher.getDepth() >= this.options.maxNestedTags) { @@ -60687,6 +61094,22 @@ Builder.prototype.j2x = function (jObj, level, matcher) { for (let key in jObj) { if (!Object.prototype.hasOwnProperty.call(jObj, key)) continue; + + // Resolve the key through sanitizeName before any use. + // Special keys (textNodeName, cdataPropName, commentPropName, attributeNamePrefix, + // attributesGroupName, "?" PI tags) are exempt — they are builder-internal conventions, + // not user-supplied XML names. + const isSpecialKey = key === this.options.textNodeName + || key === this.options.cdataPropName + || key === this.options.commentPropName + || (this.options.attributesGroupName && key === this.options.attributesGroupName) + || this.isAttribute(key) + || key[0] === '?'; + + const resolvedKey = isSpecialKey + ? key + : fxb_resolveTagName(key, false, this.options, matcher, xmlVersion); + if (typeof jObj[key] === 'undefined') { // supress undefined node only if it is not an attribute if (this.isAttribute(key)) { @@ -60696,21 +61119,22 @@ Builder.prototype.j2x = function (jObj, level, matcher) { // null attribute should be ignored by the attribute list, but should not cause the tag closing if (this.isAttribute(key)) { val += ''; - } else if (key === this.options.cdataPropName) { + } else if (resolvedKey === this.options.cdataPropName || resolvedKey === this.options.commentPropName) { val += ''; - } else if (key[0] === '?') { - val += this.indentate(level) + '<' + key + '?' + this.tagEndChar; + } else if (resolvedKey[0] === '?') { + val += this.indentate(level) + '<' + resolvedKey + '?' + this.tagEndChar; } else { - val += this.indentate(level) + '<' + key + '/' + this.tagEndChar; + val += this.indentate(level) + '<' + resolvedKey + '/' + this.tagEndChar; } - // val += this.indentate(level) + '<' + key + '/' + this.tagEndChar; } else if (jObj[key] instanceof Date) { - val += this.buildTextValNode(jObj[key], key, '', level, matcher); + val += this.buildTextValNode(jObj[key], resolvedKey, '', level, matcher); } else if (typeof jObj[key] !== 'object') { //premitive type const attr = this.isAttribute(key); if (attr && !this.ignoreAttributesFn(attr, jPath)) { - attrStr += this.buildAttrPairStr(attr, '' + jObj[key], isCurrentStopNode); + // Resolve the attribute name through sanitizeName + const resolvedAttr = fxb_resolveTagName(attr, true, this.options, matcher, xmlVersion); + attrStr += this.buildAttrPairStr(resolvedAttr, '' + jObj[key], isCurrentStopNode); } else if (!attr) { //tag value if (key === this.options.textNodeName) { @@ -60718,7 +61142,7 @@ Builder.prototype.j2x = function (jObj, level, matcher) { val += this.replaceEntitiesValue(newval); } else { // Check if this is a stopNode before building - matcher.push(key); + matcher.push(resolvedKey); const isStopNode = this.checkStopNode(matcher); matcher.pop(); @@ -60726,12 +61150,12 @@ Builder.prototype.j2x = function (jObj, level, matcher) { // Build as raw content without encoding const textValue = '' + jObj[key]; if (textValue === '') { - val += this.indentate(level) + '<' + key + this.closeTag(key) + this.tagEndChar; + val += this.indentate(level) + '<' + resolvedKey + this.closeTag(resolvedKey) + this.tagEndChar; } else { - val += this.indentate(level) + '<' + key + '>' + textValue + '' + textValue + '' + textValue + '' + textValue + '/g, ']]]]>'); + const safeVal = safeCdata(val); return this.indentate(level) + `` + this.newLine; } else if (this.options.commentPropName !== false && key === this.options.commentPropName) { - const safeVal = String(val) - .replace(/--/g, '- -') // -- is illegal anywhere in comment content - .replace(/-$/, '- '); // trailing - would form -- with the closing --> + const safeVal = safeComment(val); return this.indentate(level) + `` + this.newLine; } else if (key[0] === "?") {//PI tag return this.indentate(level) + '<' + key + attrStr + '?' + this.tagEndChar; @@ -61175,7 +61603,7 @@ const validator_defaultOptions = { }; //const tagsPattern = new RegExp("<\\/?([\\w:\\-_\.]+)\\s*\/?>","g"); -function validate(xmlData, options) { +function validator_validate(xmlData, options) { options = Object.assign({}, validator_defaultOptions, options); //xmlData = xmlData.replace(/(\r\n|\n|\r)/gm,"");//make it single line @@ -61599,7 +62027,7 @@ function getPositionFromMatch(match) { const XMLValidator = { - validate: validate + validate: validator_validate } ;// CONCATENATED MODULE: ./node_modules/fast-xml-parser/src/xmlparser/OptionsBuilder.js @@ -61812,11 +62240,15 @@ class XmlNode { class DocTypeReader { - constructor(options) { + constructor(options, xmlVersion) { this.suppressValidationErr = !options; this.options = options; + this.xmlVersion = xmlVersion || 1.0; } + setXmlVersion(xmlVersion = 1.0) { + this.xmlVersion = xmlVersion; + } readDocType(xmlData, i) { const entities = Object.create(null); let entityCount = 0; @@ -61914,7 +62346,7 @@ class DocTypeReader { } let entityName = xmlData.substring(startIndex, i); - validateEntityName(entityName); + validateEntityName(entityName, { xmlVersion: this.xmlVersion }); // Skip whitespace after entity name i = skipWhitespace(xmlData, i); @@ -61957,7 +62389,7 @@ class DocTypeReader { } let notationName = xmlData.substring(startIndex, i); - !this.suppressValidationErr && validateEntityName(notationName); + !this.suppressValidationErr && validateEntityName(notationName, { xmlVersion: this.xmlVersion }); // Skip whitespace after notation name i = skipWhitespace(xmlData, i); @@ -62037,7 +62469,7 @@ class DocTypeReader { let elementName = xmlData.substring(startIndex, i); // Validate element name - if (!this.suppressValidationErr && !isName(elementName)) { + if (!this.suppressValidationErr && !qName(elementName, { xmlVersion: this.xmlVersion })) { throw new Error(`Invalid element name: "${elementName}"`); } @@ -62084,7 +62516,7 @@ class DocTypeReader { let elementName = xmlData.substring(startIndex, i); // Validate element name - validateEntityName(elementName) + validateEntityName(elementName, { xmlVersion: this.xmlVersion }) // Skip whitespace after element name i = skipWhitespace(xmlData, i); @@ -62097,7 +62529,7 @@ class DocTypeReader { let attributeName = xmlData.substring(startIndex, i); // Validate attribute name - if (!validateEntityName(attributeName)) { + if (!validateEntityName(attributeName, { xmlVersion: this.xmlVersion })) { throw new Error(`Invalid attribute name: "${attributeName}"`); } @@ -62132,7 +62564,7 @@ class DocTypeReader { // Validate notation name notation = notation.trim(); - if (!validateEntityName(notation)) { + if (!validateEntityName(notation, { xmlVersion: this.xmlVersion })) { throw new Error(`Invalid notation name: "${notation}"`); } @@ -62210,22 +62642,22 @@ function hasSeq(data, seq, i) { return true; } -function validateEntityName(name) { - if (isName(name)) +function validateEntityName(name, xmlVersion) { + if (qName(name, { xmlVersion: xmlVersion })) return name; else throw new Error(`Invalid entity name ${name}`); } ;// CONCATENATED MODULE: ./node_modules/strnum/strnum.js const hexRegex = /^[-+]?0x[a-fA-F0-9]+$/; +const binRegex = /^0b[01]+$/; +const octRegex = /^0o[0-7]+$/; const numRegex = /^([\-\+])?(0*)([0-9]*(\.[0-9]*)?)$/; -// const octRegex = /^0x[a-z0-9]+/; -// const binRegex = /0x[a-z0-9]+/; - const consider = { hex: true, - // oct: false, + binary: false, + octal: false, leadingZeros: true, decimalPoint: "\.", eNotation: true, @@ -62244,14 +62676,14 @@ function toNumber(str, options = {}) { else if (trimmedStr === "0") return 0; else if (options.hex && hexRegex.test(trimmedStr)) { return parse_int(trimmedStr, 16); - // }else if (options.oct && octRegex.test(str)) { - // return Number.parseInt(val, 8); + } else if (options.binary && binRegex.test(trimmedStr)) { + return parse_int(trimmedStr, 2); + } else if (options.octal && octRegex.test(trimmedStr)) { + return parse_int(trimmedStr, 8); } else if (!isFinite(trimmedStr)) { //Infinity return handleInfinity(str, Number(trimmedStr), options); } else if (trimmedStr.includes('e') || trimmedStr.includes('E')) { //eNotation return resolveEnotation(str, trimmedStr, options); - // }else if (options.parseBin && binRegex.test(str)) { - // return Number.parseInt(val, 2); } else { //separate negative sign, leading zeros, and rest number const match = numRegex.exec(trimmedStr); @@ -62349,11 +62781,13 @@ function trimZeros(numStr) { } function parse_int(numStr, base) { - //polyfill + const str = numStr.trim(); + if (base === 2 || base === 8) numStr = str.substring(2); + if (parseInt) return parseInt(numStr, base); else if (Number.parseInt) return Number.parseInt(numStr, base); else if (window && window.parseInt) return window.parseInt(numStr, base); - else throw new Error("parseInt, Number.parseInt, window.parseInt are not supported") + else throw new Error("parseInt, Number.parseInt, window.parseInt are not supported"); } /** @@ -64402,7 +64836,7 @@ function extractNamespace(rawTagName) { } class OrderedObjParser { - constructor(options) { + constructor(options, externalEntities) { this.options = options; this.currentNode = null; this.tagsNodeStack = []; @@ -64425,7 +64859,7 @@ class OrderedObjParser { if (typeof this.options.htmlEntities === "object") namedEntities = this.options.htmlEntities; else if (this.options.htmlEntities === true) namedEntities = { ...COMMON_HTML, ...CURRENCY }; this.entityDecoder = new EntityDecoder({ - namedEntities: namedEntities, + namedEntities: { ...namedEntities, ...externalEntities }, numericAllowed: this.options.htmlEntities, limit: { maxTotalExpansions: this.options.processEntities.maxTotalExpansions, @@ -64438,9 +64872,6 @@ class OrderedObjParser { // Initialize path matcher for path-expression-matcher this.matcher = new Matcher(); - - // Live read-only proxy of matcher — PEM creates and caches this internally. - // All user callbacks receive this instead of the mutable matcher. this.readonlyMatcher = this.matcher.readOnly(); // Flag to track if current node is a stop node (optimization) @@ -64602,7 +65033,7 @@ function buildAttributesMap(attrStr, jPath, tagName, force = false) { if (!hasAttrs) return; - if (options.attributesGroupName) { + if (options.attributesGroupName && !options.preserveOrder) { const attrCollection = {}; attrCollection[options.attributesGroupName] = attrs; return attrCollection; @@ -64676,6 +65107,7 @@ const parseXml = function (xmlData) { if (attsMap) { const ver = attsMap[this.options.attributeNamePrefix + "version"]; this.entityDecoder.setXmlVersion(Number(ver) || 1.0); + docTypeReader.setXmlVersion(Number(ver) || 1.0); } if ((options.ignoreDeclaration && tagData.tagName === "?xml") || options.ignorePiTags) { //do nothing @@ -64988,12 +65420,16 @@ function isItStopNode() { * @returns */ function tagExpWithClosingIndex(xmlData, i, closingChar = ">") { + //TODO: ignore boolean attributes in tag expression + //TODO: if ignore attributes, dont read full attribute expression but the end. But read for xml declaration let attrBoundary = 0; - const chars = []; const len = xmlData.length; const closeCode0 = closingChar.charCodeAt(0); const closeCode1 = closingChar.length > 1 ? closingChar.charCodeAt(1) : -1; + let result = ''; + let segmentStart = i; + for (let index = i; index < len; index++) { const code = xmlData.charCodeAt(index); @@ -65004,17 +65440,18 @@ function tagExpWithClosingIndex(xmlData, i, closingChar = ">") { } else if (code === closeCode0) { if (closeCode1 !== -1) { if (xmlData.charCodeAt(index + 1) === closeCode1) { - return { data: String.fromCharCode(...chars), index }; + result += xmlData.substring(segmentStart, index); + return { data: result, index }; } } else { - return { data: String.fromCharCode(...chars), index }; + result += xmlData.substring(segmentStart, index); + return { data: result, index }; } - } else if (code === 9) { // \t - chars.push(32); // space - continue; + } else if (code === 9 && !attrBoundary) { // \t - only replace with space outside attribute values + // Flush accumulated segment, add space, start new segment + result += xmlData.substring(segmentStart, index) + ' '; + segmentStart = index + 1; } - - chars.push(code); } } @@ -65104,7 +65541,7 @@ function readStopNodeData(xmlData, tagName, i) { const closeIndex = findClosingIndex(xmlData, "]]>", i, "StopNode is not closed.") - 2; i = closeIndex; } else { - const tagData = readTagExp(xmlData, i, '>') + const tagData = readTagExp(xmlData, i, false) if (tagData) { const openTagName = tagData && tagData.tagName; @@ -65240,6 +65677,10 @@ function compress(arr, options, matcher, readonlyMatcher) { let val = compress(tagObj[property], options, matcher, readonlyMatcher); const isLeaf = isLeafTag(val, options); + if (Object.keys(val).length === 0 && options.alwaysCreateTextNode) { + val[options.textNodeName] = ""; + } + if (tagObj[":@"]) { assignAttributes(val, tagObj[":@"], readonlyMatcher, options); } else if (Object.keys(val).length === 1 && val[options.textNodeName] !== undefined && !options.alwaysCreateTextNode) { @@ -65369,13 +65810,13 @@ class XMLParser { if (validationOption) { if (validationOption === true) validationOption = {}; //validate with default options - const result = validate(xmlData, validationOption); + const result = validator_validate(xmlData, validationOption); if (result !== true) { throw Error(`${result.err.msg}:${result.err.line}:${result.err.col}`) } } - const orderedObjParser = new OrderedObjParser(this.options); - orderedObjParser.entityDecoder.setExternalEntities(this.externalEntities); + const orderedObjParser = new OrderedObjParser(this.options, this.externalEntities); + // orderedObjParser.entityDecoder.setExternalEntities(this.externalEntities); const orderedResult = orderedObjParser.parseXml(xmlData); if (this.options.preserveOrder || orderedResult === undefined) return orderedResult; else return prettify(orderedResult, this.options, orderedObjParser.matcher, orderedObjParser.readonlyMatcher); @@ -65430,20 +65871,34 @@ const xml_common_XML_CHARKEY = "_"; function getCommonOptions(options) { - var _a; return { attributesGroupName: xml_common_XML_ATTRKEY, - textNodeName: (_a = options.xmlCharKey) !== null && _a !== void 0 ? _a : xml_common_XML_CHARKEY, + textNodeName: options.xmlCharKey ?? xml_common_XML_CHARKEY, ignoreAttributes: false, suppressBooleanAttributes: false, }; } function getSerializerOptions(options = {}) { - var _a, _b; - return Object.assign(Object.assign({}, getCommonOptions(options)), { attributeNamePrefix: "@_", format: true, suppressEmptyNode: true, indentBy: "", rootNodeName: (_a = options.rootName) !== null && _a !== void 0 ? _a : "root", cdataPropName: (_b = options.cdataPropName) !== null && _b !== void 0 ? _b : "__cdata" }); + return { + ...getCommonOptions(options), + attributeNamePrefix: "@_", + format: true, + suppressEmptyNode: true, + indentBy: "", + rootNodeName: options.rootName ?? "root", + cdataPropName: options.cdataPropName ?? "__cdata", + }; } function getParserOptions(options = {}) { - return Object.assign(Object.assign({}, getCommonOptions(options)), { parseAttributeValue: false, parseTagValue: false, attributeNamePrefix: "", stopNodes: options.stopNodes, processEntities: true, trimValues: false }); + return { + ...getCommonOptions(options), + parseAttributeValue: false, + parseTagValue: false, + attributeNamePrefix: "", + stopNodes: options.stopNodes, + processEntities: true, + trimValues: false, + }; } /** * Converts given JSON object to XML string @@ -65482,7 +65937,7 @@ async function parseXML(str, opts = {}) { if (!opts.includeRoot) { for (const key of Object.keys(parsedXml)) { const value = parsedXml[key]; - return typeof value === "object" ? Object.assign({}, value) : value; + return typeof value === "object" ? { ...value } : value; } } return parsedXml; @@ -67067,39 +67522,6 @@ class StorageSharedKeyCredential extends Credential { } } //# sourceMappingURL=StorageSharedKeyCredential.js.map -;// CONCATENATED MODULE: ./node_modules/@azure/storage-common/node_modules/@azure/abort-controller/dist/esm/AbortError.js -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. -/** - * This error is thrown when an asynchronous operation has been aborted. - * Check for this error by testing the `name` that the name property of the - * error matches `"AbortError"`. - * - * @example - * ```ts - * const controller = new AbortController(); - * controller.abort(); - * try { - * doAsyncWork(controller.signal) - * } catch (e) { - * if (e.name === 'AbortError') { - * // handle abort error here. - * } - * } - * ``` - */ -class esm_AbortError_AbortError extends Error { - constructor(message) { - super(message); - this.name = "AbortError"; - } -} -//# sourceMappingURL=AbortError.js.map -;// CONCATENATED MODULE: ./node_modules/@azure/storage-common/node_modules/@azure/abort-controller/dist/esm/index.js -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -//# sourceMappingURL=index.js.map ;// CONCATENATED MODULE: ./node_modules/@azure/storage-common/dist/esm/log.js // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. @@ -67157,7 +67579,7 @@ const DEFAULT_RETRY_OPTIONS = { secondaryHost: "", tryTimeoutInMs: undefined, // Use server side default timeout strategy }; -const RETRY_ABORT_ERROR = new esm_AbortError_AbortError("The operation was aborted."); +const RETRY_ABORT_ERROR = new AbortError_AbortError("The operation was aborted."); /** * Retry policy with exponential retry and linear retry implemented. */ @@ -67470,7 +67892,7 @@ const retriableErrors = [ "EPIPE", "REQUEST_SEND_ERROR", ]; -const StorageRetryPolicyV2_RETRY_ABORT_ERROR = new esm_AbortError_AbortError("The operation was aborted."); +const StorageRetryPolicyV2_RETRY_ABORT_ERROR = new AbortError_AbortError("The operation was aborted."); /** * Retry policy with exponential retry and linear retry implemented. */ @@ -67838,7 +68260,7 @@ class UserDelegationKeyCredential { ;// CONCATENATED MODULE: ./node_modules/@azure/storage-blob/dist/esm/utils/constants.js // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -const esm_utils_constants_SDK_VERSION = "12.30.0"; +const esm_utils_constants_SDK_VERSION = "12.31.0"; const SERVICE_VERSION = "2026-02-06"; const BLOCK_BLOB_MAX_UPLOAD_BLOB_BYTES = 256 * 1024 * 1024; // 256MB const BLOCK_BLOB_MAX_STAGE_BLOCK_BYTES = 4000 * 1024 * 1024; // 4000MB @@ -84336,39 +84758,6 @@ class BlobLeaseClient { } } //# sourceMappingURL=BlobLeaseClient.js.map -;// CONCATENATED MODULE: ./node_modules/@azure/storage-blob/node_modules/@azure/abort-controller/dist/esm/AbortError.js -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. -/** - * This error is thrown when an asynchronous operation has been aborted. - * Check for this error by testing the `name` that the name property of the - * error matches `"AbortError"`. - * - * @example - * ```ts - * const controller = new AbortController(); - * controller.abort(); - * try { - * doAsyncWork(controller.signal) - * } catch (e) { - * if (e.name === 'AbortError') { - * // handle abort error here. - * } - * } - * ``` - */ -class dist_esm_AbortError_AbortError extends Error { - constructor(message) { - super(message); - this.name = "AbortError"; - } -} -//# sourceMappingURL=AbortError.js.map -;// CONCATENATED MODULE: ./node_modules/@azure/storage-blob/node_modules/@azure/abort-controller/dist/esm/index.js -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -//# sourceMappingURL=index.js.map ;// CONCATENATED MODULE: ./node_modules/@azure/storage-blob/dist/esm/utils/RetriableReadableStream.js // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. @@ -84448,7 +84837,7 @@ class RetriableReadableStream extends external_node_stream_.Readable { } }; sourceAbortedHandler = () => { - const abortError = new dist_esm_AbortError_AbortError("The operation was aborted."); + const abortError = new AbortError_AbortError("The operation was aborted."); this.destroy(abortError); }; sourceErrorOrEndHandler = (err) => { @@ -85443,7 +85832,7 @@ const external_buffer_namespaceObject = require("buffer"); -const ABORT_ERROR = new dist_esm_AbortError_AbortError("Reading from the avro stream was aborted."); +const ABORT_ERROR = new AbortError_AbortError("Reading from the avro stream was aborted."); class AvroReadableFromStream extends AvroReadable { _position; _readable; @@ -88063,7 +88452,7 @@ class BlobClient extends StorageClient_StorageClient { options.conditions = options.conditions || {}; ensureCpkIfSpecified(options.customerProvidedKey, this.isHttps); return tracingClient.withSpan("BlobClient-download", options, async (updatedOptions) => { - const res = utils_common_assertResponse(await this.blobContext.download({ + const res = utils_common_assertResponse((await this.blobContext.download({ abortSignal: options.abortSignal, leaseAccessConditions: options.conditions, modifiedAccessConditions: { @@ -88079,7 +88468,7 @@ class BlobClient extends StorageClient_StorageClient { snapshot: options.snapshot, cpkInfo: options.customerProvidedKey, tracingOptions: updatedOptions.tracingOptions, - })); + }))); const wrappedRes = { ...res, _response: res._response, // _response is made non-enumerable @@ -89401,7 +89790,7 @@ class BlockBlobClient extends BlobClient { throw new Error("This operation currently is only supported in Node.js."); } return tracingClient.withSpan("BlockBlobClient-query", options, async (updatedOptions) => { - const response = utils_common_assertResponse(await this._blobContext.query({ + const response = utils_common_assertResponse((await this._blobContext.query({ abortSignal: options.abortSignal, queryRequest: { queryType: "SQL", @@ -89416,7 +89805,7 @@ class BlockBlobClient extends BlobClient { }, cpkInfo: options.customerProvidedKey, tracingOptions: updatedOptions.tracingOptions, - })); + }))); return new BlobQueryResponse(response, { abortSignal: options.abortSignal, onProgress: options.onProgress, @@ -91312,9 +91701,9 @@ class BlobBatchClient { return tracingClient.withSpan("BlobBatchClient-submitBatch", options, async (updatedOptions) => { const batchRequestBody = batchRequest.getHttpRequestBody(); // ServiceSubmitBatchResponseModel and ContainerSubmitBatchResponse are compatible for now. - const rawBatchResponse = utils_common_assertResponse(await this.serviceOrContainerContext.submitBatch(utf8ByteLength(batchRequestBody), batchRequest.getMultiPartContentType(), batchRequestBody, { + const rawBatchResponse = utils_common_assertResponse((await this.serviceOrContainerContext.submitBatch(utf8ByteLength(batchRequestBody), batchRequest.getMultiPartContentType(), batchRequestBody, { ...updatedOptions, - })); + }))); // Parse the sub responses result, if logic reaches here(i.e. the batch request succeeded with status code 202). const batchResponseParser = new BatchResponseParser(rawBatchResponse, batchRequest.getSubRequests()); const responseSummary = await batchResponseParser.parseBatchResponse(); @@ -93894,7 +94283,7 @@ NetworkError.isNetworkErrorCode = (code) => { }; class UsageError extends Error { constructor() { - const message = `Cache storage quota has been hit. Unable to upload any new cache entries. Usage is recalculated every 6-12 hours.\nMore info on storage limits: https://docs.github.com/en/billing/managing-billing-for-github-actions/about-billing-for-github-actions#calculating-minute-and-storage-spending`; + const message = `Cache storage quota has been hit. Unable to upload any new cache entries.\nMore info on storage limits: https://docs.github.com/en/billing/managing-billing-for-github-actions/about-billing-for-github-actions#calculating-minute-and-storage-spending`; super(message); this.name = 'UsageError'; } diff --git a/package-lock.json b/package-lock.json index faec97c..480af8d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,8 +21,8 @@ "@types/js-yaml": "^4.0.9", "@types/node": "^25.9.1", "@typescript-eslint/eslint-plugin": "^8.60.0", - "@typescript-eslint/parser": "^8.59.2", - "eslint": "^10.4.0", + "@typescript-eslint/parser": "^8.60.0", + "eslint": "^10.4.1", "eslint-plugin-jest": "^29.15.2", "globals": "^17.6.0", "jest": "^30.4.2", @@ -922,7 +922,9 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.7.1", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.2.tgz", + "integrity": "sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -2782,9 +2784,9 @@ } }, "node_modules/eslint": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.4.0.tgz", - "integrity": "sha512-loXy6bWOoP3EP6JA7jo6p5jMpBJmHmsNZM5SFRHLdh1MGOPurMnNBj4ZlAbaqUAaQWbCr7jHV4P7gzAyryZWkQ==", + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.4.1.tgz", + "integrity": "sha512-AyIKhnOBuOAdueD7RB3xB+YeAWScb9jHsJBgH2Hcde8InP5JYhqrRR6iTMHyTEwgENK54Cp44e4v8BwNhsuHuw==", "dev": true, "license": "MIT", "dependencies": { @@ -2793,7 +2795,7 @@ "@eslint/config-array": "^0.23.5", "@eslint/config-helpers": "^0.6.0", "@eslint/core": "^1.2.1", - "@eslint/plugin-kit": "^0.7.1", + "@eslint/plugin-kit": "^0.7.2", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", diff --git a/package.json b/package.json index 32d97b9..1b0f52e 100644 --- a/package.json +++ b/package.json @@ -37,8 +37,8 @@ "@types/js-yaml": "^4.0.9", "@types/node": "^25.9.1", "@typescript-eslint/eslint-plugin": "^8.60.0", - "@typescript-eslint/parser": "^8.59.2", - "eslint": "^10.4.0", + "@typescript-eslint/parser": "^8.60.0", + "eslint": "^10.4.1", "eslint-plugin-jest": "^29.15.2", "globals": "^17.6.0", "jest": "^30.4.2",