rork-xcode 0.11.0 → 0.12.0

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.
package/dist/index.js CHANGED
@@ -213,20 +213,25 @@ function createReferenceComments(root) {
213
213
  *
214
214
  * @module
215
215
  */
216
- /** UTF-16 code unit of `\n`, used to count lines when reporting a failure. */
217
216
  const LINE_FEED = 10;
217
+ const CARRIAGE_RETURN = 13;
218
218
  /**
219
219
  * Converts a source offset into a position.
220
220
  *
221
221
  * Runs only when an error is actually thrown, so parsing never pays for line
222
- * tracking on the happy path.
222
+ * tracking on the happy path. All three line-ending conventions count as
223
+ * one break each, with the carriage return of a `\r\n` pair deferring to
224
+ * its line feed.
223
225
  */
224
226
  function positionAt(source, offset) {
225
227
  let line = 1;
226
228
  let lineStart = 0;
227
- for (let i = 0; i < offset && i < source.length; i++) if (source.charCodeAt(i) === LINE_FEED) {
228
- line++;
229
- lineStart = i + 1;
229
+ for (let i = 0; i < offset && i < source.length; i++) {
230
+ const code = source.charCodeAt(i);
231
+ if (code === LINE_FEED || code === CARRIAGE_RETURN && source.charCodeAt(i + 1) !== LINE_FEED) {
232
+ line++;
233
+ lineStart = i + 1;
234
+ }
230
235
  }
231
236
  return {
232
237
  offset,
@@ -283,6 +288,30 @@ var XcschemeParseError = class extends Error {
283
288
  }
284
289
  };
285
290
  /**
291
+ * Thrown when the source text is not a well-formed workspace data file
292
+ * (the XML dialect of `contents.xcworkspacedata` files).
293
+ *
294
+ * The message always embeds the line and column of the failure, and the
295
+ * same information is available in structured form on {@link position}
296
+ * for programmatic use.
297
+ */
298
+ var XcworkspaceParseError = class extends Error {
299
+ /** Where in the source text parsing failed. */
300
+ position;
301
+ /**
302
+ * @param message Failure description without location. The location is
303
+ * appended automatically.
304
+ * @param source Full source text, used to compute the position.
305
+ * @param offset Character offset of the failure inside `source`.
306
+ */
307
+ constructor(message, source, offset) {
308
+ const position = positionAt(source, offset);
309
+ super(`${message} (line ${position.line}, column ${position.column})`);
310
+ this.name = "XcworkspaceParseError";
311
+ this.position = position;
312
+ }
313
+ };
314
+ /**
286
315
  * Thrown when the source text is not a well-formed build configuration
287
316
  * file (the line-based format of `.xcconfig` files).
288
317
  *
@@ -328,6 +357,27 @@ var XcschemeBuildError = class extends Error {
328
357
  }
329
358
  };
330
359
  /**
360
+ * Thrown when a workspace element cannot be written as XML.
361
+ *
362
+ * Raised for element and attribute names that are not valid XML names and
363
+ * for attribute values carrying control characters XML 1.0 cannot encode.
364
+ * The {@link path} pinpoints the offending element inside the tree.
365
+ */
366
+ var XcworkspaceBuildError = class extends Error {
367
+ /** Path to the offending element from the root, e.g. `Workspace.FileRef[0]`. */
368
+ path;
369
+ /**
370
+ * @param message Failure description without location. The element path
371
+ * is appended automatically.
372
+ * @param path Path to the offending element from the root.
373
+ */
374
+ constructor(message, path) {
375
+ super(`${message} (at ${path})`);
376
+ this.name = "XcworkspaceBuildError";
377
+ this.path = path;
378
+ }
379
+ };
380
+ /**
331
381
  * Thrown by the object model when an operation cannot proceed, because the
332
382
  * document lacks the structure the operation needs (no objects dictionary,
333
383
  * no root project object), a view's object was removed from the document,
@@ -524,17 +574,17 @@ function sanitizeComment(comment) {
524
574
  * Sharing the strings avoids a `"\t".repeat(depth)` allocation on every
525
575
  * line of output.
526
576
  */
527
- const INDENTS = [""];
577
+ const INDENTS$1 = [""];
528
578
  /**
529
579
  * Returns the shared indentation string for a nesting depth.
530
580
  */
531
581
  function indentString(depth) {
532
- const cached = INDENTS[depth];
582
+ const cached = INDENTS$1[depth];
533
583
  if (cached != null) return cached;
534
- let known = INDENTS.at(-1);
535
- while (INDENTS.length <= depth) {
584
+ let known = INDENTS$1.at(-1);
585
+ while (INDENTS$1.length <= depth) {
536
586
  known += " ";
537
- INDENTS.push(known);
587
+ INDENTS$1.push(known);
538
588
  }
539
589
  return known;
540
590
  }
@@ -896,8 +946,7 @@ function expandReference(reference, inner, lookup, expandLookupValues, active) {
896
946
  const name = colon === -1 ? inner : inner.slice(0, colon);
897
947
  if (active.has(name)) return reference;
898
948
  const raw = lookup(name);
899
- const nested = new Set(active);
900
- nested.add(name);
949
+ const nested = /* @__PURE__ */ new Set([...active, name]);
901
950
  let value = raw;
902
951
  if (raw != null && expandLookupValues) value = expand(raw, lookup, expandLookupValues, nested);
903
952
  if (colon !== -1) {
@@ -2228,11 +2277,11 @@ const IS_LITERAL_CHAR = (() => {
2228
2277
  for (const ch of "_$/:.-") table[ch.charCodeAt(0)] = 1;
2229
2278
  return table;
2230
2279
  })();
2231
- const CODE_TAB$1 = 9;
2232
- const CODE_LINE_FEED$1 = 10;
2233
- const CODE_CARRIAGE_RETURN$1 = 13;
2280
+ const CODE_TAB$2 = 9;
2281
+ const CODE_LINE_FEED$2 = 10;
2282
+ const CODE_CARRIAGE_RETURN$2 = 13;
2234
2283
  const CODE_SPACE$1 = 32;
2235
- const CODE_QUOTE$1 = 34;
2284
+ const CODE_QUOTE$2 = 34;
2236
2285
  const CODE_SINGLE_QUOTE = 39;
2237
2286
  const CODE_OPEN_PAREN = 40;
2238
2287
  const CODE_CLOSE_PAREN = 41;
@@ -2244,9 +2293,9 @@ const CODE_SLASH$1 = 47;
2244
2293
  const CODE_ZERO = 48;
2245
2294
  const CODE_NINE = 57;
2246
2295
  const CODE_SEMICOLON = 59;
2247
- const CODE_LESS_THAN$1 = 60;
2296
+ const CODE_LESS_THAN$2 = 60;
2248
2297
  const CODE_EQUALS$1 = 61;
2249
- const CODE_GREATER_THAN$1 = 62;
2298
+ const CODE_GREATER_THAN$2 = 62;
2250
2299
  const CODE_BACKSLASH = 92;
2251
2300
  const CODE_OPEN_BRACE = 123;
2252
2301
  const CODE_CLOSE_BRACE = 125;
@@ -2259,9 +2308,9 @@ const CODE_CLOSE_BRACE = 125;
2259
2308
  const IS_WHITESPACE = (() => {
2260
2309
  const table = /* @__PURE__ */ new Uint8Array(256);
2261
2310
  table[CODE_SPACE$1] = 1;
2262
- table[CODE_TAB$1] = 1;
2263
- table[CODE_CARRIAGE_RETURN$1] = 1;
2264
- table[CODE_LINE_FEED$1] = 1;
2311
+ table[CODE_TAB$2] = 1;
2312
+ table[CODE_CARRIAGE_RETURN$2] = 1;
2313
+ table[CODE_LINE_FEED$2] = 1;
2265
2314
  return table;
2266
2315
  })();
2267
2316
  /**
@@ -2439,7 +2488,7 @@ var Parser$1 = class {
2439
2488
  const input = this.input;
2440
2489
  const length = input.length;
2441
2490
  const start = ++this.pos;
2442
- while (this.pos < length && input.charCodeAt(this.pos) !== CODE_GREATER_THAN$1) this.pos++;
2491
+ while (this.pos < length && input.charCodeAt(this.pos) !== CODE_GREATER_THAN$2) this.pos++;
2443
2492
  if (this.pos >= length) this.fail("Unterminated data run", start - 1);
2444
2493
  let hex = "";
2445
2494
  for (let i = start; i < this.pos; i++) {
@@ -2482,7 +2531,7 @@ var Parser$1 = class {
2482
2531
  return result;
2483
2532
  }
2484
2533
  let key;
2485
- if (code === CODE_QUOTE$1 || code === CODE_SINGLE_QUOTE) key = this.readQuotedString();
2534
+ if (code === CODE_QUOTE$2 || code === CODE_SINGLE_QUOTE) key = this.readQuotedString();
2486
2535
  else if (IS_LITERAL_CHAR[code] === 1) key = this.readLiteral();
2487
2536
  else this.fail(`Expected a key but found '${input[this.pos]}'`);
2488
2537
  this.expect(CODE_EQUALS$1, "=");
@@ -2538,9 +2587,9 @@ var Parser$1 = class {
2538
2587
  const code = this.input.charCodeAt(this.pos);
2539
2588
  if (code === CODE_OPEN_BRACE) return this.parseObject();
2540
2589
  if (code === CODE_OPEN_PAREN) return this.parseArray();
2541
- if (code === CODE_QUOTE$1 || code === CODE_SINGLE_QUOTE) return this.readQuotedString();
2590
+ if (code === CODE_QUOTE$2 || code === CODE_SINGLE_QUOTE) return this.readQuotedString();
2542
2591
  if (IS_LITERAL_CHAR[code] === 1) return interpretLiteral(this.readLiteral());
2543
- if (code === CODE_LESS_THAN$1) return this.readData();
2592
+ if (code === CODE_LESS_THAN$2) return this.readData();
2544
2593
  this.fail(`Expected a value but found '${this.input[this.pos]}'`);
2545
2594
  }
2546
2595
  };
@@ -3208,8 +3257,7 @@ var Target = class extends XcodeObject {
3208
3257
  const resolve = (name, fromLayer, active) => {
3209
3258
  const guard = `${fromLayer}:${name}`;
3210
3259
  if (active.has(guard)) return;
3211
- const nested = new Set(active);
3212
- nested.add(guard);
3260
+ const nested = /* @__PURE__ */ new Set([...active, guard]);
3213
3261
  for (let layer = fromLayer; layer < layers.length; layer++) {
3214
3262
  const settings = layers[layer];
3215
3263
  if (settings == null || !(name in settings)) continue;
@@ -4286,57 +4334,159 @@ function stripReferences(properties, id) {
4286
4334
  }
4287
4335
  }
4288
4336
  //#endregion
4289
- //#region src/scheme/types.ts
4337
+ //#region src/xml/types.ts
4290
4338
  /**
4291
4339
  * Whether a node is an element rather than a comment.
4292
4340
  */
4293
- function isXcschemeElement(node) {
4341
+ function isXmlElement(node) {
4294
4342
  return "name" in node;
4295
4343
  }
4344
+ /**
4345
+ * Collects elements of the given name anywhere under a root, in document
4346
+ * order, root included. Passing no name collects every element. Scheme
4347
+ * and workspace models both build their typed views over this query.
4348
+ */
4349
+ function xmlElements(root, name) {
4350
+ const found = [];
4351
+ const visit = (element) => {
4352
+ if (name == null || element.name === name) found.push(element);
4353
+ for (const child of element.children) if (isXmlElement(child)) visit(child);
4354
+ };
4355
+ visit(root);
4356
+ return found;
4357
+ }
4296
4358
  //#endregion
4297
- //#region src/scheme/build.ts
4359
+ //#region src/xml/build.ts
4298
4360
  /**
4299
- * Serializer for the `.xcscheme` XML dialect.
4361
+ * Serializer for Xcode's XML dialect, shared by scheme and workspace
4362
+ * files.
4300
4363
  *
4301
4364
  * The output reproduces Xcode's own layout byte for byte. Xcode writes
4302
4365
  * the UTF-8 declaration, indents with three spaces, puts each attribute
4303
4366
  * on its own line with spaces around the equals sign, glues the closing
4304
4367
  * angle bracket to the last attribute, and closes every element with an
4305
- * explicit close tag. Parsing an Xcode-written scheme and building it
4368
+ * explicit close tag. Parsing an Xcode-written file and building it
4306
4369
  * back therefore yields the identical file, and any other input reaches
4307
4370
  * that canonical form in one build.
4308
4371
  *
4372
+ * Each file format wraps this core with its own error type, so a caller
4373
+ * always sees the error class of the format it asked for.
4374
+ *
4309
4375
  * @module
4310
4376
  */
4311
- /** The declaration line Xcode writes at the top of every scheme file. */
4377
+ /**
4378
+ * The internal failure the renderers throw. It carries the offending
4379
+ * node instead of a path, and {@link buildXmlDocument} resolves the path
4380
+ * by searching the tree only when a failure actually happens, so the
4381
+ * happy path never pays for path bookkeeping.
4382
+ */
4383
+ var XmlBuildFailure = class extends Error {
4384
+ /** The element or comment node the failure points at. */
4385
+ node;
4386
+ constructor(message, node) {
4387
+ super(message);
4388
+ this.name = "XmlBuildFailure";
4389
+ this.node = node;
4390
+ }
4391
+ };
4392
+ /** The declaration line Xcode writes at the top of every file. */
4312
4393
  const XML_DECLARATION = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
4313
- /** One indentation step of Xcode's scheme writer. */
4394
+ /** One indentation step of Xcode's writer. */
4314
4395
  const INDENT = " ";
4315
4396
  /**
4397
+ * Indentation strings by depth, extended on demand. Documents nest a
4398
+ * handful of levels, and reusing the strings keeps the writer from
4399
+ * re-allocating the same prefixes for every node.
4400
+ */
4401
+ const INDENTS = [""];
4402
+ /**
4403
+ * The indentation prefix for a nesting depth.
4404
+ */
4405
+ function indentAt(depth) {
4406
+ for (let known = INDENTS.length; known <= depth; known++) INDENTS.push(INDENTS[known - 1] + INDENT);
4407
+ return INDENTS[depth];
4408
+ }
4409
+ /**
4316
4410
  * Matches valid XML names. A stray non-name, such as an empty string or
4317
4411
  * one carrying spaces or XML syntax, must fail rather than produce a
4318
4412
  * document no parser accepts.
4319
4413
  */
4320
4414
  const NAME_PATTERN = /^[A-Za-z_:][A-Za-z0-9_:.-]*$/u;
4321
4415
  /**
4322
- * Matches characters that cannot appear in an attribute value. XML 1.0
4323
- * has no representation for control characters other than tab, line
4324
- * feed, and carriage return.
4416
+ * Names that already passed {@link NAME_PATTERN}, capped so hostile
4417
+ * documents cannot grow the set without bound. Element and attribute
4418
+ * vocabularies repeat heavily, so nearly every check after the first is
4419
+ * a set lookup instead of a regex test.
4325
4420
  */
4326
- const UNENCODABLE_PATTERN = /[\u0000-\u0008\u000B\u000C\u000E-\u001F]/u;
4421
+ const VALID_NAMES = /* @__PURE__ */ new Set();
4327
4422
  /**
4328
- * Serializes a scheme document to the text of a `.xcscheme` file.
4329
- *
4330
- * @throws XcschemeBuildError for element or attribute names that are not
4331
- * XML names and for attribute values carrying unencodable control
4332
- * characters, with the path of the offending node.
4423
+ * Whether a name is a valid XML name, memoized across documents.
4333
4424
  */
4334
- function buildXcscheme(document) {
4335
- let output = XML_DECLARATION;
4336
- for (const comment of document.leading) output += `<!--${comment.comment}-->\n`;
4337
- output += renderElement(document.root, 0, document.root.name);
4338
- for (const comment of document.trailing) output += `<!--${comment.comment}-->\n`;
4339
- return output;
4425
+ function isValidName(name) {
4426
+ if (VALID_NAMES.has(name)) return true;
4427
+ if (!NAME_PATTERN.test(name)) return false;
4428
+ if (VALID_NAMES.size < 512) VALID_NAMES.add(name);
4429
+ return true;
4430
+ }
4431
+ /**
4432
+ * Serializes a document to text in Xcode's canonical layout, reporting
4433
+ * failures through the given error factory.
4434
+ */
4435
+ function buildXmlDocument(document, makeError) {
4436
+ try {
4437
+ let output = XML_DECLARATION;
4438
+ for (const comment of document.leading) output += renderComment(comment, 0);
4439
+ output += renderElement(document.root, 0);
4440
+ for (const comment of document.trailing) output += renderComment(comment, 0);
4441
+ return output;
4442
+ } catch (error) {
4443
+ if (error instanceof XmlBuildFailure) throw makeError(error.message, pathOf(document, error.node));
4444
+ throw error;
4445
+ }
4446
+ }
4447
+ /**
4448
+ * Resolves the path of a node for an error message, in the
4449
+ * `Scheme.BuildAction[0]` form, by walking the tree. This runs only when
4450
+ * a build actually fails.
4451
+ */
4452
+ function pathOf(document, node) {
4453
+ if (node == null || document.leading.includes(node) || document.trailing.includes(node)) return "document";
4454
+ const search = (element, path) => {
4455
+ if (element === node) return path;
4456
+ const seen = /* @__PURE__ */ new Map();
4457
+ for (const child of element.children) {
4458
+ if (!isXmlElement(child)) {
4459
+ if (child === node) return path;
4460
+ continue;
4461
+ }
4462
+ const index = seen.get(child.name) ?? 0;
4463
+ seen.set(child.name, index + 1);
4464
+ const found = search(child, `${path}.${child.name}[${index}]`);
4465
+ if (found != null) return found;
4466
+ }
4467
+ };
4468
+ return search(document.root, document.root.name) ?? document.root.name;
4469
+ }
4470
+ /**
4471
+ * Matches the characters no XML document can carry, in any context. The
4472
+ * alternatives are the control characters XML cannot represent,
4473
+ * unpaired surrogate halves, and the two noncharacters at the end of
4474
+ * the basic plane. Comments validate against this directly, since
4475
+ * comment text has no escapes to fall back on.
4476
+ */
4477
+ const UNCARRIABLE_PATTERN$1 = /[\u0000-\u0008\u000B\u000C\u000E-\u001F]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]|[\uFFFE\uFFFF]/u;
4478
+ /**
4479
+ * Renders one comment, failing on text the comment grammar cannot hold.
4480
+ * A `--` inside the text or a `-` against the closing marker would
4481
+ * reparse at a different terminator, and characters outside XML's
4482
+ * character set have no escaped form inside a comment, so emitting
4483
+ * either would corrupt the document.
4484
+ */
4485
+ function renderComment(node, depth) {
4486
+ const comment = node.comment;
4487
+ if (comment.includes("--") || comment.endsWith("-")) throw new XmlBuildFailure("Comments cannot contain -- or end with -", node);
4488
+ if (UNCARRIABLE_PATTERN$1.test(comment)) throw new XmlBuildFailure("Comments cannot contain characters XML cannot carry", node);
4489
+ return `${indentAt(depth)}<!--${comment}-->\n`;
4340
4490
  }
4341
4491
  /**
4342
4492
  * Renders one element with Xcode's layout. Attributes go each on their
@@ -4344,67 +4494,109 @@ function buildXcscheme(document) {
4344
4494
  * attribute, children indent one step, and the close tag is always
4345
4495
  * explicit.
4346
4496
  */
4347
- function renderElement(element, depth, path) {
4348
- if (!NAME_PATTERN.test(element.name)) throw new XcschemeBuildError(`Element name ${JSON.stringify(element.name)} is not a valid XML name`, path);
4349
- const indent = INDENT.repeat(depth);
4497
+ function renderElement(element, depth) {
4498
+ if (!isValidName(element.name)) throw new XmlBuildFailure(`Element name ${JSON.stringify(element.name)} is not a valid XML name`, element);
4499
+ const indent = indentAt(depth);
4350
4500
  const names = Object.keys(element.attributes);
4351
4501
  let output;
4352
4502
  if (names.length === 0) output = `${indent}<${element.name}>\n`;
4353
4503
  else {
4354
4504
  output = `${indent}<${element.name}\n`;
4355
- const attributeIndent = indent + INDENT;
4505
+ const attributeIndent = indentAt(depth + 1);
4356
4506
  for (let i = 0; i < names.length; i++) {
4357
4507
  const name = names[i];
4358
- if (!NAME_PATTERN.test(name)) throw new XcschemeBuildError(`Attribute name ${JSON.stringify(name)} is not a valid XML name`, path);
4359
- const value = escapeAttribute(element.attributes[name], path, name);
4508
+ if (!isValidName(name)) throw new XmlBuildFailure(`Attribute name ${JSON.stringify(name)} is not a valid XML name`, element);
4509
+ const value = escapeAttribute(element.attributes[name], element, name);
4360
4510
  const terminator = i === names.length - 1 ? ">" : "";
4361
4511
  output += `${attributeIndent}${name} = "${value}"${terminator}\n`;
4362
4512
  }
4363
4513
  }
4364
- output += renderChildren(element.children, depth + 1, path);
4514
+ const children = element.children;
4515
+ const childDepth = depth + 1;
4516
+ for (const child of children) output += isXmlElement(child) ? renderElement(child, childDepth) : renderComment(child, childDepth);
4365
4517
  output += `${indent}</${element.name}>\n`;
4366
4518
  return output;
4367
4519
  }
4520
+ const CODE_TAB$1 = 9;
4521
+ const CODE_LINE_FEED$1 = 10;
4522
+ const CODE_CARRIAGE_RETURN$1 = 13;
4523
+ const CODE_QUOTE$1 = 34;
4524
+ const CODE_AMPERSAND$1 = 38;
4525
+ const CODE_APOSTROPHE$1 = 39;
4526
+ const CODE_LESS_THAN$1 = 60;
4527
+ const CODE_GREATER_THAN$1 = 62;
4368
4528
  /**
4369
- * Renders an element's children in document order, numbering repeated
4370
- * element names in the error path so a failure points at one node.
4371
- */
4372
- function renderChildren(children, depth, path) {
4373
- let output = "";
4374
- const seen = /* @__PURE__ */ new Map();
4375
- for (const child of children) if (isXcschemeElement(child)) {
4376
- const index = seen.get(child.name) ?? 0;
4377
- seen.set(child.name, index + 1);
4378
- output += renderElement(child, depth, `${path}.${child.name}[${index}]`);
4379
- } else output += `${INDENT.repeat(depth)}<!--${child.comment}-->\n`;
4380
- return output;
4381
- }
4529
+ * Matches every code unit the writer must escape, validate, or reject.
4530
+ * Nearly all attribute values contain none of them, and the single
4531
+ * regex test is the cheapest full-string scan the engine offers, so a
4532
+ * miss returns the value with no further work.
4533
+ */
4534
+ const NEEDS_WORK_PATTERN = /[\u0000-\u001F&<>"'\uD800-\uDFFF\uFFFE\uFFFF]/u;
4382
4535
  /**
4383
4536
  * Escapes an attribute value the way Xcode's writer does. XML syntax
4384
4537
  * characters become the five named entities, and tab, line feed, and
4385
4538
  * carriage return become character references so they survive
4386
4539
  * attribute-value normalization on the next parse.
4387
- */
4388
- function escapeAttribute(value, path, attributeName) {
4389
- const unencodable = UNENCODABLE_PATTERN.exec(value);
4390
- if (unencodable != null) throw new XcschemeBuildError(`Attribute ${attributeName} contains the control character U+${unencodable[0].charCodeAt(0).toString(16).padStart(4, "0").toUpperCase()}, which XML cannot encode`, path);
4540
+ *
4541
+ * The common value with nothing to escape returns as-is after one regex
4542
+ * scan. Only values carrying an interesting code unit take the
4543
+ * classifying pass, which escapes what has an escape and rejects what
4544
+ * no XML document can carry, meaning the control characters XML cannot
4545
+ * represent, unpaired surrogate halves, and the two noncharacters at
4546
+ * the end of the basic plane.
4547
+ */
4548
+ function escapeAttribute(value, element, attributeName) {
4549
+ if (!NEEDS_WORK_PATTERN.test(value)) return value;
4550
+ let needsEscaping = false;
4551
+ for (let i = 0; i < value.length; i++) {
4552
+ const code = value.charCodeAt(i);
4553
+ if (code < 32) {
4554
+ if (code === CODE_TAB$1 || code === CODE_LINE_FEED$1 || code === CODE_CARRIAGE_RETURN$1) {
4555
+ needsEscaping = true;
4556
+ continue;
4557
+ }
4558
+ throw new XmlBuildFailure(`Attribute ${attributeName} contains the control character U+${code.toString(16).padStart(4, "0").toUpperCase()}, which XML cannot encode`, element);
4559
+ }
4560
+ if (code === CODE_AMPERSAND$1 || code === CODE_LESS_THAN$1 || code === CODE_GREATER_THAN$1 || code === CODE_QUOTE$1 || code === CODE_APOSTROPHE$1) {
4561
+ needsEscaping = true;
4562
+ continue;
4563
+ }
4564
+ if (code >= 55296) {
4565
+ if (code <= 56319) {
4566
+ const next = value.charCodeAt(i + 1);
4567
+ if (next >= 56320 && next <= 57343) {
4568
+ i++;
4569
+ continue;
4570
+ }
4571
+ }
4572
+ if (code <= 57343 || code === 65534 || code === 65535) throw new XmlBuildFailure(`Attribute ${attributeName} contains a code point XML cannot carry (U+${code.toString(16).padStart(4, "0").toUpperCase()})`, element);
4573
+ }
4574
+ }
4575
+ if (!needsEscaping) return value;
4391
4576
  return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\"", "&quot;").replaceAll("'", "&apos;").replaceAll(" ", "&#9;").replaceAll("\n", "&#10;").replaceAll("\r", "&#13;");
4392
4577
  }
4393
4578
  //#endregion
4394
- //#region src/scheme/parse.ts
4579
+ //#region src/scheme/build.ts
4395
4580
  /**
4396
- * Parser for the `.xcscheme` XML dialect.
4397
- *
4398
- * Scheme files are XML with a narrow shape. Elements carry attributes and
4399
- * child elements, and there is no text content, no namespace, and no
4400
- * DOCTYPE. The parser accepts that shape from any writer, since attribute
4401
- * order, quoting style, and whitespace vary across tools. Character and
4402
- * entity references in attribute values resolve to their characters, and
4403
- * comments are preserved. Anything outside the shape fails loudly with a
4404
- * position, in line with the pbxproj parser.
4581
+ * Serializer entry point for the `.xcscheme` dialect. The layout rules
4582
+ * live in the shared XML core, and this wrapper binds them to the scheme
4583
+ * error type.
4405
4584
  *
4406
4585
  * @module
4407
4586
  */
4587
+ /**
4588
+ * Serializes a scheme document to the text of a `.xcscheme` file in
4589
+ * Xcode's canonical layout.
4590
+ *
4591
+ * @throws XcschemeBuildError for element or attribute names that are not
4592
+ * XML names and for attribute values carrying unencodable control
4593
+ * characters, with the path of the offending node.
4594
+ */
4595
+ function buildXcscheme(document) {
4596
+ return buildXmlDocument(document, (message, path) => new XcschemeBuildError(message, path));
4597
+ }
4598
+ //#endregion
4599
+ //#region src/xml/parse.ts
4408
4600
  const CODE_TAB = 9;
4409
4601
  const CODE_LINE_FEED = 10;
4410
4602
  const CODE_CARRIAGE_RETURN = 13;
@@ -4429,7 +4621,7 @@ function isWhitespace(code) {
4429
4621
  return code === CODE_SPACE || code === CODE_TAB || code === CODE_LINE_FEED || code === CODE_CARRIAGE_RETURN;
4430
4622
  }
4431
4623
  /**
4432
- * Whether a code unit can start an XML name. The scheme vocabulary is
4624
+ * Whether a code unit can start an XML name. The dialect's vocabulary is
4433
4625
  * ASCII, so the accepted alphabet is letters, underscore, and colon.
4434
4626
  */
4435
4627
  function isNameStart(code) {
@@ -4450,25 +4642,41 @@ const NAMED_ENTITIES = {
4450
4642
  quot: "\""
4451
4643
  };
4452
4644
  /**
4453
- * Parses the text of a `.xcscheme` file into its node tree.
4454
- *
4455
- * @throws XcschemeParseError when the text is not a well-formed scheme
4456
- * document, with the line and column of the failure.
4645
+ * Matches the characters no XML document can carry, mirroring the
4646
+ * writer's validation so a comment the parser accepts is one the
4647
+ * serializer reproduces.
4457
4648
  */
4458
- function parseXcscheme(text) {
4459
- return new Parser(text).parseDocument();
4649
+ const UNCARRIABLE_PATTERN = /[\u0000-\u0008\u000B\u000C\u000E-\u001F]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]|[\uFFFE\uFFFF]/u;
4650
+ /**
4651
+ * Whether a code point is a character XML 1.0 allows in a document.
4652
+ * The excluded ranges are the control characters other than tab, line
4653
+ * feed, and carriage return, the surrogate halves, and the two
4654
+ * noncharacters at the end of the basic plane.
4655
+ */
4656
+ function isXmlChar(codePoint) {
4657
+ return codePoint === CODE_TAB || codePoint === CODE_LINE_FEED || codePoint === CODE_CARRIAGE_RETURN || codePoint >= 32 && codePoint <= 55295 || codePoint >= 57344 && codePoint <= 65533 || codePoint >= 65536 && codePoint <= 1114111;
4658
+ }
4659
+ /**
4660
+ * Parses the text of a document in the dialect into its node tree,
4661
+ * reporting failures through the given error factory.
4662
+ */
4663
+ function parseXmlDocument(text, makeError) {
4664
+ return new Parser(text, makeError).parseDocument();
4460
4665
  }
4461
4666
  /**
4462
4667
  * Single-pass recursive-descent parser over the source text. One instance
4463
4668
  * parses one document and is discarded.
4464
4669
  */
4465
4670
  var Parser = class {
4466
- /** The full source text of the scheme file. */
4671
+ /** The full source text of the file. */
4467
4672
  input;
4673
+ /** Constructs the format's parse error for a failure. */
4674
+ makeError;
4468
4675
  /** Cursor into {@link input}, in UTF-16 code units. */
4469
4676
  pos = 0;
4470
- constructor(input) {
4677
+ constructor(input, makeError) {
4471
4678
  this.input = input;
4679
+ this.makeError = makeError;
4472
4680
  if (input.charCodeAt(0) === CODE_BOM) this.pos = 1;
4473
4681
  }
4474
4682
  /**
@@ -4502,10 +4710,14 @@ var Parser = class {
4502
4710
  /**
4503
4711
  * Skips the `<?xml ... ?>` declaration when present. Its attributes are
4504
4712
  * not retained, since the writer always emits the canonical UTF-8
4505
- * declaration.
4713
+ * declaration. Other processing instructions fail, because the dialect
4714
+ * has no place to keep them and dropping one silently would make the
4715
+ * round-trip lossy.
4506
4716
  */
4507
4717
  skipDeclaration() {
4508
4718
  if (this.input.charCodeAt(this.pos) !== CODE_LESS_THAN || this.input.charCodeAt(this.pos + 1) !== CODE_QUESTION) return;
4719
+ const after = this.input.charCodeAt(this.pos + 5);
4720
+ if (this.input.slice(this.pos + 2, this.pos + 5) !== "xml" || !isWhitespace(after) && after !== CODE_QUESTION) this.fail("Unsupported processing instruction");
4509
4721
  const end = this.input.indexOf("?>", this.pos + 2);
4510
4722
  if (end === -1) this.fail("Unterminated XML declaration");
4511
4723
  this.pos = end + 2;
@@ -4577,12 +4789,17 @@ var Parser = class {
4577
4789
  }
4578
4790
  /**
4579
4791
  * Parses one comment with the cursor on its `<!--` opener. The text
4580
- * between the markers is kept verbatim.
4792
+ * between the markers is kept verbatim. A `--` inside the text or a
4793
+ * `-` against the closing marker fails the way XML requires, which
4794
+ * also keeps every accepted comment rebuildable, since such text would
4795
+ * reparse at a different terminator.
4581
4796
  */
4582
4797
  parseComment() {
4583
4798
  const end = this.input.indexOf("-->", this.pos + 4);
4584
4799
  if (end === -1) this.fail("Unterminated comment");
4585
4800
  const comment = this.input.slice(this.pos + 4, end);
4801
+ if (comment.includes("--") || comment.endsWith("-")) this.fail("Comments cannot contain -- or end with -");
4802
+ if (UNCARRIABLE_PATTERN.test(comment)) this.fail("Comments cannot contain characters XML cannot carry");
4586
4803
  this.pos = end + 3;
4587
4804
  return { comment };
4588
4805
  }
@@ -4622,14 +4839,37 @@ var Parser = class {
4622
4839
  value += this.input.slice(runStart, this.pos);
4623
4840
  value += this.parseReference();
4624
4841
  runStart = this.pos;
4625
- } else this.pos++;
4842
+ continue;
4843
+ }
4844
+ if (code < 32 && !isWhitespace(code)) this.fail("Attribute values cannot contain a raw control character");
4845
+ if (code >= 55296) {
4846
+ this.validateUpperCharacter(code);
4847
+ this.pos += code <= 56319 ? 2 : 1;
4848
+ continue;
4849
+ }
4850
+ this.pos++;
4626
4851
  }
4627
4852
  }
4628
4853
  /**
4854
+ * Validates a code unit in the surrogate or upper basic-plane range at
4855
+ * the cursor. A high surrogate must pair with a low one, a bare low
4856
+ * surrogate is not a character, and the two noncharacters at the end
4857
+ * of the plane have no XML representation.
4858
+ */
4859
+ validateUpperCharacter(code) {
4860
+ if (code <= 56319) {
4861
+ const next = this.input.charCodeAt(this.pos + 1);
4862
+ if (Number.isNaN(next) || next < 56320 || next > 57343) this.fail("Attribute values cannot contain an unpaired surrogate");
4863
+ return;
4864
+ }
4865
+ if (code <= 57343) this.fail("Attribute values cannot contain an unpaired surrogate");
4866
+ if (code === 65534 || code === 65535) this.fail("Attribute values cannot contain a noncharacter");
4867
+ }
4868
+ /**
4629
4869
  * Resolves one `&...;` reference with the cursor on the ampersand. The
4630
4870
  * accepted forms are the five XML named entities and decimal or hex
4631
4871
  * character references, which covers everything observed in
4632
- * Xcode-written schemes (`&quot;`, `&amp;`, `&apos;`, `&lt;`, `&gt;`,
4872
+ * Xcode-written files (`&quot;`, `&amp;`, `&apos;`, `&lt;`, `&gt;`,
4633
4873
  * and `&#10;`-style whitespace).
4634
4874
  */
4635
4875
  parseReference() {
@@ -4641,9 +4881,10 @@ var Parser = class {
4641
4881
  if (body.charCodeAt(0) === CODE_HASH) {
4642
4882
  const isHex = body.charCodeAt(1) === 120 || body.charCodeAt(1) === 88;
4643
4883
  const digits = body.slice(isHex ? 2 : 1);
4884
+ if (!(isHex ? /^[0-9A-Fa-f]+$/u : /^[0-9]+$/u).test(digits)) this.failAt(`Invalid character reference &${body};`, start);
4644
4885
  const radix = isHex ? 16 : 10;
4645
4886
  const codePoint = Number.parseInt(digits, radix);
4646
- if (digits.length === 0 || Number.isNaN(codePoint) || codePoint > 1114111) this.failAt(`Invalid character reference &${body};`, start);
4887
+ if (!isXmlChar(codePoint)) this.failAt(`Character reference &${body}; is not an XML character`, start);
4647
4888
  return String.fromCodePoint(codePoint);
4648
4889
  }
4649
4890
  const named = Object.hasOwn(NAMED_ENTITIES, body) ? NAMED_ENTITIES[body] : void 0;
@@ -4670,10 +4911,28 @@ var Parser = class {
4670
4911
  * uses to point at the start of a bad reference rather than its end.
4671
4912
  */
4672
4913
  failAt(message, offset) {
4673
- throw new XcschemeParseError(message, this.input, offset);
4914
+ throw this.makeError(message, this.input, offset);
4674
4915
  }
4675
4916
  };
4676
4917
  //#endregion
4918
+ //#region src/scheme/parse.ts
4919
+ /**
4920
+ * Parser entry point for the `.xcscheme` dialect. The grammar lives in
4921
+ * the shared XML core, and this wrapper binds it to the scheme error
4922
+ * type.
4923
+ *
4924
+ * @module
4925
+ */
4926
+ /**
4927
+ * Parses the text of a `.xcscheme` file into its node tree.
4928
+ *
4929
+ * @throws XcschemeParseError when the text is not a well-formed scheme
4930
+ * document, with the line and column of the failure.
4931
+ */
4932
+ function parseXcscheme(text) {
4933
+ return parseXmlDocument(text, (message, source, offset) => new XcschemeParseError(message, source, offset));
4934
+ }
4935
+ //#endregion
4677
4936
  //#region src/scheme/model.ts
4678
4937
  /**
4679
4938
  * The scheme object model and its helpers.
@@ -4694,13 +4953,7 @@ var Parser = class {
4694
4953
  * element.
4695
4954
  */
4696
4955
  function xcschemeElements(root, name) {
4697
- const found = [];
4698
- const visit = (element) => {
4699
- if (name == null || element.name === name) found.push(element);
4700
- for (const child of element.children) if (isXcschemeElement(child)) visit(child);
4701
- };
4702
- visit(root);
4703
- return found;
4956
+ return xmlElements(root, name);
4704
4957
  }
4705
4958
  /**
4706
4959
  * A `BuildableReference` element with property-style attribute access.
@@ -4970,6 +5223,273 @@ function createXcscheme(options) {
4970
5223
  };
4971
5224
  }
4972
5225
  //#endregion
5226
+ //#region src/scheme/types.ts
5227
+ /**
5228
+ * The node model of a scheme document. Scheme files share Xcode's XML
5229
+ * dialect with workspace data files, so the shapes here are the shared
5230
+ * XML node types under their scheme names.
5231
+ *
5232
+ * A parsed `.xcscheme` is a tree of plain objects. Elements carry ordered
5233
+ * attributes and child nodes, and comments survive as their own nodes.
5234
+ * All state lives in this tree. There is no wrapper to keep in sync, so
5235
+ * callers mutate nodes directly and serialize whatever the tree currently
5236
+ * says.
5237
+ *
5238
+ * @module
5239
+ */
5240
+ /**
5241
+ * Whether a node is an element rather than a comment.
5242
+ */
5243
+ function isXcschemeElement(node) {
5244
+ return isXmlElement(node);
5245
+ }
5246
+ //#endregion
5247
+ //#region src/workspace/build.ts
5248
+ /**
5249
+ * Serializer entry point for the `contents.xcworkspacedata` dialect. The
5250
+ * layout rules live in the shared XML core, and this wrapper binds them
5251
+ * to the workspace error type.
5252
+ *
5253
+ * @module
5254
+ */
5255
+ /**
5256
+ * Serializes a workspace document to the text of a
5257
+ * `contents.xcworkspacedata` file in Xcode's canonical layout.
5258
+ *
5259
+ * @throws XcworkspaceBuildError for element or attribute names that are
5260
+ * not XML names and for attribute values carrying unencodable control
5261
+ * characters, with the path of the offending node.
5262
+ */
5263
+ function buildXcworkspace(document) {
5264
+ return buildXmlDocument(document, (message, path) => new XcworkspaceBuildError(message, path));
5265
+ }
5266
+ //#endregion
5267
+ //#region src/workspace/parse.ts
5268
+ /**
5269
+ * Parser entry point for the `contents.xcworkspacedata` dialect. The
5270
+ * grammar lives in the shared XML core, and this wrapper binds it to the
5271
+ * workspace error type.
5272
+ *
5273
+ * @module
5274
+ */
5275
+ /**
5276
+ * Parses the text of a `contents.xcworkspacedata` file into its node
5277
+ * tree.
5278
+ *
5279
+ * @throws XcworkspaceParseError when the text is not a well-formed
5280
+ * workspace document, with the line and column of the failure.
5281
+ */
5282
+ function parseXcworkspace(text) {
5283
+ return parseXmlDocument(text, (message, source, offset) => new XcworkspaceParseError(message, source, offset));
5284
+ }
5285
+ //#endregion
5286
+ //#region src/workspace/model.ts
5287
+ /**
5288
+ * The workspace object model.
5289
+ *
5290
+ * A `.xcworkspace` directory carries a `contents.xcworkspacedata` file
5291
+ * listing the projects and folders the workspace shows, in the same XML
5292
+ * dialect scheme files use. {@link Xcworkspace} wraps the parsed
5293
+ * document with typed access to the file references, so tooling resolves
5294
+ * which projects a workspace opens instead of globbing the directory
5295
+ * tree. The node tree stays the single source of truth. Views hold only
5296
+ * a reference into it, so model calls and direct tree edits compose
5297
+ * freely.
5298
+ *
5299
+ * @module
5300
+ */
5301
+ /**
5302
+ * Splits a location attribute into its kind and path. Xcode writes the
5303
+ * kinds `group` (relative to the enclosing group), `container` (relative
5304
+ * to the directory containing the `.xcworkspace`), `absolute`, `self`
5305
+ * (the containing `.xcodeproj` itself), and `developer` (inside the
5306
+ * developer directory).
5307
+ */
5308
+ function parseWorkspaceLocation(location) {
5309
+ const colon = location.indexOf(":");
5310
+ if (colon === -1) return {
5311
+ kind: "group",
5312
+ path: location
5313
+ };
5314
+ return {
5315
+ kind: location.slice(0, colon),
5316
+ path: location.slice(colon + 1)
5317
+ };
5318
+ }
5319
+ /**
5320
+ * A `FileRef` element with property-style attribute access. File
5321
+ * references are the elements workspace edits touch, since each one
5322
+ * names a project or folder the workspace shows. The view reads and
5323
+ * writes the element's attributes directly, so it never goes stale and
5324
+ * needs no separate save step.
5325
+ */
5326
+ var WorkspaceFileRef = class {
5327
+ /** The underlying element inside the document tree. */
5328
+ element;
5329
+ constructor(element) {
5330
+ this.element = element;
5331
+ }
5332
+ /**
5333
+ * The reference's location attribute, when present, for example
5334
+ * `group:Pods/Pods.xcodeproj`.
5335
+ */
5336
+ get location() {
5337
+ return this.element.attributes["location"];
5338
+ }
5339
+ set location(value) {
5340
+ this.element.attributes["location"] = value;
5341
+ }
5342
+ };
5343
+ /**
5344
+ * A workspace document with typed access to the elements editing flows
5345
+ * touch.
5346
+ *
5347
+ * The model is a thin layer over the node tree. All state lives in the
5348
+ * document itself, and {@link build} serializes whatever the tree
5349
+ * currently says, so typed edits and direct tree edits compose freely.
5350
+ *
5351
+ * ```ts
5352
+ * const workspace = Xcworkspace.parse(xcworkspacedataText);
5353
+ * workspace.projectFilePaths(); // ["DemoApp.xcodeproj", "Pods/Pods.xcodeproj"]
5354
+ * ```
5355
+ */
5356
+ var Xcworkspace = class Xcworkspace {
5357
+ /** The underlying parsed document. */
5358
+ document;
5359
+ constructor(document) {
5360
+ this.document = document;
5361
+ }
5362
+ /**
5363
+ * Parses the text of a `contents.xcworkspacedata` file into a
5364
+ * workspace model.
5365
+ *
5366
+ * @throws XcworkspaceParseError when the text is not a well-formed
5367
+ * workspace document, with the line and column of the failure.
5368
+ */
5369
+ static parse(text) {
5370
+ return new Xcworkspace(parseXcworkspace(text));
5371
+ }
5372
+ /**
5373
+ * Creates the workspace document Xcode writes, listing the given
5374
+ * locations as file references.
5375
+ */
5376
+ static create(options) {
5377
+ const children = (options?.locations ?? []).map((location) => ({
5378
+ name: "FileRef",
5379
+ attributes: { location },
5380
+ children: []
5381
+ }));
5382
+ return new Xcworkspace({
5383
+ leading: [],
5384
+ root: {
5385
+ name: "Workspace",
5386
+ attributes: { version: "1.0" },
5387
+ children
5388
+ },
5389
+ trailing: []
5390
+ });
5391
+ }
5392
+ /**
5393
+ * The document's `Workspace` element.
5394
+ */
5395
+ get root() {
5396
+ return this.document.root;
5397
+ }
5398
+ /**
5399
+ * Serializes the workspace to the text of a `contents.xcworkspacedata`
5400
+ * file in Xcode's canonical layout.
5401
+ */
5402
+ build() {
5403
+ return buildXcworkspace(this.document);
5404
+ }
5405
+ /**
5406
+ * Collects elements of the given name anywhere in the document, in
5407
+ * document order. Passing no name collects every element.
5408
+ */
5409
+ elements(name) {
5410
+ return xmlElements(this.document.root, name);
5411
+ }
5412
+ /**
5413
+ * The views of every file reference in the document, in document
5414
+ * order, references nested inside groups included.
5415
+ */
5416
+ fileRefs() {
5417
+ return this.elements("FileRef").map((element) => new WorkspaceFileRef(element));
5418
+ }
5419
+ /**
5420
+ * Appends a file reference to the workspace's top level and returns
5421
+ * its view.
5422
+ */
5423
+ addFileRef(location) {
5424
+ const element = {
5425
+ name: "FileRef",
5426
+ attributes: { location },
5427
+ children: []
5428
+ };
5429
+ this.root.children.push(element);
5430
+ return new WorkspaceFileRef(element);
5431
+ }
5432
+ /**
5433
+ * Removes a file reference from whichever element holds it. Returns
5434
+ * whether the reference was found and removed.
5435
+ */
5436
+ removeFileRef(reference) {
5437
+ for (const parent of this.elements()) {
5438
+ const index = parent.children.indexOf(reference.element);
5439
+ if (index !== -1) {
5440
+ parent.children.splice(index, 1);
5441
+ return true;
5442
+ }
5443
+ }
5444
+ return false;
5445
+ }
5446
+ /**
5447
+ * The paths of every `.xcodeproj` the workspace references, in
5448
+ * document order, resolved relative to the directory containing the
5449
+ * `.xcworkspace`. Group locations compose through their enclosing
5450
+ * groups, container locations anchor at the workspace's directory, and
5451
+ * absolute locations pass through unchanged.
5452
+ *
5453
+ * The resolution is textual. The library never touches the
5454
+ * filesystem, so locations that only the running Xcode can resolve
5455
+ * (`self` and `developer`) are not listed.
5456
+ */
5457
+ projectFilePaths() {
5458
+ const paths = [];
5459
+ const visit = (element, base) => {
5460
+ for (const child of element.children) {
5461
+ if (!isXmlElement(child)) continue;
5462
+ const resolved = resolveLocationPath(parseWorkspaceLocation(child.attributes["location"] ?? ""), base);
5463
+ if (child.name === "Group") visit(child, resolved ?? base);
5464
+ else if (child.name === "FileRef" && resolved != null && resolved.endsWith(".xcodeproj")) paths.push(resolved);
5465
+ }
5466
+ };
5467
+ visit(this.document.root, "");
5468
+ return paths;
5469
+ }
5470
+ };
5471
+ /**
5472
+ * Resolves a location against the enclosing group's base path, or
5473
+ * `undefined` for the kinds only a running Xcode can resolve. The empty
5474
+ * string names the workspace's own directory.
5475
+ */
5476
+ function resolveLocationPath(location, base) {
5477
+ switch (location.kind) {
5478
+ case "group": return joinPaths(base, location.path);
5479
+ case "container": return location.path;
5480
+ case "absolute": return location.path;
5481
+ default: return;
5482
+ }
5483
+ }
5484
+ /**
5485
+ * Joins two textual path segments, keeping the result free of empty
5486
+ * segments when either side is empty.
5487
+ */
5488
+ function joinPaths(base, path) {
5489
+ if (base === "" || path === "") return base === "" ? path : base;
5490
+ return `${base}/${path}`;
5491
+ }
5492
+ //#endregion
4973
5493
  //#region src/xcconfig/build.ts
4974
5494
  /**
4975
5495
  * Serializes a document back to `.xcconfig` text.
@@ -5294,4 +5814,4 @@ var Xcconfig = class Xcconfig {
5294
5814
  }
5295
5815
  };
5296
5816
  //#endregion
5297
- export { AggregateTarget, AppleScriptBuildPhase, BuildConfiguration, BuildFile, BuildFileExceptionSet, BuildPhase, BuildPhaseMembershipExceptionSet, BuildRule, BuildStyle, BuildableReference, ConfigurationList, ContainerItemProxy, CopyFilesBuildPhase, CopyFilesDestination, ExceptionSet, FileReference, FrameworksBuildPhase, Group, HeadersBuildPhase, Isa, LegacyTarget, LocalSwiftPackageReference, NativeTarget, PbxprojBuildError, PbxprojParseError, ProductType, ReferenceProxy, RemoteSwiftPackageReference, ResourcesBuildPhase, RezBuildPhase, RootProject, ShellScriptBuildPhase, SourcesBuildPhase, SwiftPackageProductDependency, SwiftPackageReference, SyncRootGroup, Target, TargetDependency, VariantGroup, VersionGroup, Xcconfig, XcconfigParseError, XcodeModelError, XcodeObject, XcodeProject, Xcscheme, XcschemeBuildError, XcschemeParseError, buildPbxproj, buildXcconfig, buildXcscheme, createXcscheme, expandBuildSettingReferences, generateObjectId, isXcschemeElement, parseApplePlatform, parsePbxproj, parseXcconfig, parseXcscheme, xcschemeElements };
5817
+ export { AggregateTarget, AppleScriptBuildPhase, BuildConfiguration, BuildFile, BuildFileExceptionSet, BuildPhase, BuildPhaseMembershipExceptionSet, BuildRule, BuildStyle, BuildableReference, ConfigurationList, ContainerItemProxy, CopyFilesBuildPhase, CopyFilesDestination, ExceptionSet, FileReference, FrameworksBuildPhase, Group, HeadersBuildPhase, Isa, LegacyTarget, LocalSwiftPackageReference, NativeTarget, PbxprojBuildError, PbxprojParseError, ProductType, ReferenceProxy, RemoteSwiftPackageReference, ResourcesBuildPhase, RezBuildPhase, RootProject, ShellScriptBuildPhase, SourcesBuildPhase, SwiftPackageProductDependency, SwiftPackageReference, SyncRootGroup, Target, TargetDependency, VariantGroup, VersionGroup, WorkspaceFileRef, Xcconfig, XcconfigParseError, XcodeModelError, XcodeObject, XcodeProject, Xcscheme, XcschemeBuildError, XcschemeParseError, Xcworkspace, XcworkspaceBuildError, XcworkspaceParseError, buildPbxproj, buildXcconfig, buildXcscheme, buildXcworkspace, createXcscheme, expandBuildSettingReferences, generateObjectId, isXcschemeElement, isXmlElement, parseApplePlatform, parsePbxproj, parseWorkspaceLocation, parseXcconfig, parseXcscheme, parseXcworkspace, xcschemeElements, xmlElements };