poe-code 15.0.0 → 15.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/dist/metafile.json +1 -1
  2. package/package.json +7 -1
  3. package/packages/safe-bash/dist/chunks/chunk-3ISDVRIM.js +3821 -0
  4. package/packages/safe-bash/dist/chunks/chunk-3ISDVRIM.js.map +7 -0
  5. package/packages/safe-bash/dist/commands/xml/evaluate.d.ts +27 -0
  6. package/packages/safe-bash/dist/commands/xml/evaluate.d.ts.map +1 -0
  7. package/packages/safe-bash/dist/commands/xml/evaluate.js +208 -0
  8. package/packages/safe-bash/dist/commands/xml/evaluate.js.map +1 -0
  9. package/packages/safe-bash/dist/commands/xml/index.browser.js +11 -0
  10. package/packages/safe-bash/dist/commands/xml/index.browser.js.map +7 -0
  11. package/packages/safe-bash/dist/commands/xml/index.d.ts +7 -0
  12. package/packages/safe-bash/dist/commands/xml/index.d.ts.map +1 -0
  13. package/packages/safe-bash/dist/commands/xml/index.js +196 -0
  14. package/packages/safe-bash/dist/commands/xml/index.js.map +1 -0
  15. package/packages/safe-bash/dist/commands/xml/limits.d.ts +36 -0
  16. package/packages/safe-bash/dist/commands/xml/limits.d.ts.map +1 -0
  17. package/packages/safe-bash/dist/commands/xml/limits.js +55 -0
  18. package/packages/safe-bash/dist/commands/xml/limits.js.map +1 -0
  19. package/packages/safe-bash/dist/commands/xml/query.d.ts +21 -0
  20. package/packages/safe-bash/dist/commands/xml/query.d.ts.map +1 -0
  21. package/packages/safe-bash/dist/commands/xml/query.js +111 -0
  22. package/packages/safe-bash/dist/commands/xml/query.js.map +1 -0
  23. package/packages/safe-bash/dist/core.browser.js +990 -3879
  24. package/packages/safe-bash/dist/core.browser.js.map +4 -4
  25. package/packages/safe-bash/dist/core.d.ts +1 -0
  26. package/packages/safe-bash/dist/core.d.ts.map +1 -1
  27. package/packages/safe-bash/dist/core.js +1 -0
  28. package/packages/safe-bash/dist/core.js.map +1 -1
  29. package/packages/safe-bash/dist/plugins/composition.d.ts +2 -0
  30. package/packages/safe-bash/dist/plugins/composition.d.ts.map +1 -1
  31. package/packages/safe-bash/dist/plugins/composition.js +3 -1
  32. package/packages/safe-bash/dist/plugins/composition.js.map +1 -1
  33. package/packages/safe-fs/dist/core.d.ts +2 -0
  34. package/packages/safe-fs/dist/fs/webdav/xml.d.ts +4 -10
  35. package/packages/safe-fs/dist/xml.d.ts +42 -0
  36. package/packages/safe-js/dist/browser/chunks/{chunk-QK4IEGRO.js → chunk-CRKYNANF.js} +304 -67
  37. package/packages/safe-js/dist/browser/chunks/{chunk-QK4IEGRO.js.map → chunk-CRKYNANF.js.map} +4 -4
  38. package/packages/safe-js/dist/browser/safe-fs-core.js +7 -1
  39. package/packages/safe-js/dist/browser/safe-fs.js +7 -1
  40. package/packages/safe-js/dist/chunks/{chunk-BG7WRAD3.js → chunk-7JFJLEHK.js} +3 -3
  41. package/packages/safe-js/dist/chunks/{chunk-XOQ5CVQM.js → chunk-CM4RZVZD.js} +2 -2
  42. package/packages/safe-js/dist/chunks/{chunk-6V4U2JZS.js → chunk-LRGCUDH7.js} +333 -96
  43. package/packages/safe-js/dist/chunks/chunk-LRGCUDH7.js.map +7 -0
  44. package/packages/safe-js/dist/cli.js +3 -3
  45. package/packages/safe-js/dist/index.js +3 -3
  46. package/packages/safe-js/dist/safe-fs-core.js +7 -1
  47. package/packages/safe-js/dist/safe-fs-core.js.map +1 -1
  48. package/packages/safe-js/dist/safe-fs-node.js +2 -2
  49. package/packages/safe-js/dist/safe-fs.js +2 -2
  50. package/packages/safe-js/dist/chunks/chunk-6V4U2JZS.js.map +0 -7
  51. /package/packages/safe-js/dist/chunks/{chunk-BG7WRAD3.js.map → chunk-7JFJLEHK.js.map} +0 -0
  52. /package/packages/safe-js/dist/chunks/{chunk-XOQ5CVQM.js.map → chunk-CM4RZVZD.js.map} +0 -0
@@ -2091,45 +2091,33 @@ function createDeviceFileSystem(filesystem) {
2091
2091
  return view;
2092
2092
  }
2093
2093
 
2094
- // packages/safe-fs/src/contracts/abort.ts
2095
- function composeAbortSignals(signals) {
2096
- const controller = new AbortController();
2097
- const listeners = /* @__PURE__ */ new Map();
2098
- const dispose = () => {
2099
- for (const [signal, listener] of listeners) signal.removeEventListener("abort", listener);
2100
- listeners.clear();
2101
- };
2102
- for (const signal of signals) {
2103
- if (signal.aborted) {
2104
- controller.abort(signal.reason);
2105
- return { signal: controller.signal, dispose };
2106
- }
2094
+ // packages/safe-fs/src/xml.ts
2095
+ var XmlLimitError = class extends SyntaxError {
2096
+ constructor(limit, message) {
2097
+ super(message);
2098
+ this.limit = limit;
2107
2099
  }
2108
- try {
2109
- for (const signal of new Set(signals)) {
2110
- const listener = () => {
2111
- dispose();
2112
- controller.abort(signal.reason);
2113
- };
2114
- listeners.set(signal, listener);
2115
- signal.addEventListener("abort", listener, { once: true });
2116
- if (signal.aborted) listener();
2117
- if (controller.signal.aborted) break;
2100
+ limit;
2101
+ };
2102
+ function* find(source, needle, start) {
2103
+ let work = 0;
2104
+ for (let offset = start; offset < source.length; offset++) {
2105
+ if (source.startsWith(needle, offset)) {
2106
+ if (work) yield work;
2107
+ return offset;
2108
+ }
2109
+ if (++work === 512) {
2110
+ yield work;
2111
+ work = 0;
2118
2112
  }
2119
- } catch (error) {
2120
- dispose();
2121
- throw error;
2122
2113
  }
2123
- return { signal: controller.signal, dispose };
2114
+ if (work) yield work;
2115
+ return -1;
2124
2116
  }
2125
-
2126
- // packages/safe-fs/src/fs/webdav/xml.ts
2127
- var XmlResponseLimitError = class extends SyntaxError {
2128
- };
2129
2117
  var xmlNamespace = "http://www.w3.org/XML/1998/namespace";
2130
2118
  var xmlnsNamespace = "http://www.w3.org/2000/xmlns/";
2131
2119
  function invalid(message) {
2132
- throw new SyntaxError(`Invalid WebDAV XML: ${message}`);
2120
+ throw new SyntaxError(`Invalid XML: ${message}`);
2133
2121
  }
2134
2122
  function validCharacter(point) {
2135
2123
  return point === 9 || point === 10 || point === 13 || point >= 32 && point <= 55295 || point >= 57344 && point <= 65533 || point >= 65536 && point <= 1114111;
@@ -2140,22 +2128,42 @@ function nameStart(point) {
2140
2128
  function namePart(point) {
2141
2129
  return nameStart(point) || point === 45 || point === 46 || point === 183 || point >= 48 && point <= 57 || point >= 768 && point <= 879 || point >= 8255 && point <= 8256;
2142
2130
  }
2143
- function qualifiedName(name) {
2144
- const parts = name.split(":");
2145
- if (parts.length > 2 || parts.some((part) => {
2146
- const points = [...part].map((character) => character.codePointAt(0));
2147
- return points.length === 0 || !nameStart(points[0]) || points.slice(1).some((point) => !namePart(point));
2148
- })) invalid("invalid qualified name");
2149
- return parts.length === 1 ? ["", parts[0]] : [parts[0], parts[1]];
2131
+ function* qualifiedName(name) {
2132
+ let prefix = "";
2133
+ let start = 0;
2134
+ let first = true;
2135
+ let work = 0;
2136
+ for (let offset = 0; offset < name.length; ) {
2137
+ const point = name.codePointAt(offset);
2138
+ if (point === 58) {
2139
+ if (start !== 0 || first) invalid("invalid qualified name");
2140
+ prefix = name.slice(0, offset);
2141
+ start = offset + 1;
2142
+ first = true;
2143
+ } else {
2144
+ if (!(first ? nameStart(point) : namePart(point))) invalid("invalid qualified name");
2145
+ first = false;
2146
+ }
2147
+ const width = point > 65535 ? 2 : 1;
2148
+ offset += width;
2149
+ work += width;
2150
+ if (work >= 512) {
2151
+ yield work;
2152
+ work = 0;
2153
+ }
2154
+ }
2155
+ if (first) invalid("invalid qualified name");
2156
+ if (work) yield work;
2157
+ return [prefix, name.slice(start)];
2150
2158
  }
2151
- function entities(text) {
2159
+ function* entities(text) {
2152
2160
  let result = "";
2153
2161
  let offset = 0;
2154
2162
  while (offset < text.length) {
2155
- const start = text.indexOf("&", offset);
2163
+ const start = yield* find(text, "&", offset);
2156
2164
  if (start < 0) return result + text.slice(offset);
2157
2165
  result += text.slice(offset, start);
2158
- const end = text.indexOf(";", start + 1);
2166
+ const end = yield* find(text, ";", start + 1);
2159
2167
  if (end < 0) invalid("unterminated entity");
2160
2168
  const entity = text.slice(start + 1, end);
2161
2169
  const predefined = { amp: "&", lt: "<", gt: ">", quot: '"', apos: "'" };
@@ -2163,10 +2171,17 @@ function entities(text) {
2163
2171
  else {
2164
2172
  const hexadecimal = entity.startsWith("#x");
2165
2173
  const digits = entity.slice(hexadecimal ? 2 : 1);
2166
- if (!entity.startsWith("#") || !(hexadecimal ? /^[0-9a-fA-F]+$/ : /^[0-9]+$/).test(digits)) {
2167
- invalid("undeclared entity");
2174
+ if (!entity.startsWith("#") || !digits.length) invalid("undeclared entity");
2175
+ let point = 0;
2176
+ for (let index = 0; index < digits.length; index++) {
2177
+ const code = digits.charCodeAt(index);
2178
+ const digit = code >= 48 && code <= 57 ? code - 48 : hexadecimal && code >= 65 && code <= 70 ? code - 55 : hexadecimal && code >= 97 && code <= 102 ? code - 87 : -1;
2179
+ if (digit < 0) invalid("undeclared entity");
2180
+ point = point * (hexadecimal ? 16 : 10) + digit;
2181
+ if (point > 1114111) invalid("invalid character reference");
2182
+ if ((index + 1) % 512 === 0) yield 512;
2168
2183
  }
2169
- const point = Number.parseInt(digits, hexadecimal ? 16 : 10);
2184
+ if (digits.length % 512) yield digits.length % 512;
2170
2185
  if (!validCharacter(point)) invalid("invalid character reference");
2171
2186
  result += String.fromCodePoint(point);
2172
2187
  }
@@ -2174,149 +2189,368 @@ function entities(text) {
2174
2189
  }
2175
2190
  return result;
2176
2191
  }
2177
- function parseXml(input, limits = {}) {
2192
+ function* validDeclaration(content, expectedEncoding) {
2193
+ let offset = 0;
2194
+ const whitespace = function* () {
2195
+ const start = offset;
2196
+ while (offset < content.length && " \n\r".includes(content[offset])) {
2197
+ offset++;
2198
+ if ((offset - start) % 512 === 0) yield 512;
2199
+ }
2200
+ if ((offset - start) % 512) yield (offset - start) % 512;
2201
+ return offset - start;
2202
+ };
2203
+ const field = function* (name) {
2204
+ if (content.slice(offset, offset + name.length).toLowerCase() !== name) return void 0;
2205
+ offset += name.length;
2206
+ yield name.length;
2207
+ yield* whitespace();
2208
+ if (content[offset++] !== "=") return void 0;
2209
+ yield* whitespace();
2210
+ const quote = content[offset++];
2211
+ if (quote !== "'" && quote !== '"') return void 0;
2212
+ const start = offset;
2213
+ while (offset < content.length && content[offset] !== quote) {
2214
+ offset++;
2215
+ if ((offset - start) % 512 === 0) yield 512;
2216
+ }
2217
+ if ((offset - start) % 512) yield (offset - start) % 512;
2218
+ if (offset >= content.length) return void 0;
2219
+ return content.slice(start, offset++);
2220
+ };
2221
+ if (!(yield* whitespace()) || (yield* field("version")) !== "1.0") return false;
2222
+ let spacing = yield* whitespace();
2223
+ if (content.slice(offset, offset + 8).toLowerCase() === "encoding") {
2224
+ if (!spacing) return false;
2225
+ const encoding = yield* field("encoding");
2226
+ if (encoding === void 0 || encoding.length > 8 || !["utf-8", "utf-16", "utf-16le", "utf-16be"].includes(encoding.toLowerCase())) return false;
2227
+ if (expectedEncoding !== void 0 && encoding.toLowerCase() !== expectedEncoding.toLowerCase()) return false;
2228
+ spacing = yield* whitespace();
2229
+ }
2230
+ if (content.slice(offset, offset + 10).toLowerCase() === "standalone") {
2231
+ if (!spacing) return false;
2232
+ const standalone = yield* field("standalone");
2233
+ if (standalone === void 0 || standalone.length > 3 || !["yes", "no"].includes(standalone.toLowerCase())) return false;
2234
+ yield* whitespace();
2235
+ }
2236
+ return offset === content.length;
2237
+ }
2238
+ function* parseXmlSteps(input, limits = {}) {
2178
2239
  const maxDepth = limits.maxDepth ?? 64;
2179
2240
  const maxNodes = limits.maxNodes ?? 1e5;
2180
2241
  const maxAttributes = limits.maxAttributes ?? 1e4;
2181
- for (const limit of [maxDepth, maxNodes, maxAttributes, ...limits.maxResponses === void 0 ? [] : [limits.maxResponses]]) {
2242
+ const retainContent = limits.retainContent !== false;
2243
+ const maxContentNodes = limits.maxContentNodes ?? (retainContent ? 1e5 : maxNodes);
2244
+ const emptyContent = Object.freeze([]);
2245
+ const emptyAttributes = Object.freeze([]);
2246
+ const emptyNamespaces = /* @__PURE__ */ new Map();
2247
+ const maxAttributesPerElement = limits.maxAttributesPerElement ?? 128;
2248
+ const maxNamespaces = limits.maxNamespaces ?? 256;
2249
+ for (const limit of [maxDepth, maxNodes, maxAttributes, maxContentNodes, maxAttributesPerElement, maxNamespaces]) {
2182
2250
  if (!Number.isSafeInteger(limit) || limit < 1) throw new RangeError("XML limits must be positive integers");
2183
2251
  }
2184
- for (const character of input) {
2185
- if (!validCharacter(character.codePointAt(0))) invalid("invalid character");
2252
+ const chunks = [];
2253
+ let chunk = "";
2254
+ for (let index = input.charCodeAt(0) === 65279 ? 1 : 0; index < input.length; index++) {
2255
+ const point = input.codePointAt(index);
2256
+ if (!validCharacter(point)) invalid("invalid character");
2257
+ if (point === 13) {
2258
+ chunk += "\n";
2259
+ if (input.charCodeAt(index + 1) === 10) index++;
2260
+ } else {
2261
+ chunk += String.fromCodePoint(point);
2262
+ if (point > 65535) index++;
2263
+ }
2264
+ if (chunk.length >= 512) {
2265
+ chunks.push(chunk);
2266
+ chunk = "";
2267
+ yield 512;
2268
+ }
2186
2269
  }
2187
- const source = input.replace(/^\uFEFF/, "").replace(/\r\n?/g, "\n");
2270
+ chunks.push(chunk);
2271
+ if (chunk.length) yield chunk.length;
2272
+ const source = chunks.join("");
2188
2273
  const stack = [];
2189
2274
  let root;
2275
+ let declaration;
2190
2276
  let offset = 0;
2191
2277
  let nodes = 0;
2192
2278
  let attributeCount = 0;
2193
- let responses2 = 0;
2194
- const whitespace = () => {
2195
- while (offset < source.length && " \n\r".includes(source[offset])) offset++;
2279
+ let contentNodes = 0;
2280
+ const admitContent = () => {
2281
+ if (++contentNodes > maxContentNodes) throw new XmlLimitError("maxContentNodes", "XML content node limit exceeded");
2282
+ };
2283
+ const whitespace = function* () {
2284
+ let work = 0;
2285
+ while (offset < source.length && " \n\r".includes(source[offset])) {
2286
+ offset++;
2287
+ if (++work === 512) {
2288
+ yield work;
2289
+ work = 0;
2290
+ }
2291
+ }
2292
+ if (work) yield work;
2196
2293
  };
2197
- const readName = () => {
2294
+ const readName = function* () {
2198
2295
  const start = offset;
2199
- while (offset < source.length && !" \r\n/=>?".includes(source[offset])) offset++;
2296
+ while (offset < source.length && !" \r\n/=>?".includes(source[offset])) {
2297
+ offset++;
2298
+ if ((offset - start) % 512 === 0) yield 512;
2299
+ }
2300
+ if ((offset - start) % 512) yield (offset - start) % 512;
2200
2301
  const name = source.slice(start, offset);
2201
- qualifiedName(name);
2302
+ yield* qualifiedName(name);
2202
2303
  return name;
2203
2304
  };
2204
- const appendText = (text) => {
2305
+ const appendText = function* (text, kind = "text") {
2205
2306
  const parent = stack.at(-1);
2206
- if (parent) parent.element.text += text;
2207
- else if (!/^[ \t\r\n]*$/.test(text)) invalid("text outside the root");
2307
+ if (parent) {
2308
+ parent.element.text += text;
2309
+ if (retainContent && (text.length || kind === "cdata")) {
2310
+ admitContent();
2311
+ parent.content.push({ kind, text });
2312
+ }
2313
+ } else {
2314
+ for (let index = 0; index < text.length; index++) {
2315
+ if (!" \r\n".includes(text[index])) invalid("text outside the root");
2316
+ if ((index + 1) % 512 === 0) yield 512;
2317
+ }
2318
+ if (text.length % 512) yield text.length % 512;
2319
+ }
2208
2320
  };
2209
2321
  while (offset < source.length) {
2322
+ yield 1;
2210
2323
  if (source[offset] !== "<") {
2211
- const next = source.indexOf("<", offset);
2324
+ const next = yield* find(source, "<", offset);
2212
2325
  const text = source.slice(offset, next < 0 ? source.length : next);
2213
- if (text.includes("]]>")) invalid("CDATA terminator in text");
2214
- appendText(entities(text));
2326
+ if ((yield* find(text, "]]>", 0)) >= 0) invalid("CDATA terminator in text");
2327
+ yield* appendText(yield* entities(text));
2215
2328
  offset += text.length;
2216
2329
  } else if (source.startsWith("<!--", offset)) {
2217
- const end = source.indexOf("-->", offset + 4);
2218
- if (end < 0 || source.slice(offset + 4, end).includes("--") || source.slice(offset + 4, end).endsWith("-")) {
2330
+ const end = yield* find(source, "-->", offset + 4);
2331
+ if (end < 0 || (yield* find(source.slice(offset + 4, end), "--", 0)) >= 0 || source.slice(offset + 4, end).endsWith("-")) {
2219
2332
  invalid("malformed comment");
2220
2333
  }
2334
+ const parent = stack.at(-1);
2335
+ if (retainContent && parent) {
2336
+ admitContent();
2337
+ parent.content.push({ kind: "comment", text: source.slice(offset + 4, end) });
2338
+ }
2221
2339
  offset = end + 3;
2222
2340
  } else if (source.startsWith("<![CDATA[", offset)) {
2223
2341
  if (!stack.length) invalid("CDATA outside root");
2224
- const end = source.indexOf("]]>", offset + 9);
2342
+ const end = yield* find(source, "]]>", offset + 9);
2225
2343
  if (end < 0) invalid("unterminated CDATA");
2226
- appendText(source.slice(offset + 9, end));
2344
+ yield* appendText(source.slice(offset + 9, end), "cdata");
2227
2345
  offset = end + 3;
2228
2346
  } else if (source.startsWith("<?", offset)) {
2229
2347
  const start = offset;
2230
2348
  offset += 2;
2231
- const target = readName();
2232
- const end = source.indexOf("?>", offset);
2349
+ const target = yield* readName();
2350
+ const end = yield* find(source, "?>", offset);
2233
2351
  if (end < 0) invalid("unterminated processing instruction");
2234
2352
  const content = source.slice(offset, end);
2235
- if (target.toLowerCase() === "xml") {
2236
- if (start !== 0 || target !== "xml" || !/^\s+version\s*=\s*(['"])1\.0\1(?:\s+encoding\s*=\s*(['"])(?:UTF-8|UTF-16|UTF-16LE|UTF-16BE)\2)?(?:\s+standalone\s*=\s*(['"])(?:yes|no)\3)?\s*$/i.test(content)) {
2353
+ if (target.length === 3 && target.toLowerCase() === "xml") {
2354
+ if (start !== 0 || target !== "xml" || !(yield* validDeclaration(content, limits.expectedEncoding))) {
2237
2355
  invalid("unsupported XML declaration");
2238
2356
  }
2357
+ if (retainContent) declaration = source.slice(start, end + 2);
2239
2358
  } else if (content && !" \n\r".includes(content[0])) invalid("invalid processing instruction");
2359
+ if (!(target.length === 3 && target.toLowerCase() === "xml")) {
2360
+ const parent = stack.at(-1);
2361
+ if (retainContent && parent) {
2362
+ let start2 = 0;
2363
+ while (start2 < content.length && " \n\r".includes(content[start2])) {
2364
+ start2++;
2365
+ if (start2 % 512 === 0) yield 512;
2366
+ }
2367
+ if (start2 % 512) yield start2 % 512;
2368
+ admitContent();
2369
+ parent.content.push({ kind: "processing-instruction", target, text: content.slice(start2) });
2370
+ }
2371
+ }
2240
2372
  offset = end + 2;
2241
2373
  } else if (source.startsWith("<!", offset)) {
2242
2374
  invalid("DTD and entity declarations are forbidden");
2243
2375
  } else if (source.startsWith("</", offset)) {
2244
2376
  offset += 2;
2245
- const name = readName();
2246
- whitespace();
2377
+ const name = yield* readName();
2378
+ yield* whitespace();
2247
2379
  if (source[offset++] !== ">" || stack.pop()?.name !== name) invalid("mismatched closing tag");
2248
2380
  } else {
2249
2381
  offset++;
2250
- const name = readName();
2382
+ const name = yield* readName();
2251
2383
  const attributes = /* @__PURE__ */ new Map();
2252
- const namespaces = new Map(stack.at(-1)?.namespaces ?? [["xml", xmlNamespace]]);
2384
+ let namespaces = stack.at(-1)?.namespaces ?? /* @__PURE__ */ new Map([["xml", xmlNamespace]]);
2385
+ let ownsNamespaces = stack.length === 0;
2253
2386
  while (true) {
2254
2387
  const beforeSpace = offset;
2255
- whitespace();
2388
+ yield* whitespace();
2256
2389
  if (source[offset] === "/" || source[offset] === ">") break;
2257
2390
  if (offset === beforeSpace) invalid("attributes require whitespace");
2258
- const attribute = readName();
2391
+ const attribute = yield* readName();
2259
2392
  if (attributes.has(attribute)) invalid("duplicate attribute");
2260
- if (++attributeCount > maxAttributes || attributes.size >= 128) invalid("XML attribute limit exceeded");
2261
- whitespace();
2393
+ if (++attributeCount > maxAttributes) throw new XmlLimitError("maxAttributes", "XML attribute limit exceeded");
2394
+ if (attributes.size >= maxAttributesPerElement) throw new XmlLimitError("maxAttributesPerElement", "XML attribute limit exceeded");
2395
+ yield* whitespace();
2262
2396
  if (source[offset++] !== "=") invalid("missing attribute equals");
2263
- whitespace();
2397
+ yield* whitespace();
2264
2398
  const quote = source[offset++];
2265
2399
  if (quote !== '"' && quote !== "'") invalid("unquoted attribute");
2266
- const end = source.indexOf(quote, offset);
2400
+ const end = yield* find(source, quote, offset);
2267
2401
  if (end < 0) invalid("unterminated attribute");
2268
2402
  const raw = source.slice(offset, end);
2269
- if (raw.includes("<")) invalid("less-than in attribute");
2270
- const value = entities(raw.replace(/[\t\n\r]/g, " "));
2403
+ if ((yield* find(raw, "<", 0)) >= 0) invalid("less-than in attribute");
2404
+ let normalized = "";
2405
+ for (let index = 0; index < raw.length; index++) {
2406
+ const character = raw[index];
2407
+ normalized += character === " " || character === "\n" || character === "\r" ? " " : character;
2408
+ if ((index + 1) % 512 === 0) yield 512;
2409
+ }
2410
+ if (raw.length % 512) yield raw.length % 512;
2411
+ const value = yield* entities(normalized);
2271
2412
  attributes.set(attribute, value);
2272
2413
  offset = end + 1;
2273
2414
  if (attribute === "xmlns" || attribute.startsWith("xmlns:")) {
2274
2415
  const prefix2 = attribute === "xmlns" ? "" : attribute.slice(6);
2275
2416
  if (prefix2 === "xmlns" || value === xmlnsNamespace || prefix2 === "xml" !== (value === xmlNamespace) || prefix2 !== "" && value === "") invalid("invalid namespace binding");
2417
+ if (!ownsNamespaces) {
2418
+ const copy = /* @__PURE__ */ new Map();
2419
+ for (const [key, uri] of namespaces) {
2420
+ copy.set(key, uri);
2421
+ yield 1;
2422
+ }
2423
+ namespaces = copy;
2424
+ ownsNamespaces = true;
2425
+ }
2276
2426
  namespaces.set(prefix2, value);
2277
- if (namespaces.size > 256) invalid("XML namespace scope limit exceeded");
2427
+ if (namespaces.size > maxNamespaces) throw new XmlLimitError("maxNamespaces", "XML namespace scope limit exceeded");
2278
2428
  }
2279
2429
  }
2280
2430
  const expanded = /* @__PURE__ */ new Set();
2281
2431
  for (const attribute of attributes.keys()) {
2282
2432
  if (attribute === "xmlns" || attribute.startsWith("xmlns:")) continue;
2283
- const [prefix2, localName2] = qualifiedName(attribute);
2433
+ const [prefix2, localName2] = yield* qualifiedName(attribute);
2284
2434
  if (prefix2 && !namespaces.has(prefix2)) invalid("unbound attribute prefix");
2285
2435
  const key = JSON.stringify([prefix2 ? namespaces.get(prefix2) : "", localName2]);
2286
2436
  if (expanded.has(key)) invalid("duplicate expanded attribute");
2287
2437
  expanded.add(key);
2288
2438
  }
2289
- const [prefix, localName] = qualifiedName(name);
2439
+ const [prefix, localName] = yield* qualifiedName(name);
2290
2440
  if (prefix === "xmlns" || prefix && !namespaces.has(prefix)) invalid("unbound element prefix");
2291
- if (++nodes > maxNodes || stack.length + 1 > maxDepth) invalid("XML resource limit exceeded");
2441
+ if (++nodes > maxNodes) throw new XmlLimitError("maxNodes", "XML resource limit exceeded");
2442
+ if (stack.length + 1 > maxDepth) throw new XmlLimitError("maxDepth", "XML resource limit exceeded");
2292
2443
  const namespace = namespaces.get(prefix) ?? "";
2293
- if (limits.maxResponses !== void 0 && stack.length === 1 && root?.namespace === "DAV:" && root.localName === "multistatus" && namespace === "DAV:" && localName === "response" && ++responses2 > limits.maxResponses) {
2294
- throw new XmlResponseLimitError("WebDAV XML response limit exceeded");
2444
+ limits.onElement?.({ name, namespace, localName }, stack.at(-1)?.element, stack.length + 1);
2445
+ admitContent();
2446
+ const retainedAttributes = [];
2447
+ for (const [attribute, value] of retainContent ? attributes : []) {
2448
+ const [prefix2, localName2] = yield* qualifiedName(attribute);
2449
+ admitContent();
2450
+ retainedAttributes.push({
2451
+ name: attribute,
2452
+ localName: localName2,
2453
+ namespace: attribute === "xmlns" || prefix2 === "xmlns" ? xmlnsNamespace : prefix2 ? namespaces.get(prefix2) : "",
2454
+ value
2455
+ });
2456
+ yield 1;
2295
2457
  }
2296
- const element = { namespace, localName, children: [], text: "" };
2458
+ const content = retainContent ? [] : void 0;
2459
+ const element = { kind: "element", name, namespace, localName, children: [], text: "", content: content ?? emptyContent, attributes: retainContent ? retainedAttributes : emptyAttributes, namespaces: retainContent ? namespaces : emptyNamespaces, ...root === void 0 && declaration !== void 0 ? { declaration } : {} };
2297
2460
  const parent = stack.at(-1);
2298
- if (parent) parent.element.children.push(element);
2299
- else if (root) invalid("multiple root elements");
2461
+ if (parent) {
2462
+ parent.element.children.push(element);
2463
+ parent.content?.push(element);
2464
+ } else if (root) invalid("multiple root elements");
2300
2465
  else root = element;
2301
2466
  const empty = source[offset] === "/";
2302
2467
  if (empty) offset++;
2303
2468
  if (source[offset++] !== ">") invalid("unterminated start tag");
2304
- if (!empty) stack.push({ element, name, namespaces });
2469
+ if (!empty) stack.push({ element, content, name, namespaces });
2305
2470
  }
2306
2471
  }
2307
2472
  if (stack.length || !root) invalid("incomplete document");
2308
2473
  return root;
2309
2474
  }
2475
+ function parseXml(input, limits = {}) {
2476
+ const parser = parseXmlSteps(input, limits);
2477
+ let result = parser.next();
2478
+ while (!result.done) result = parser.next();
2479
+ return result.value;
2480
+ }
2481
+
2482
+ // packages/safe-fs/src/contracts/abort.ts
2483
+ function composeAbortSignals(signals) {
2484
+ const controller = new AbortController();
2485
+ const listeners = /* @__PURE__ */ new Map();
2486
+ const dispose = () => {
2487
+ for (const [signal, listener] of listeners) signal.removeEventListener("abort", listener);
2488
+ listeners.clear();
2489
+ };
2490
+ for (const signal of signals) {
2491
+ if (signal.aborted) {
2492
+ controller.abort(signal.reason);
2493
+ return { signal: controller.signal, dispose };
2494
+ }
2495
+ }
2496
+ try {
2497
+ for (const signal of new Set(signals)) {
2498
+ const listener = () => {
2499
+ dispose();
2500
+ controller.abort(signal.reason);
2501
+ };
2502
+ listeners.set(signal, listener);
2503
+ signal.addEventListener("abort", listener, { once: true });
2504
+ if (signal.aborted) listener();
2505
+ if (controller.signal.aborted) break;
2506
+ }
2507
+ } catch (error) {
2508
+ dispose();
2509
+ throw error;
2510
+ }
2511
+ return { signal: controller.signal, dispose };
2512
+ }
2513
+
2514
+ // packages/safe-fs/src/fs/webdav/xml.ts
2515
+ var XmlResponseLimitError = class extends SyntaxError {
2516
+ };
2517
+ function invalid2(message) {
2518
+ throw new SyntaxError(`Invalid WebDAV XML: ${message}`);
2519
+ }
2520
+ function parseXml2(input, limits = {}) {
2521
+ const { maxResponses, ...documentLimits } = limits;
2522
+ if (maxResponses !== void 0 && (!Number.isSafeInteger(maxResponses) || maxResponses < 1)) {
2523
+ throw new RangeError("XML limits must be positive integers");
2524
+ }
2525
+ let responses2 = 0;
2526
+ try {
2527
+ return parseXml(input, {
2528
+ ...documentLimits,
2529
+ retainContent: false,
2530
+ onElement(element, parent, depth) {
2531
+ if (maxResponses !== void 0 && depth === 2 && parent?.namespace === "DAV:" && parent.localName === "multistatus" && element.namespace === "DAV:" && element.localName === "response" && ++responses2 > maxResponses) {
2532
+ throw new XmlResponseLimitError("WebDAV XML response limit exceeded");
2533
+ }
2534
+ }
2535
+ });
2536
+ } catch (error) {
2537
+ if (error instanceof XmlLimitError) invalid2(error.message);
2538
+ if (error instanceof SyntaxError && error.message.startsWith("Invalid XML:")) {
2539
+ error.message = error.message.replace("Invalid XML:", "Invalid WebDAV XML:");
2540
+ }
2541
+ throw error;
2542
+ }
2543
+ }
2310
2544
  function davChildren(element, localName) {
2311
2545
  return element.children.filter((child) => child.namespace === "DAV:" && child.localName === localName);
2312
2546
  }
2313
2547
  function davChild(element, localName) {
2314
2548
  const children = davChildren(element, localName);
2315
- if (children.length > 1) invalid(`duplicate DAV:${localName}`);
2549
+ if (children.length > 1) invalid2(`duplicate DAV:${localName}`);
2316
2550
  return children[0];
2317
2551
  }
2318
2552
  function scalar(element) {
2319
- if (element.children.length) invalid("expected text-only element");
2553
+ if (element.children.length) invalid2("expected text-only element");
2320
2554
  return element.text.trim();
2321
2555
  }
2322
2556
 
@@ -2800,7 +3034,7 @@ var WebDavFileSystem = class {
2800
3034
  async xml(response, signal, maxResponses) {
2801
3035
  const data = await this.bytes(response, this.maxXmlBytes, signal);
2802
3036
  const encoding = data[0] === 255 && data[1] === 254 || data[0] === 60 && data[1] === 0 ? "utf-16le" : data[0] === 254 && data[1] === 255 || data[0] === 0 && data[1] === 60 ? "utf-16be" : "utf-8";
2803
- return parseXml(new TextDecoder(encoding, { fatal: true }).decode(data), maxResponses === void 0 ? void 0 : { maxResponses });
3037
+ return parseXml2(new TextDecoder(encoding, { fatal: true }).decode(data), maxResponses === void 0 ? void 0 : { maxResponses });
2804
3038
  }
2805
3039
  async multistatus(response, signal, method = "PROPFIND", path = "") {
2806
3040
  const link = response.headers.get("link");
@@ -6046,6 +6280,9 @@ export {
6046
6280
  DeviceFileSystem,
6047
6281
  createDeviceFileSystem,
6048
6282
  composeAbortSignals,
6283
+ XmlLimitError,
6284
+ parseXmlSteps,
6285
+ parseXml,
6049
6286
  WebDavFileSystem,
6050
6287
  ReadOnlyFileSystem,
6051
6288
  createReadOnlyFileSystem,
@@ -6058,4 +6295,4 @@ export {
6058
6295
  scopeFileSystem,
6059
6296
  FileSystemBridge
6060
6297
  };
6061
- //# sourceMappingURL=chunk-6V4U2JZS.js.map
6298
+ //# sourceMappingURL=chunk-LRGCUDH7.js.map