rork-xcode 0.3.0 → 0.4.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/README.md CHANGED
@@ -25,11 +25,11 @@ const text = buildPbxproj(project); // byte-stable, Xcode-canonical layout
25
25
 
26
26
  `rork-xcode` is designed for exactly that situation:
27
27
 
28
- - **Zero dependencies.** The pbxproj grammar is a small OpenStep-style property list dialect: dictionaries, arrays, strings, and hex data runs. A dedicated scanner covers it completely, with no general-purpose parser stack, no native addon, and no WASM blob.
28
+ - **Zero dependencies.** The pbxproj grammar is a small OpenStep-style property list dialect of dictionaries, arrays, strings, and hex data runs. A dedicated scanner covers it completely, with no general-purpose parser stack, no native addon, and no WASM blob.
29
29
  - **One artifact, one code path.** A single ESM file with named exports. No environment-conditional entry points, no reliance on ambient globals like `Buffer`. What you test locally is what runs in production, whatever the bundler.
30
30
  - **Xcode-canonical output.** The serializer reproduces the layout Xcode itself writes (tab indentation, per-isa object sections in sorted order, single-line build-file entries, and derived reference comments like `13B07F86… /* AppDelegate.swift in Sources */`), so diffs against Xcode-saved projects stay minimal and Xcode does not rewrite the file on next save.
31
31
  - **Round-trip faithful.** Parse → build is byte-identical for Xcode-canonical documents and a fixed point for everything else. Lexical subtleties that plain number conversion would destroy (leading-zero values like `0755`, trailing-zero versions like `5.0`, digit runs longer than the double-precision safe range) are preserved as strings by design.
32
- - **Loud failure modes.** Malformed documents fail with a typed error carrying line and column; unrepresentable values (`null`, booleans, non-finite numbers) fail with the exact path of the offending value. Nothing is silently dropped.
32
+ - **Loud failure modes.** Malformed documents fail with a typed error carrying line and column, and unrepresentable values (`null`, booleans, non-finite numbers) fail with the exact path of the offending value. Nothing is silently dropped.
33
33
 
34
34
  ## Install
35
35
 
@@ -222,45 +222,48 @@ for (const [id, object] of project.objects()) {
222
222
 
223
223
  ### Semantics
224
224
 
225
- - **Typed vocabulary, generic fallback.** The typed views cover targets of every kind, groups and variant groups, Xcode 16 synchronized folders and their exception sets, build phases and build rules, Core Data version groups, and cross-project reference proxies. Every other kind is a generic `XcodeObject` with the same read and write access, so nothing in a document is out of reach.
225
+ - **Typed vocabulary, generic fallback.** The typed views cover targets of every kind, groups and variant groups, Xcode 16 synchronized folders and their exception sets, build phases and build rules, build configurations, file references, container item proxies, Core Data version groups, and cross-project reference proxies. Every other kind is a generic `XcodeObject` with the same read and write access, so nothing in a document is out of reach.
226
+ - **`is()` narrowing.** Every view class carries a static type guard for discriminating mixed objects: `if (NativeTarget.is(object))` narrows the way `instanceof` does, subclasses included. Build configurations additionally expose their settings as a live typed dictionary through `configuration.buildSettings`.
226
227
  - **Typed, open property shapes.** Known keys autocomplete (`target.properties.productType`) and the shape stays open, so keys like `INFOPLIST_KEY_*` settings remain first-class. The shapes describe well-formed documents. When reading untrusted input, use the narrowing accessors, which never trust them.
227
- - **Two verb families.** `add*` wires something to its owner (a dependency, a package, a framework, a synchronized folder) and is idempotent: re-adding returns the existing wiring. `ensure*` returns a structural container, creating it when missing (a build phase, a group chain, the Products group). Both families can therefore run unconditionally in scaffold and repair flows.
228
+ - **Two verb families.** `add*` wires something to its owner (a dependency, a package, a framework, a synchronized folder) and is idempotent, so re-adding returns the existing wiring. `ensure*` returns a structural container, creating it when missing (a build phase, a group chain, the Products group). Both families can therefore run unconditionally in scaffold and repair flows.
228
229
  - **Deterministic identifiers.** New objects get ids derived from what they are (`XX` + 20 digest characters + `XX`, from an embedded hash), so programmatic edits are reproducible run to run and diffs stay minimal. Collisions within a document resolve deterministically, and identical edit sequences produce byte-identical documents.
229
230
  - **Soft reads, loud writes.** Real-world projects can be malformed, so lookups return `undefined` where a document could omit something. Operations that cannot proceed without structure (no root project object, an unknown product type, a view whose object was deleted) throw `XcodeModelError`.
230
231
  - **Identity-mapped views.** Two lookups of the same id return the same instance, so views compare with `===`.
231
232
 
232
233
  ## Schemes
233
234
 
234
- `.xcscheme` files describe how Xcode builds, runs, tests, and archives a target. They are not property lists but a small XML dialect of their own, and `parseXcscheme` and `buildXcscheme` cover it with the same contract as the pbxproj functions: an Xcode-written scheme rebuilds byte for byte, any other input reaches Xcode's canonical layout in one build, and malformed input fails with a typed error carrying line and column.
235
+ `.xcscheme` files describe how Xcode builds, runs, tests, and archives a target. They are not property lists but a small XML dialect of their own, and the scheme module covers it with the same contract as the pbxproj functions. An Xcode-written scheme rebuilds byte for byte, any other input reaches Xcode's canonical layout in one build, and malformed input fails with a typed error carrying line and column.
236
+
237
+ `Xcscheme` is the model. Buildable references are the elements editing flows touch, and they come back as typed views:
235
238
 
236
239
  ```ts
237
- import { buildXcscheme, parseXcscheme, xcschemeElements } from "rork-xcode";
240
+ import { Xcscheme } from "rork-xcode";
238
241
 
239
- const scheme = parseXcscheme(xcschemeText);
242
+ const scheme = Xcscheme.parse(xcschemeText);
240
243
 
241
- // The tree is plain data: elements with ordered attributes and children.
242
- for (const reference of xcschemeElements(scheme.root, "BuildableReference")) {
243
- reference.attributes["BlueprintName"] = "RenamedApp";
244
- reference.attributes["BuildableName"] = "RenamedApp.app";
245
- reference.attributes["ReferencedContainer"] = "container:RenamedApp.xcodeproj";
244
+ // Rename the app while keeping each product's own shape, so a testable
245
+ // like DemoAppTests.xctest stays a test bundle.
246
+ for (const reference of scheme.buildableReferences()) {
247
+ const { blueprintName, buildableName } = reference;
248
+ if (blueprintName) reference.blueprintName = blueprintName.replace("DemoApp", "RenamedApp");
249
+ if (buildableName) reference.buildableName = buildableName.replace("DemoApp", "RenamedApp");
250
+ reference.referencedContainer = "container:RenamedApp.xcodeproj";
246
251
  }
247
252
 
248
- const text = buildXcscheme(scheme);
253
+ const text = scheme.build();
249
254
  ```
250
255
 
251
- `createXcscheme` produces the scheme Xcode's own "New Scheme" action writes for an application target, wired to the target's object id from the project document:
256
+ `Xcscheme.create` produces the scheme Xcode's own "New Scheme" action writes for an application target, wired to the target's object id from the project document:
252
257
 
253
258
  ```ts
254
- import { createXcscheme } from "rork-xcode";
255
-
256
- const scheme = createXcscheme({
259
+ const scheme = Xcscheme.create({
257
260
  appName: "DemoApp",
258
261
  blueprintIdentifier: app.id,
259
262
  });
260
- const text = buildXcscheme(scheme);
263
+ const text = scheme.build();
261
264
  ```
262
265
 
263
- Attribute order is preserved and meaningful: the writer emits attributes in insertion order, which is how byte-identical round-trips fall out. Comments are kept, attribute values resolve the character references Xcode writes (`"`, `&`, `
` and friends), and the writer re-escapes them identically.
266
+ Underneath, the document is a plain tree of elements with ordered attributes and children, reachable through `scheme.root` and `scheme.elements(name)`, so anything the typed surface does not cover stays one property away. `parseXcscheme` and `buildXcscheme` remain available for working with the tree directly. Attribute order is preserved and meaningful, which is how byte-identical round-trips fall out. Comments are kept, attribute values resolve the character references Xcode writes (`"`, `&`, `
` and friends), and the writer re-escapes them identically.
264
267
 
265
268
  ## Performance
266
269
 
@@ -283,8 +286,8 @@ Measured on an Apple M5 Max, Node.js 24, single thread, with `@bacons/xcode` 1.0
283
286
 
284
287
  ### Key performance features
285
288
 
286
- - **Single-pass scanner.** One cursor over the input string with table-driven character classification; no tokenizer stage, no intermediate token objects.
287
- - **Comments skip in bulk.** Reference comments are a sizable share of a canonical document's bytes; comment bodies are jumped with `indexOf` instead of being scanned per character.
289
+ - **Single-pass scanner.** One cursor over the input string with table-driven character classification. There is no tokenizer stage and no intermediate token objects.
290
+ - **Comments skip in bulk.** Reference comments are a sizable share of a canonical document's bytes, so comment bodies are jumped with `indexOf` instead of being scanned per character.
288
291
  - **Linear comment derivation.** Building the `/* … */` annotations uses reverse indexes over the object graph (build file → phase, configuration list → owner), so serialization stays linear on projects with thousands of objects.
289
292
  - **Memoized rendering.** Quoting decisions for the repeated key vocabulary and rendered uuid references are cached per document, halving the quote scans on reference-heavy sections.
290
293
 
package/dist/index.d.ts CHANGED
@@ -307,6 +307,8 @@ interface BuildSettings extends PbxprojObject {
307
307
  SUPPORTED_PLATFORMS?: string;
308
308
  SWIFT_VERSION?: string;
309
309
  TARGETED_DEVICE_FAMILY?: number | string;
310
+ TEST_HOST?: string;
311
+ TEST_TARGET_NAME?: string;
310
312
  TVOS_DEPLOYMENT_TARGET?: string;
311
313
  WATCHOS_DEPLOYMENT_TARGET?: string;
312
314
  XROS_DEPLOYMENT_TARGET?: string;
@@ -888,6 +890,49 @@ declare class VersionGroup extends Group<VersionGroupProperties> {
888
890
  */
889
891
  setCurrentVersion(reference: XcodeObject): void;
890
892
  }
893
+ /**
894
+ * An `XCBuildConfiguration` holds one named settings dictionary of a
895
+ * target or of the project, for example Debug or Release.
896
+ */
897
+ declare class BuildConfiguration extends XcodeObject<BuildConfigurationProperties> {
898
+ /**
899
+ * The configuration's name, when present.
900
+ */
901
+ get name(): string | undefined;
902
+ /**
903
+ * The configuration's settings dictionary, typed with the keys
904
+ * programmatic edits touch most, or `undefined` when the configuration
905
+ * carries none. The dictionary is live. Writes through it land in the
906
+ * document.
907
+ */
908
+ get buildSettings(): BuildSettings | undefined;
909
+ }
910
+ /**
911
+ * A `PBXFileReference` names one file on disk, from source files to the
912
+ * built products themselves.
913
+ */
914
+ declare class FileReference extends XcodeObject<FileReferenceProperties> {
915
+ /**
916
+ * The reference's path, relative to its `sourceTree`, when present.
917
+ */
918
+ get path(): string | undefined;
919
+ /**
920
+ * The reference's display name, when it carries one distinct from the
921
+ * path.
922
+ */
923
+ get name(): string | undefined;
924
+ }
925
+ /**
926
+ * A `PBXContainerItemProxy` is the indirection Xcode places between a
927
+ * target dependency and the target it points at.
928
+ */
929
+ declare class ContainerItemProxy extends XcodeObject<ContainerItemProxyProperties> {
930
+ /**
931
+ * The display name of the object the proxy points at, when present.
932
+ * For target dependencies this is the target's name.
933
+ */
934
+ get remoteInfo(): string | undefined;
935
+ }
891
936
  /**
892
937
  * A `PBXReferenceProxy` stands in for a product built by a target of
893
938
  * another project referenced from this one.
@@ -1213,15 +1258,32 @@ declare class XcodeObject<Properties extends PbxprojObject = PbxprojObject> {
1213
1258
  /** The object's 24-character identifier (its key in `objects`). */
1214
1259
  readonly id: string;
1215
1260
  /**
1216
- * Views are created by the project's identity map; use
1261
+ * Views are created by the project's identity map. Use
1217
1262
  * {@link XcodeProject.get} or a typed query instead of constructing
1218
1263
  * views directly.
1219
1264
  */
1220
1265
  constructor(project: XcodeProject, id: string);
1221
1266
  /**
1222
- * The object's raw dictionary inside the document. Mutations through the
1223
- * model write here, and direct writes are equally valid; the model adds
1224
- * no caching over these properties.
1267
+ * Whether a value is a view of this class, narrowing it when so. Views
1268
+ * come typed out of the factory, and this is the readable way to
1269
+ * discriminate them when iterating mixed objects.
1270
+ *
1271
+ * ```ts
1272
+ * for (const [, object] of project.objects()) {
1273
+ * if (NativeTarget.is(object)) {
1274
+ * console.log(object.name);
1275
+ * }
1276
+ * }
1277
+ * ```
1278
+ *
1279
+ * Subclass views match their parent class too, the way `instanceof`
1280
+ * does, so a `VersionGroup` is a `Group`.
1281
+ */
1282
+ static is<Constructor extends abstract new (...args: never) => unknown>(this: Constructor, value: unknown): value is InstanceType<Constructor>;
1283
+ /**
1284
+ * The object's raw dictionary inside the document. Mutations through
1285
+ * the model write here, direct writes are equally valid, and the model
1286
+ * adds no caching over these properties.
1225
1287
  *
1226
1288
  * The typed shape is asserted, not checked. It describes what a
1227
1289
  * well-formed object of this kind carries (see `properties.ts`).
@@ -1285,19 +1347,20 @@ declare function parsePbxproj(text: string): PbxprojValue;
1285
1347
  /**
1286
1348
  * The node model of a scheme document.
1287
1349
  *
1288
- * A parsed `.xcscheme` is a tree of plain objects: elements with ordered
1289
- * attributes and child nodes, plus the occasional comment. All state lives
1290
- * in this tree. There is no wrapper class to keep in sync, so callers
1291
- * mutate nodes directly and serialize whatever the tree currently says.
1350
+ * A parsed `.xcscheme` is a tree of plain objects. Elements carry ordered
1351
+ * attributes and child nodes, and comments survive as their own nodes.
1352
+ * All state lives in this tree. There is no wrapper to keep in sync, so
1353
+ * callers mutate nodes directly and serialize whatever the tree currently
1354
+ * says.
1292
1355
  *
1293
1356
  * @module
1294
1357
  */
1295
1358
  /**
1296
1359
  * An XML element of a scheme document.
1297
1360
  *
1298
- * Attribute order is preserved and meaningful: the writer emits attributes
1299
- * in insertion order, which is how byte-identical round-trips of
1300
- * Xcode-written files fall out. Assigning an existing key keeps its
1361
+ * Attribute order is preserved and meaningful. The writer emits
1362
+ * attributes in insertion order, which is how Xcode-written files
1363
+ * round-trip byte-identically. Assigning an existing key keeps its
1301
1364
  * position, and adding a new key appends it.
1302
1365
  */
1303
1366
  interface XcschemeElement {
@@ -1322,9 +1385,10 @@ interface XcschemeComment {
1322
1385
  */
1323
1386
  type XcschemeNode = XcschemeElement | XcschemeComment;
1324
1387
  /**
1325
- * A parsed scheme file: its root element plus any comments sitting
1326
- * outside it. Xcode writes only the root, so the comment lists are almost
1327
- * always empty, but files that carry them round-trip without loss.
1388
+ * A parsed scheme file, made of its root element plus any comments
1389
+ * sitting outside it. Xcode writes only the root, so the comment lists
1390
+ * are almost always empty, but files that carry them round-trip without
1391
+ * loss.
1328
1392
  */
1329
1393
  interface XcschemeDocument {
1330
1394
  /** Comments before the root element. */
@@ -1354,14 +1418,99 @@ declare function buildXcscheme(document: XcschemeDocument): string;
1354
1418
  * Collects elements of the given name anywhere in the tree, in document
1355
1419
  * order, the subtree root included. Passing no name collects every
1356
1420
  * element.
1421
+ */
1422
+ declare function xcschemeElements(root: XcschemeElement, name?: string): XcschemeElement[];
1423
+ /**
1424
+ * A `BuildableReference` element with property-style attribute access.
1425
+ *
1426
+ * Buildable references are the elements editing flows touch most, since
1427
+ * every action points at its target through one. The view reads and
1428
+ * writes the element's attributes directly, so it never goes stale and
1429
+ * needs no separate save step.
1430
+ */
1431
+ declare class BuildableReference {
1432
+ /** The underlying element inside the document tree. */
1433
+ readonly element: XcschemeElement;
1434
+ constructor(element: XcschemeElement);
1435
+ /**
1436
+ * The referenced target's object id in the project document, when
1437
+ * present. Xcode repairs a missing or stale identifier on first open.
1438
+ */
1439
+ get blueprintIdentifier(): string | undefined;
1440
+ set blueprintIdentifier(value: string);
1441
+ /**
1442
+ * The referenced target's name, when present.
1443
+ */
1444
+ get blueprintName(): string | undefined;
1445
+ set blueprintName(value: string);
1446
+ /**
1447
+ * The built product's file name, for example `DemoApp.app`, when
1448
+ * present.
1449
+ */
1450
+ get buildableName(): string | undefined;
1451
+ set buildableName(value: string);
1452
+ /**
1453
+ * The container the target lives in, for example
1454
+ * `container:DemoApp.xcodeproj`, when present.
1455
+ */
1456
+ get referencedContainer(): string | undefined;
1457
+ set referencedContainer(value: string);
1458
+ }
1459
+ /**
1460
+ * A scheme document with typed access to the elements editing flows
1461
+ * touch.
1462
+ *
1463
+ * The model is a thin layer over the node tree. All state lives in the
1464
+ * document itself, and {@link build} serializes whatever the tree
1465
+ * currently says, so typed edits and direct tree edits compose freely.
1357
1466
  *
1358
1467
  * ```ts
1359
- * for (const reference of xcschemeElements(scheme.root, "BuildableReference")) {
1360
- * reference.attributes["BlueprintName"] = "RenamedApp";
1468
+ * const scheme = Xcscheme.parse(xcschemeText);
1469
+ * for (const reference of scheme.buildableReferences()) {
1470
+ * reference.blueprintName = "RenamedApp";
1471
+ * reference.buildableName = "RenamedApp.app";
1361
1472
  * }
1473
+ * const text = scheme.build();
1362
1474
  * ```
1363
1475
  */
1364
- declare function xcschemeElements(root: XcschemeElement, name?: string): XcschemeElement[];
1476
+ declare class Xcscheme {
1477
+ /** The underlying parsed document. */
1478
+ readonly document: XcschemeDocument;
1479
+ constructor(document: XcschemeDocument);
1480
+ /**
1481
+ * Parses the text of a `.xcscheme` file into a scheme model.
1482
+ *
1483
+ * @throws XcschemeParseError when the text is not a well-formed scheme
1484
+ * document, with the line and column of the failure.
1485
+ */
1486
+ static parse(text: string): Xcscheme;
1487
+ /**
1488
+ * Creates the scheme Xcode writes for an application target. See
1489
+ * {@link createXcscheme} for the shape it produces.
1490
+ */
1491
+ static create(options: CreateXcschemeOptions): Xcscheme;
1492
+ /**
1493
+ * The document's `Scheme` element.
1494
+ */
1495
+ get root(): XcschemeElement;
1496
+ /**
1497
+ * Serializes the scheme to the text of a `.xcscheme` file in Xcode's
1498
+ * canonical layout.
1499
+ */
1500
+ build(): string;
1501
+ /**
1502
+ * Collects elements of the given name anywhere in the document, in
1503
+ * document order. Passing no name collects every element.
1504
+ */
1505
+ elements(name?: string): XcschemeElement[];
1506
+ /**
1507
+ * The views of every buildable reference in the document, in document
1508
+ * order. Build entries, testables, macro expansions, runnables, and
1509
+ * action environment buildables all point at their target through one
1510
+ * of these, so rename flows iterate this list.
1511
+ */
1512
+ buildableReferences(): BuildableReference[];
1513
+ }
1365
1514
  /**
1366
1515
  * Options for {@link createXcscheme}.
1367
1516
  */
@@ -1381,10 +1530,11 @@ interface CreateXcschemeOptions {
1381
1530
  blueprintIdentifier?: string;
1382
1531
  }
1383
1532
  /**
1384
- * Creates the scheme Xcode writes for an application target: build,
1385
- * launch, profile, analyze, and archive actions wired to the app product,
1386
- * with Xcode's default configuration choices (Debug for development
1387
- * actions, Release for profiling and archiving).
1533
+ * Creates the scheme Xcode writes for an application target. The
1534
+ * document carries build, launch, profile, analyze, and archive actions
1535
+ * wired to the app product, with Xcode's default configuration choices
1536
+ * of Debug for development actions and Release for profiling and
1537
+ * archiving.
1388
1538
  */
1389
1539
  declare function createXcscheme(options: CreateXcschemeOptions): XcschemeDocument;
1390
1540
  //#endregion
@@ -1424,4 +1574,4 @@ declare function parseXcscheme(text: string): XcschemeDocument;
1424
1574
  */
1425
1575
  declare function generateObjectId(seed: string, existing: ReadonlySet<string>): string;
1426
1576
  //#endregion
1427
- export { type AddNativeTargetOptions, AggregateTarget, type ApplePlatform, type BuildConfigurationProperties, type BuildFileProperties, BuildPhase, type BuildPhaseProperties, BuildRule, type BuildRuleProperties, type BuildSettings, type ConfigurationListProperties, type ContainerItemProxyProperties, CopyFilesDestination, type CreateXcschemeOptions, type ExceptionSetProperties, type FileReferenceProperties, Group, type GroupProperties, Isa, LegacyTarget, type LegacyTargetProperties, NativeTarget, type NativeTargetProperties, type PbxprojArray, PbxprojBuildError, type PbxprojErrorPosition, type PbxprojObject, PbxprojParseError, type PbxprojValue, ProductType, type ProjectIssue, type ProjectIssueKind, ReferenceProxy, type ReferenceProxyProperties, RootProject, type RootProjectProperties, type SwiftPackageProductDependencyProperties, type SwiftPackageReferenceProperties, SyncRootGroup, type SyncRootGroupProperties, Target, type TargetDependencyProperties, type TargetProperties, VersionGroup, type VersionGroupProperties, XcodeModelError, XcodeObject, XcodeProject, XcschemeBuildError, type XcschemeComment, type XcschemeDocument, type XcschemeElement, type XcschemeNode, XcschemeParseError, buildPbxproj, buildXcscheme, createXcscheme, generateObjectId, isXcschemeElement, parsePbxproj, parseXcscheme, xcschemeElements };
1577
+ export { type AddNativeTargetOptions, AggregateTarget, type ApplePlatform, BuildConfiguration, type BuildConfigurationProperties, type BuildFileProperties, BuildPhase, type BuildPhaseProperties, BuildRule, type BuildRuleProperties, type BuildSettings, BuildableReference, type ConfigurationListProperties, ContainerItemProxy, type ContainerItemProxyProperties, CopyFilesDestination, type CreateXcschemeOptions, type ExceptionSetProperties, FileReference, type FileReferenceProperties, Group, type GroupProperties, Isa, LegacyTarget, type LegacyTargetProperties, NativeTarget, type NativeTargetProperties, type PbxprojArray, PbxprojBuildError, type PbxprojErrorPosition, type PbxprojObject, PbxprojParseError, type PbxprojValue, ProductType, type ProjectIssue, type ProjectIssueKind, ReferenceProxy, type ReferenceProxyProperties, RootProject, type RootProjectProperties, type SwiftPackageProductDependencyProperties, type SwiftPackageReferenceProperties, SyncRootGroup, type SyncRootGroupProperties, Target, type TargetDependencyProperties, type TargetProperties, VersionGroup, type VersionGroupProperties, XcodeModelError, XcodeObject, XcodeProject, Xcscheme, XcschemeBuildError, type XcschemeComment, type XcschemeDocument, type XcschemeElement, type XcschemeNode, XcschemeParseError, buildPbxproj, buildXcscheme, createXcscheme, generateObjectId, isXcschemeElement, parsePbxproj, parseXcscheme, xcschemeElements };
package/dist/index.js CHANGED
@@ -1006,9 +1006,9 @@ function stringItems(value) {
1006
1006
  *
1007
1007
  * Views are lightweight, identity-mapped facades over entries of the
1008
1008
  * document's `objects` dictionary. All state lives in the parsed document
1009
- * itself; a view holds only its id and a reference back to the project, so
1010
- * document text produced from the model reflects every mutation with no
1011
- * separate serialization step.
1009
+ * itself, and a view holds only its id and a reference back to the
1010
+ * project, so document text produced from the model reflects every
1011
+ * mutation with no separate serialization step.
1012
1012
  *
1013
1013
  * @module
1014
1014
  */
@@ -1030,7 +1030,7 @@ var XcodeObject = class {
1030
1030
  /** The object's 24-character identifier (its key in `objects`). */
1031
1031
  id;
1032
1032
  /**
1033
- * Views are created by the project's identity map; use
1033
+ * Views are created by the project's identity map. Use
1034
1034
  * {@link XcodeProject.get} or a typed query instead of constructing
1035
1035
  * views directly.
1036
1036
  */
@@ -1039,9 +1039,28 @@ var XcodeObject = class {
1039
1039
  this.id = id;
1040
1040
  }
1041
1041
  /**
1042
- * The object's raw dictionary inside the document. Mutations through the
1043
- * model write here, and direct writes are equally valid; the model adds
1044
- * no caching over these properties.
1042
+ * Whether a value is a view of this class, narrowing it when so. Views
1043
+ * come typed out of the factory, and this is the readable way to
1044
+ * discriminate them when iterating mixed objects.
1045
+ *
1046
+ * ```ts
1047
+ * for (const [, object] of project.objects()) {
1048
+ * if (NativeTarget.is(object)) {
1049
+ * console.log(object.name);
1050
+ * }
1051
+ * }
1052
+ * ```
1053
+ *
1054
+ * Subclass views match their parent class too, the way `instanceof`
1055
+ * does, so a `VersionGroup` is a `Group`.
1056
+ */
1057
+ static is(value) {
1058
+ return value instanceof this;
1059
+ }
1060
+ /**
1061
+ * The object's raw dictionary inside the document. Mutations through
1062
+ * the model write here, direct writes are equally valid, and the model
1063
+ * adds no caching over these properties.
1045
1064
  *
1046
1065
  * The typed shape is asserted, not checked. It describes what a
1047
1066
  * well-formed object of this kind carries (see `properties.ts`).
@@ -1342,6 +1361,59 @@ var VersionGroup = class extends Group {
1342
1361
  }
1343
1362
  };
1344
1363
  /**
1364
+ * An `XCBuildConfiguration` holds one named settings dictionary of a
1365
+ * target or of the project, for example Debug or Release.
1366
+ */
1367
+ var BuildConfiguration = class extends XcodeObject {
1368
+ /**
1369
+ * The configuration's name, when present.
1370
+ */
1371
+ get name() {
1372
+ return this.getString("name");
1373
+ }
1374
+ /**
1375
+ * The configuration's settings dictionary, typed with the keys
1376
+ * programmatic edits touch most, or `undefined` when the configuration
1377
+ * carries none. The dictionary is live. Writes through it land in the
1378
+ * document.
1379
+ */
1380
+ get buildSettings() {
1381
+ return asDictionary(this.properties["buildSettings"]);
1382
+ }
1383
+ };
1384
+ /**
1385
+ * A `PBXFileReference` names one file on disk, from source files to the
1386
+ * built products themselves.
1387
+ */
1388
+ var FileReference = class extends XcodeObject {
1389
+ /**
1390
+ * The reference's path, relative to its `sourceTree`, when present.
1391
+ */
1392
+ get path() {
1393
+ return this.getString("path");
1394
+ }
1395
+ /**
1396
+ * The reference's display name, when it carries one distinct from the
1397
+ * path.
1398
+ */
1399
+ get name() {
1400
+ return this.getString("name");
1401
+ }
1402
+ };
1403
+ /**
1404
+ * A `PBXContainerItemProxy` is the indirection Xcode places between a
1405
+ * target dependency and the target it points at.
1406
+ */
1407
+ var ContainerItemProxy = class extends XcodeObject {
1408
+ /**
1409
+ * The display name of the object the proxy points at, when present.
1410
+ * For target dependencies this is the target's name.
1411
+ */
1412
+ get remoteInfo() {
1413
+ return this.getString("remoteInfo");
1414
+ }
1415
+ };
1416
+ /**
1345
1417
  * A `PBXReferenceProxy` stands in for a product built by a target of
1346
1418
  * another project referenced from this one.
1347
1419
  */
@@ -3370,6 +3442,9 @@ var XcodeProject = class XcodeProject {
3370
3442
  case Isa.versionGroup: return new VersionGroup(this, id);
3371
3443
  case Isa.fileSystemSynchronizedRootGroup: return new SyncRootGroup(this, id);
3372
3444
  case Isa.buildRule: return new BuildRule(this, id);
3445
+ case Isa.buildConfiguration: return new BuildConfiguration(this, id);
3446
+ case Isa.fileReference: return new FileReference(this, id);
3447
+ case Isa.containerItemProxy: return new ContainerItemProxy(this, id);
3373
3448
  case Isa.referenceProxy: return new ReferenceProxy(this, id);
3374
3449
  default: return isa.endsWith("BuildPhase") ? new BuildPhase(this, id) : new XcodeObject(this, id);
3375
3450
  }
@@ -3454,26 +3529,28 @@ function isXcschemeElement(node) {
3454
3529
  /**
3455
3530
  * Serializer for the `.xcscheme` XML dialect.
3456
3531
  *
3457
- * The output reproduces Xcode's own layout byte for byte: the UTF-8
3458
- * declaration, three-space indentation, one attribute per line with
3459
- * spaces around the equals sign, the closing angle bracket glued to the
3460
- * last attribute, and an explicit close tag on every element. Parsing an
3461
- * Xcode-written scheme and building it back yields the identical file,
3462
- * and any input reaches that canonical form in one build.
3532
+ * The output reproduces Xcode's own layout byte for byte. Xcode writes
3533
+ * the UTF-8 declaration, indents with three spaces, puts each attribute
3534
+ * on its own line with spaces around the equals sign, glues the closing
3535
+ * angle bracket to the last attribute, and closes every element with an
3536
+ * explicit close tag. Parsing an Xcode-written scheme and building it
3537
+ * back therefore yields the identical file, and any other input reaches
3538
+ * that canonical form in one build.
3463
3539
  *
3464
3540
  * @module
3465
3541
  */
3542
+ /** The declaration line Xcode writes at the top of every scheme file. */
3466
3543
  const XML_DECLARATION = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
3467
3544
  /** One indentation step of Xcode's scheme writer. */
3468
3545
  const INDENT = " ";
3469
3546
  /**
3470
- * Matches the names Xcode's scheme vocabulary uses; a stray non-name
3471
- * (an empty string, spaces, XML syntax) must fail rather than produce a
3547
+ * Matches valid XML names. A stray non-name, such as an empty string or
3548
+ * one carrying spaces or XML syntax, must fail rather than produce a
3472
3549
  * document no parser accepts.
3473
3550
  */
3474
3551
  const NAME_PATTERN = /^[A-Za-z_:][A-Za-z0-9_:.-]*$/u;
3475
3552
  /**
3476
- * Matches characters that cannot appear in an attribute value: XML 1.0
3553
+ * Matches characters that cannot appear in an attribute value. XML 1.0
3477
3554
  * has no representation for control characters other than tab, line
3478
3555
  * feed, and carriage return.
3479
3556
  */
@@ -3493,9 +3570,10 @@ function buildXcscheme(document) {
3493
3570
  return output;
3494
3571
  }
3495
3572
  /**
3496
- * Renders one element with Xcode's layout: attributes each on their own
3497
- * line indented one step past the tag, `>` glued to the last attribute,
3498
- * children indented one step, and always an explicit close tag.
3573
+ * Renders one element with Xcode's layout. Attributes go each on their
3574
+ * own line indented one step past the tag, the `>` glues to the last
3575
+ * attribute, children indent one step, and the close tag is always
3576
+ * explicit.
3499
3577
  */
3500
3578
  function renderElement(element, depth, path) {
3501
3579
  if (!NAME_PATTERN.test(element.name)) throw new XcschemeBuildError(`Element name ${JSON.stringify(element.name)} is not a valid XML name`, path);
@@ -3533,10 +3611,10 @@ function renderChildren(children, depth, path) {
3533
3611
  return output;
3534
3612
  }
3535
3613
  /**
3536
- * Escapes an attribute value the way Xcode's writer does: the five named
3537
- * entities for XML syntax characters, and character references for tab,
3538
- * line feed, and carriage return so they survive attribute-value
3539
- * normalization on the next parse.
3614
+ * Escapes an attribute value the way Xcode's writer does. XML syntax
3615
+ * characters become the five named entities, and tab, line feed, and
3616
+ * carriage return become character references so they survive
3617
+ * attribute-value normalization on the next parse.
3540
3618
  */
3541
3619
  function escapeAttribute(value, path, attributeName) {
3542
3620
  const unencodable = UNENCODABLE_PATTERN.exec(value);
@@ -3544,152 +3622,17 @@ function escapeAttribute(value, path, attributeName) {
3544
3622
  return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\"", "&quot;").replaceAll("'", "&apos;").replaceAll(" ", "&#9;").replaceAll("\n", "&#10;").replaceAll("\r", "&#13;");
3545
3623
  }
3546
3624
  //#endregion
3547
- //#region src/scheme/model.ts
3548
- /**
3549
- * Helpers over the scheme node tree: element queries and the default
3550
- * scheme factory.
3551
- *
3552
- * The tree itself is plain data, so most edits are direct property
3553
- * writes. What this module adds is the recursive query that editing
3554
- * flows start from and a factory producing the scheme Xcode's own "New
3555
- * Scheme" action writes for an application target.
3556
- *
3557
- * @module
3558
- */
3559
- /**
3560
- * Collects elements of the given name anywhere in the tree, in document
3561
- * order, the subtree root included. Passing no name collects every
3562
- * element.
3563
- *
3564
- * ```ts
3565
- * for (const reference of xcschemeElements(scheme.root, "BuildableReference")) {
3566
- * reference.attributes["BlueprintName"] = "RenamedApp";
3567
- * }
3568
- * ```
3569
- */
3570
- function xcschemeElements(root, name) {
3571
- const found = [];
3572
- const visit = (element) => {
3573
- if (name == null || element.name === name) found.push(element);
3574
- for (const child of element.children) if (isXcschemeElement(child)) visit(child);
3575
- };
3576
- visit(root);
3577
- return found;
3578
- }
3579
- /**
3580
- * Creates the scheme Xcode writes for an application target: build,
3581
- * launch, profile, analyze, and archive actions wired to the app product,
3582
- * with Xcode's default configuration choices (Debug for development
3583
- * actions, Release for profiling and archiving).
3584
- */
3585
- function createXcscheme(options) {
3586
- const xcodeprojName = options.xcodeprojName ?? `${options.appName}.xcodeproj`;
3587
- /**
3588
- * Buildable references appear once per action; each site gets its own
3589
- * element so a mutation through one action cannot alias into another.
3590
- */
3591
- const buildableReference = () => ({
3592
- name: "BuildableReference",
3593
- attributes: {
3594
- BuildableIdentifier: "primary",
3595
- BlueprintIdentifier: options.blueprintIdentifier ?? "",
3596
- BuildableName: `${options.appName}.app`,
3597
- BlueprintName: options.appName,
3598
- ReferencedContainer: `container:${xcodeprojName}`
3599
- },
3600
- children: []
3601
- });
3602
- return {
3603
- leading: [],
3604
- root: {
3605
- name: "Scheme",
3606
- attributes: { version: "1.7" },
3607
- children: [
3608
- {
3609
- name: "BuildAction",
3610
- attributes: {
3611
- parallelizeBuildables: "YES",
3612
- buildImplicitDependencies: "YES"
3613
- },
3614
- children: [{
3615
- name: "BuildActionEntries",
3616
- attributes: {},
3617
- children: [{
3618
- name: "BuildActionEntry",
3619
- attributes: {
3620
- buildForTesting: "YES",
3621
- buildForRunning: "YES",
3622
- buildForProfiling: "YES",
3623
- buildForArchiving: "YES",
3624
- buildForAnalyzing: "YES"
3625
- },
3626
- children: [buildableReference()]
3627
- }]
3628
- }]
3629
- },
3630
- {
3631
- name: "LaunchAction",
3632
- attributes: {
3633
- buildConfiguration: "Debug",
3634
- selectedDebuggerIdentifier: "Xcode.DebuggerFoundation.Debugger.LLDB",
3635
- selectedLauncherIdentifier: "Xcode.DebuggerFoundation.Launcher.LLDB",
3636
- launchStyle: "0",
3637
- useCustomWorkingDirectory: "NO",
3638
- ignoresPersistentStateOnLaunch: "NO",
3639
- debugDocumentVersioning: "YES",
3640
- debugServiceExtension: "internal",
3641
- allowLocationSimulation: "YES"
3642
- },
3643
- children: [{
3644
- name: "BuildableProductRunnable",
3645
- attributes: { runnableDebuggingMode: "0" },
3646
- children: [buildableReference()]
3647
- }]
3648
- },
3649
- {
3650
- name: "ProfileAction",
3651
- attributes: {
3652
- buildConfiguration: "Release",
3653
- shouldUseLaunchSchemeArgsEnv: "YES",
3654
- savedToolIdentifier: "",
3655
- useCustomWorkingDirectory: "NO",
3656
- debugDocumentVersioning: "YES"
3657
- },
3658
- children: [{
3659
- name: "BuildableProductRunnable",
3660
- attributes: { runnableDebuggingMode: "0" },
3661
- children: [buildableReference()]
3662
- }]
3663
- },
3664
- {
3665
- name: "AnalyzeAction",
3666
- attributes: { buildConfiguration: "Debug" },
3667
- children: []
3668
- },
3669
- {
3670
- name: "ArchiveAction",
3671
- attributes: {
3672
- buildConfiguration: "Release",
3673
- revealArchiveInOrganizer: "YES"
3674
- },
3675
- children: []
3676
- }
3677
- ]
3678
- },
3679
- trailing: []
3680
- };
3681
- }
3682
- //#endregion
3683
3625
  //#region src/scheme/parse.ts
3684
3626
  /**
3685
3627
  * Parser for the `.xcscheme` XML dialect.
3686
3628
  *
3687
- * Scheme files are XML with a narrow shape: elements with attributes and
3688
- * child elements, no text content, no namespaces, no DOCTYPE. The parser
3689
- * accepts that shape from any writer (attribute order, quoting style, and
3690
- * whitespace vary across tools), resolves character and entity references
3691
- * in attribute values, and preserves comments. Anything outside the shape
3692
- * fails loudly with a position, in line with the pbxproj parser.
3629
+ * Scheme files are XML with a narrow shape. Elements carry attributes and
3630
+ * child elements, and there is no text content, no namespace, and no
3631
+ * DOCTYPE. The parser accepts that shape from any writer, since attribute
3632
+ * order, quoting style, and whitespace vary across tools. Character and
3633
+ * entity references in attribute values resolve to their characters, and
3634
+ * comments are preserved. Anything outside the shape fails loudly with a
3635
+ * position, in line with the pbxproj parser.
3693
3636
  *
3694
3637
  * @module
3695
3638
  */
@@ -3746,13 +3689,24 @@ const NAMED_ENTITIES = {
3746
3689
  function parseXcscheme(text) {
3747
3690
  return new Parser(text).parseDocument();
3748
3691
  }
3692
+ /**
3693
+ * Single-pass recursive-descent parser over the source text. One instance
3694
+ * parses one document and is discarded.
3695
+ */
3749
3696
  var Parser = class {
3697
+ /** The full source text of the scheme file. */
3750
3698
  input;
3699
+ /** Cursor into {@link input}, in UTF-16 code units. */
3751
3700
  pos = 0;
3752
3701
  constructor(input) {
3753
3702
  this.input = input;
3754
3703
  if (input.charCodeAt(0) === CODE_BOM) this.pos = 1;
3755
3704
  }
3705
+ /**
3706
+ * Parses the whole document. The XML declaration is skipped, comments
3707
+ * around the root element are collected, and anything left after the
3708
+ * root fails.
3709
+ */
3756
3710
  parseDocument() {
3757
3711
  this.skipWhitespace();
3758
3712
  this.skipDeclaration();
@@ -3778,7 +3732,8 @@ var Parser = class {
3778
3732
  }
3779
3733
  /**
3780
3734
  * Skips the `<?xml ... ?>` declaration when present. Its attributes are
3781
- * not retained: the writer always emits the canonical UTF-8 declaration.
3735
+ * not retained, since the writer always emits the canonical UTF-8
3736
+ * declaration.
3782
3737
  */
3783
3738
  skipDeclaration() {
3784
3739
  if (this.input.charCodeAt(this.pos) !== CODE_LESS_THAN || this.input.charCodeAt(this.pos + 1) !== CODE_QUESTION) return;
@@ -3786,6 +3741,12 @@ var Parser = class {
3786
3741
  if (end === -1) this.fail("Unterminated XML declaration");
3787
3742
  this.pos = end + 2;
3788
3743
  }
3744
+ /**
3745
+ * Parses one element with the cursor on its opening `<`, including its
3746
+ * attributes and children, through to the matching close tag. Xcode
3747
+ * never writes self-closing tags, but other generators do, so both
3748
+ * forms are accepted.
3749
+ */
3789
3750
  parseElement() {
3790
3751
  if (this.input.charCodeAt(this.pos) !== CODE_LESS_THAN) this.fail("Expected an element");
3791
3752
  this.pos++;
@@ -3839,9 +3800,16 @@ var Parser = class {
3839
3800
  else children.push(this.parseElement());
3840
3801
  }
3841
3802
  }
3803
+ /**
3804
+ * Whether the cursor sits on a `<!--` comment opener.
3805
+ */
3842
3806
  peekIsCommentStart() {
3843
3807
  return this.input.charCodeAt(this.pos) === CODE_LESS_THAN && this.input.charCodeAt(this.pos + 1) === CODE_BANG && this.input.charCodeAt(this.pos + 2) === CODE_HYPHEN && this.input.charCodeAt(this.pos + 3) === CODE_HYPHEN;
3844
3808
  }
3809
+ /**
3810
+ * Parses one comment with the cursor on its `<!--` opener. The text
3811
+ * between the markers is kept verbatim.
3812
+ */
3845
3813
  parseComment() {
3846
3814
  const end = this.input.indexOf("-->", this.pos + 4);
3847
3815
  if (end === -1) this.fail("Unterminated comment");
@@ -3849,6 +3817,10 @@ var Parser = class {
3849
3817
  this.pos = end + 3;
3850
3818
  return { comment };
3851
3819
  }
3820
+ /**
3821
+ * Parses an XML name at the cursor. The `what` label names the
3822
+ * expectation in the error when no name starts here.
3823
+ */
3852
3824
  parseName(what) {
3853
3825
  const start = this.pos;
3854
3826
  if (!isNameStart(this.input.charCodeAt(this.pos))) this.fail(`Expected ${what}`);
@@ -3856,6 +3828,12 @@ var Parser = class {
3856
3828
  while (isNameChar(this.input.charCodeAt(this.pos))) this.pos++;
3857
3829
  return this.input.slice(start, this.pos);
3858
3830
  }
3831
+ /**
3832
+ * Parses a quoted attribute value with the cursor on the opening quote,
3833
+ * resolving character and entity references along the way. Both quote
3834
+ * styles are accepted, and a raw `<` inside the value fails as XML
3835
+ * requires.
3836
+ */
3859
3837
  parseAttributeValue() {
3860
3838
  const quote = this.input.charCodeAt(this.pos);
3861
3839
  if (quote !== CODE_QUOTE && quote !== CODE_APOSTROPHE) this.fail("Expected a quoted attribute value");
@@ -3912,12 +3890,275 @@ var Parser = class {
3912
3890
  while (isWhitespace(this.input.charCodeAt(this.pos))) this.pos++;
3913
3891
  return this.pos > start;
3914
3892
  }
3893
+ /**
3894
+ * Throws a parse error at the cursor.
3895
+ */
3915
3896
  fail(message) {
3916
3897
  this.failAt(message, this.pos);
3917
3898
  }
3899
+ /**
3900
+ * Throws a parse error at an explicit offset, which reference parsing
3901
+ * uses to point at the start of a bad reference rather than its end.
3902
+ */
3918
3903
  failAt(message, offset) {
3919
3904
  throw new XcschemeParseError(message, this.input, offset);
3920
3905
  }
3921
3906
  };
3922
3907
  //#endregion
3923
- export { AggregateTarget, BuildPhase, BuildRule, CopyFilesDestination, Group, Isa, LegacyTarget, NativeTarget, PbxprojBuildError, PbxprojParseError, ProductType, ReferenceProxy, RootProject, SyncRootGroup, Target, VersionGroup, XcodeModelError, XcodeObject, XcodeProject, XcschemeBuildError, XcschemeParseError, buildPbxproj, buildXcscheme, createXcscheme, generateObjectId, isXcschemeElement, parsePbxproj, parseXcscheme, xcschemeElements };
3908
+ //#region src/scheme/model.ts
3909
+ /**
3910
+ * The scheme object model and its helpers.
3911
+ *
3912
+ * {@link Xcscheme} wraps a parsed document with the typed access editing
3913
+ * flows want, {@link BuildableReference} gives buildable references
3914
+ * property-style attribute access, {@link xcschemeElements} is the
3915
+ * recursive query underneath it all, and {@link createXcscheme} produces
3916
+ * the scheme Xcode's own "New Scheme" action writes. The node tree stays
3917
+ * the single source of truth. Views hold only a reference into it, so
3918
+ * model calls and direct tree edits compose freely.
3919
+ *
3920
+ * @module
3921
+ */
3922
+ /**
3923
+ * Collects elements of the given name anywhere in the tree, in document
3924
+ * order, the subtree root included. Passing no name collects every
3925
+ * element.
3926
+ */
3927
+ function xcschemeElements(root, name) {
3928
+ const found = [];
3929
+ const visit = (element) => {
3930
+ if (name == null || element.name === name) found.push(element);
3931
+ for (const child of element.children) if (isXcschemeElement(child)) visit(child);
3932
+ };
3933
+ visit(root);
3934
+ return found;
3935
+ }
3936
+ /**
3937
+ * A `BuildableReference` element with property-style attribute access.
3938
+ *
3939
+ * Buildable references are the elements editing flows touch most, since
3940
+ * every action points at its target through one. The view reads and
3941
+ * writes the element's attributes directly, so it never goes stale and
3942
+ * needs no separate save step.
3943
+ */
3944
+ var BuildableReference = class {
3945
+ /** The underlying element inside the document tree. */
3946
+ element;
3947
+ constructor(element) {
3948
+ this.element = element;
3949
+ }
3950
+ /**
3951
+ * The referenced target's object id in the project document, when
3952
+ * present. Xcode repairs a missing or stale identifier on first open.
3953
+ */
3954
+ get blueprintIdentifier() {
3955
+ return this.element.attributes["BlueprintIdentifier"];
3956
+ }
3957
+ set blueprintIdentifier(value) {
3958
+ this.element.attributes["BlueprintIdentifier"] = value;
3959
+ }
3960
+ /**
3961
+ * The referenced target's name, when present.
3962
+ */
3963
+ get blueprintName() {
3964
+ return this.element.attributes["BlueprintName"];
3965
+ }
3966
+ set blueprintName(value) {
3967
+ this.element.attributes["BlueprintName"] = value;
3968
+ }
3969
+ /**
3970
+ * The built product's file name, for example `DemoApp.app`, when
3971
+ * present.
3972
+ */
3973
+ get buildableName() {
3974
+ return this.element.attributes["BuildableName"];
3975
+ }
3976
+ set buildableName(value) {
3977
+ this.element.attributes["BuildableName"] = value;
3978
+ }
3979
+ /**
3980
+ * The container the target lives in, for example
3981
+ * `container:DemoApp.xcodeproj`, when present.
3982
+ */
3983
+ get referencedContainer() {
3984
+ return this.element.attributes["ReferencedContainer"];
3985
+ }
3986
+ set referencedContainer(value) {
3987
+ this.element.attributes["ReferencedContainer"] = value;
3988
+ }
3989
+ };
3990
+ /**
3991
+ * A scheme document with typed access to the elements editing flows
3992
+ * touch.
3993
+ *
3994
+ * The model is a thin layer over the node tree. All state lives in the
3995
+ * document itself, and {@link build} serializes whatever the tree
3996
+ * currently says, so typed edits and direct tree edits compose freely.
3997
+ *
3998
+ * ```ts
3999
+ * const scheme = Xcscheme.parse(xcschemeText);
4000
+ * for (const reference of scheme.buildableReferences()) {
4001
+ * reference.blueprintName = "RenamedApp";
4002
+ * reference.buildableName = "RenamedApp.app";
4003
+ * }
4004
+ * const text = scheme.build();
4005
+ * ```
4006
+ */
4007
+ var Xcscheme = class Xcscheme {
4008
+ /** The underlying parsed document. */
4009
+ document;
4010
+ constructor(document) {
4011
+ this.document = document;
4012
+ }
4013
+ /**
4014
+ * Parses the text of a `.xcscheme` file into a scheme model.
4015
+ *
4016
+ * @throws XcschemeParseError when the text is not a well-formed scheme
4017
+ * document, with the line and column of the failure.
4018
+ */
4019
+ static parse(text) {
4020
+ return new Xcscheme(parseXcscheme(text));
4021
+ }
4022
+ /**
4023
+ * Creates the scheme Xcode writes for an application target. See
4024
+ * {@link createXcscheme} for the shape it produces.
4025
+ */
4026
+ static create(options) {
4027
+ return new Xcscheme(createXcscheme(options));
4028
+ }
4029
+ /**
4030
+ * The document's `Scheme` element.
4031
+ */
4032
+ get root() {
4033
+ return this.document.root;
4034
+ }
4035
+ /**
4036
+ * Serializes the scheme to the text of a `.xcscheme` file in Xcode's
4037
+ * canonical layout.
4038
+ */
4039
+ build() {
4040
+ return buildXcscheme(this.document);
4041
+ }
4042
+ /**
4043
+ * Collects elements of the given name anywhere in the document, in
4044
+ * document order. Passing no name collects every element.
4045
+ */
4046
+ elements(name) {
4047
+ return xcschemeElements(this.document.root, name);
4048
+ }
4049
+ /**
4050
+ * The views of every buildable reference in the document, in document
4051
+ * order. Build entries, testables, macro expansions, runnables, and
4052
+ * action environment buildables all point at their target through one
4053
+ * of these, so rename flows iterate this list.
4054
+ */
4055
+ buildableReferences() {
4056
+ return this.elements("BuildableReference").map((element) => new BuildableReference(element));
4057
+ }
4058
+ };
4059
+ /**
4060
+ * Creates the scheme Xcode writes for an application target. The
4061
+ * document carries build, launch, profile, analyze, and archive actions
4062
+ * wired to the app product, with Xcode's default configuration choices
4063
+ * of Debug for development actions and Release for profiling and
4064
+ * archiving.
4065
+ */
4066
+ function createXcscheme(options) {
4067
+ const xcodeprojName = options.xcodeprojName ?? `${options.appName}.xcodeproj`;
4068
+ /**
4069
+ * Buildable references appear once per action. Each site gets its own
4070
+ * element so a mutation through one action cannot alias into another.
4071
+ */
4072
+ const buildableReference = () => ({
4073
+ name: "BuildableReference",
4074
+ attributes: {
4075
+ BuildableIdentifier: "primary",
4076
+ BlueprintIdentifier: options.blueprintIdentifier ?? "",
4077
+ BuildableName: `${options.appName}.app`,
4078
+ BlueprintName: options.appName,
4079
+ ReferencedContainer: `container:${xcodeprojName}`
4080
+ },
4081
+ children: []
4082
+ });
4083
+ return {
4084
+ leading: [],
4085
+ root: {
4086
+ name: "Scheme",
4087
+ attributes: { version: "1.7" },
4088
+ children: [
4089
+ {
4090
+ name: "BuildAction",
4091
+ attributes: {
4092
+ parallelizeBuildables: "YES",
4093
+ buildImplicitDependencies: "YES"
4094
+ },
4095
+ children: [{
4096
+ name: "BuildActionEntries",
4097
+ attributes: {},
4098
+ children: [{
4099
+ name: "BuildActionEntry",
4100
+ attributes: {
4101
+ buildForTesting: "YES",
4102
+ buildForRunning: "YES",
4103
+ buildForProfiling: "YES",
4104
+ buildForArchiving: "YES",
4105
+ buildForAnalyzing: "YES"
4106
+ },
4107
+ children: [buildableReference()]
4108
+ }]
4109
+ }]
4110
+ },
4111
+ {
4112
+ name: "LaunchAction",
4113
+ attributes: {
4114
+ buildConfiguration: "Debug",
4115
+ selectedDebuggerIdentifier: "Xcode.DebuggerFoundation.Debugger.LLDB",
4116
+ selectedLauncherIdentifier: "Xcode.DebuggerFoundation.Launcher.LLDB",
4117
+ launchStyle: "0",
4118
+ useCustomWorkingDirectory: "NO",
4119
+ ignoresPersistentStateOnLaunch: "NO",
4120
+ debugDocumentVersioning: "YES",
4121
+ debugServiceExtension: "internal",
4122
+ allowLocationSimulation: "YES"
4123
+ },
4124
+ children: [{
4125
+ name: "BuildableProductRunnable",
4126
+ attributes: { runnableDebuggingMode: "0" },
4127
+ children: [buildableReference()]
4128
+ }]
4129
+ },
4130
+ {
4131
+ name: "ProfileAction",
4132
+ attributes: {
4133
+ buildConfiguration: "Release",
4134
+ shouldUseLaunchSchemeArgsEnv: "YES",
4135
+ savedToolIdentifier: "",
4136
+ useCustomWorkingDirectory: "NO",
4137
+ debugDocumentVersioning: "YES"
4138
+ },
4139
+ children: [{
4140
+ name: "BuildableProductRunnable",
4141
+ attributes: { runnableDebuggingMode: "0" },
4142
+ children: [buildableReference()]
4143
+ }]
4144
+ },
4145
+ {
4146
+ name: "AnalyzeAction",
4147
+ attributes: { buildConfiguration: "Debug" },
4148
+ children: []
4149
+ },
4150
+ {
4151
+ name: "ArchiveAction",
4152
+ attributes: {
4153
+ buildConfiguration: "Release",
4154
+ revealArchiveInOrganizer: "YES"
4155
+ },
4156
+ children: []
4157
+ }
4158
+ ]
4159
+ },
4160
+ trailing: []
4161
+ };
4162
+ }
4163
+ //#endregion
4164
+ export { AggregateTarget, BuildConfiguration, BuildPhase, BuildRule, BuildableReference, ContainerItemProxy, CopyFilesDestination, FileReference, Group, Isa, LegacyTarget, NativeTarget, PbxprojBuildError, PbxprojParseError, ProductType, ReferenceProxy, RootProject, SyncRootGroup, Target, VersionGroup, XcodeModelError, XcodeObject, XcodeProject, Xcscheme, XcschemeBuildError, XcschemeParseError, buildPbxproj, buildXcscheme, createXcscheme, generateObjectId, isXcschemeElement, parsePbxproj, parseXcscheme, xcschemeElements };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rork-xcode",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Zero-dependency Xcode project (pbxproj) and scheme (xcscheme) parser, builder, and object model that runs identically in every JavaScript runtime",
5
5
  "keywords": [
6
6
  "apple",