rork-xcode 0.10.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/README.md CHANGED
@@ -100,7 +100,7 @@ const text = project.build();
100
100
 
101
101
  ### Targets and build settings
102
102
 
103
- `getBuildSetting` resolves hierarchically the way Xcode does: the target's default configuration first, then the project-level configuration. Writes go to every configuration of the target, so Debug and Release stay consistent.
103
+ `getBuildSetting` resolves hierarchically the way Xcode does, reading the target's default configuration first and the project-level configuration below it. Writes go to every configuration of the target, so Debug and Release stay consistent.
104
104
 
105
105
  ```ts
106
106
  const app = project.findMainAppTarget("ios"); // "macos" | "tvos" | "watchos" | "visionos"
@@ -114,6 +114,13 @@ for (const target of project.nativeTargets()) {
114
114
  }
115
115
  ```
116
116
 
117
+ `resolveBuildSetting` reads the same layers and expands the `$(NAME)` and `${NAME}` references in the value. Referenced settings resolve through the chain, `$(inherited)` continues from the next layer down, and `$(TARGET_NAME)` falls back to the target's name, so the template's `PRODUCT_NAME = "$(TARGET_NAME)"` resolves without any setup. References the document cannot answer (build-system paths like `$(BUILT_PRODUCTS_DIR)`) stay verbatim unless a caller-supplied lookup answers them, so nothing is invented.
118
+
119
+ ```ts
120
+ app?.resolveBuildSetting("PRODUCT_NAME"); // "DemoApp", from PRODUCT_NAME = "$(TARGET_NAME)"
121
+ app?.resolveBuildSetting("WIDGET_ID"); // "com.example.demo.widget", through PRODUCT_BUNDLE_IDENTIFIER
122
+ ```
123
+
117
124
  `project.targets()` returns every target kind. Aggregate targets (`PBXAggregateTarget`) and legacy external-build-tool targets (`PBXLegacyTarget`) share the full target surface, from configurations and build settings to phases and dependency wiring.
118
125
 
119
126
  ```ts
@@ -273,6 +280,27 @@ const text = scheme.build();
273
280
 
274
281
  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.
275
282
 
283
+ ## Workspaces
284
+
285
+ A `.xcworkspace` directory carries a `contents.xcworkspacedata` file listing the projects and folders the workspace shows, in the same XML dialect scheme files use, with the same round-trip contract. An Xcode-written file rebuilds byte for byte, any other input reaches the canonical layout in one build, and malformed input fails with a typed error carrying line and column.
286
+
287
+ `Xcworkspace` is the model. Its flagship read resolves which projects the workspace references, so tooling stops globbing directory trees and asks the file that already knows:
288
+
289
+ ```ts
290
+ import { Xcworkspace } from "rork-xcode";
291
+
292
+ const workspace = Xcworkspace.parse(xcworkspacedataText);
293
+
294
+ workspace.projectFilePaths(); // ["DemoApp.xcodeproj", "Pods/Pods.xcodeproj"]
295
+
296
+ workspace.addFileRef("group:Vendor/Vendor.xcodeproj");
297
+ const text = workspace.build();
298
+ ```
299
+
300
+ Group locations compose through their enclosing groups, container locations anchor at the workspace's directory, and absolute locations pass through. The resolution is textual, because the library never touches the filesystem, so locations only a running Xcode can resolve (`self` and `developer`) stay out of the list. `Xcworkspace.create` produces the document Xcode writes for a new workspace, file references come back as typed views through `fileRefs()`, and `parseXcworkspace` and `buildXcworkspace` remain available for working with the tree directly.
301
+
302
+ The other files inside a `.xcworkspace`, such as `WorkspaceSettings.xcsettings` and `IDEWorkspaceChecks.plist` under `xcshareddata`, are standard property lists rather than this dialect. [`rork-plist`](https://www.npmjs.com/package/rork-plist) parses and writes them with the same round-trip discipline, and the two libraries compose.
303
+
276
304
  ## Xcconfig files
277
305
 
278
306
  Build settings do not only live in the pbxproj. Projects push them into `.xcconfig` files referenced through `baseConfigurationReference`, and the xcconfig module reads and writes that format with the fidelity the rest of the library promises. The format is hand-authored with no canonical layout, so the contract here is losslessness. Parsing and building an untouched file reproduces it byte for byte, including comments, blank lines, column alignment, and line endings. Malformed lines fail loudly with a typed error carrying line and column rather than being dropped, so a file the parser accepts is a file it fully understood.
@@ -314,6 +342,24 @@ project.registerXcconfig(reference, Xcconfig.parse(text));
314
342
  app.getBuildSetting("SDKROOT"); // now sees values the xcconfig defines
315
343
  ```
316
344
 
345
+ ## Build-setting references
346
+
347
+ Values reference other build settings as `$(NAME)` and `${NAME}`, in the pbxproj, in xcconfig files, and in Info.plist templates. The syntax is Xcode's own, down to the `:` operators, and Xcode's app templates write values in exactly this shape, for example `PRODUCT_BUNDLE_IDENTIFIER = com.yourcompany.$(PRODUCT_NAME:rfc1034identifier)`. `expandBuildSettingReferences` evaluates the syntax through a caller-supplied lookup, so the same code serves all three formats. Substituted text expands recursively, names may themselves contain references (`$(SETTING_$(VARIANT))`), cycles stay finite, and a reference the lookup cannot answer stays verbatim, so partial resolution loses no information.
348
+
349
+ ```ts
350
+ import { expandBuildSettingReferences } from "rork-xcode";
351
+
352
+ // A value as found in a project file. The references and their operators
353
+ // are part of the document, so the expander takes them from the text
354
+ // rather than from options.
355
+ const found = "com.example.$(PRODUCT_NAME:rfc1034identifier)";
356
+
357
+ expandBuildSettingReferences(found, (name) => (name === "PRODUCT_NAME" ? "My App" : undefined));
358
+ // "com.example.My-App"
359
+ ```
360
+
361
+ The `:` operators are honored for `lower`, `upper`, `rfc1034identifier` (the mapping into RFC 1034 host-name characters that bundle identifiers need), `c99extidentifier`, and `default=`. A reference carrying any other operator stays verbatim rather than expanding to a wrongly transformed value. The model composes the expander with settings resolution as `target.resolveBuildSetting(key)`, described under [Targets and build settings](#targets-and-build-settings).
362
+
317
363
  ## Performance
318
364
 
319
365
  `rork-xcode` is measured against the pbxproj parsers on npm, [`@bacons/xcode`](https://www.npmjs.com/package/@bacons/xcode) (its `/json` parse/build entry point) and [`xcode`](https://www.npmjs.com/package/xcode) (the long-standing package used by native build tooling), on three documents: two real Xcode-written projects from the test suite and a deterministically generated five-target app with 800 source files. It is the fastest at both operations on every document, with zero dependencies.
@@ -331,6 +377,17 @@ app.getBuildSetting("SDKROOT"); // now sees values the xcconfig defines
331
377
  | build | app, Xcode 16 | **37.5 µs** | 113.6 µs (3.0×) | 71.3 µs (1.9×) |
332
378
  | build | generated app | **0.98 ms** | 85.98 ms (87.7×) | 1.20 ms (1.2×) |
333
379
 
380
+ The XML dialect files measure against `@bacons/xcode`, the one other npm package that parses and writes them (the `xcode` package has no scheme or workspace support):
381
+
382
+ | Operation | Document | `rork-xcode` | `@bacons/xcode` |
383
+ | --------- | --------------------------- | ------------ | --------------- |
384
+ | parse | app scheme (3.3 KiB) | **28.1 µs** | 108.7 µs (3.9×) |
385
+ | parse | actions scheme (5.8 KiB) | **46.7 µs** | 185.7 µs (4.0×) |
386
+ | parse | grouped workspace (0.7 KiB) | **4.7 µs** | 20.5 µs (4.3×) |
387
+ | build | app scheme | **7.1 µs** | 8.0 µs (1.1×) |
388
+ | build | actions scheme | **11.9 µs** | 13.8 µs (1.2×) |
389
+ | build | grouped workspace | **2.2 µs** | 3.0 µs (1.4×) |
390
+
334
391
  Measured on an Apple M5 Max, Node.js 24, single thread, with `@bacons/xcode` 1.0.0-alpha.33 and `xcode` 3.0.1. Multipliers are relative to `rork-xcode` on the same row; the ordering also holds on Bun. Reproduce with `pnpm bench:compare`, which interleaves the libraries in round-robin batches and reports the median, after verifying that every library round-trips every fixture.
335
392
 
336
393
  ### Key performance features
@@ -339,13 +396,14 @@ Measured on an Apple M5 Max, Node.js 24, single thread, with `@bacons/xcode` 1.0
339
396
  - **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.
340
397
  - **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.
341
398
  - **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.
399
+ - **Single-scan XML writing.** Attribute values pass one character-class test, and the near-universal value with nothing to escape returns as-is. The same machinery validates what XML cannot carry, and error paths are resolved only when a build actually fails, so correctness checks cost nothing on the happy path.
342
400
 
343
401
  ## Verification
344
402
 
345
403
  - The committed fixture corpus spans project generations from Xcode 3 to Xcode 16, captured from real projects with identifiers neutralized: synchronized folders with both exception-set kinds, classic groups, variant groups, aggregate and legacy targets, reference proxies, build rules, Swift packages, and a ~100 KiB multiplatform framework project.
346
404
  - Documents already in current Xcode's layout must round-trip byte for byte, and documents from other tool generations must normalize to a byte-stable fixed point with unchanged values.
347
405
  - On macOS, the suite cross-validates every fixture and its rebuilt form with `plutil`, Apple's own property list parser and the empirical ground truth for what Apple tooling accepts.
348
- - A corpus sweep (`pnpm corpus`) walks every Xcode project, scheme, and xcconfig on the machine, verifies each one parses and reaches a byte-stable fixed point (byte-exact losslessness for xcconfig, which has no canonical layout), exercises the object model against every project, and cross-validates a sample against plutil's own reading.
406
+ - A corpus sweep (`pnpm corpus`) walks every Xcode project, scheme, workspace, and xcconfig on the machine, verifies each one parses and reaches a byte-stable fixed point (byte-exact losslessness for xcconfig, which has no canonical layout), exercises the object model against every project, and cross-validates a sample against plutil's own reading.
349
407
  - CI runs the full gate on Linux and macOS, and executes the built artifact on the oldest supported Node to enforce the `engines` floor.
350
408
 
351
409
  ## Releasing
package/dist/index.d.ts CHANGED
@@ -82,13 +82,14 @@ declare function buildPbxproj(root: PbxprojObject): string;
82
82
  * @module
83
83
  */
84
84
  /**
85
- * Location of a parse failure inside the source text.
85
+ * Location of a parse failure inside the source text, shared by every
86
+ * parse error the library throws.
86
87
  *
87
88
  * Offsets count UTF-16 code units from the start of the string (the same
88
89
  * units `String.prototype.slice` uses), so editors and log tooling can jump
89
90
  * straight to the failure.
90
91
  */
91
- interface PbxprojErrorPosition {
92
+ interface TextPosition {
92
93
  /** Zero-based character offset into the source string. */
93
94
  offset: number;
94
95
  /** One-based line number. */
@@ -96,6 +97,12 @@ interface PbxprojErrorPosition {
96
97
  /** One-based column number, in characters from the start of the line. */
97
98
  column: number;
98
99
  }
100
+ /**
101
+ * The name {@link TextPosition} carried before the scheme, workspace, and
102
+ * xcconfig parsers shared it. Kept as an alias so existing annotations
103
+ * keep compiling.
104
+ */
105
+ type PbxprojErrorPosition = TextPosition;
99
106
  /**
100
107
  * Thrown when the source text is not a well-formed OpenStep-style property
101
108
  * list (the format of `project.pbxproj` files).
@@ -106,7 +113,7 @@ interface PbxprojErrorPosition {
106
113
  */
107
114
  declare class PbxprojParseError extends Error {
108
115
  /** Where in the source text parsing failed. */
109
- readonly position: PbxprojErrorPosition;
116
+ readonly position: TextPosition;
110
117
  /**
111
118
  * @param message Failure description without location. The location is
112
119
  * appended automatically.
@@ -125,7 +132,26 @@ declare class PbxprojParseError extends Error {
125
132
  */
126
133
  declare class XcschemeParseError extends Error {
127
134
  /** Where in the source text parsing failed. */
128
- readonly position: PbxprojErrorPosition;
135
+ readonly position: TextPosition;
136
+ /**
137
+ * @param message Failure description without location. The location is
138
+ * appended automatically.
139
+ * @param source Full source text, used to compute the position.
140
+ * @param offset Character offset of the failure inside `source`.
141
+ */
142
+ constructor(message: string, source: string, offset: number);
143
+ }
144
+ /**
145
+ * Thrown when the source text is not a well-formed workspace data file
146
+ * (the XML dialect of `contents.xcworkspacedata` files).
147
+ *
148
+ * The message always embeds the line and column of the failure, and the
149
+ * same information is available in structured form on {@link position}
150
+ * for programmatic use.
151
+ */
152
+ declare class XcworkspaceParseError extends Error {
153
+ /** Where in the source text parsing failed. */
154
+ readonly position: TextPosition;
129
155
  /**
130
156
  * @param message Failure description without location. The location is
131
157
  * appended automatically.
@@ -144,7 +170,7 @@ declare class XcschemeParseError extends Error {
144
170
  */
145
171
  declare class XcconfigParseError extends Error {
146
172
  /** Where in the source text parsing failed. */
147
- readonly position: PbxprojErrorPosition;
173
+ readonly position: TextPosition;
148
174
  /**
149
175
  * @param message Failure description without location. The location is
150
176
  * appended automatically.
@@ -170,6 +196,23 @@ declare class XcschemeBuildError extends Error {
170
196
  */
171
197
  constructor(message: string, path: string);
172
198
  }
199
+ /**
200
+ * Thrown when a workspace element cannot be written as XML.
201
+ *
202
+ * Raised for element and attribute names that are not valid XML names and
203
+ * for attribute values carrying control characters XML 1.0 cannot encode.
204
+ * The {@link path} pinpoints the offending element inside the tree.
205
+ */
206
+ declare class XcworkspaceBuildError extends Error {
207
+ /** Path to the offending element from the root, e.g. `Workspace.FileRef[0]`. */
208
+ readonly path: string;
209
+ /**
210
+ * @param message Failure description without location. The element path
211
+ * is appended automatically.
212
+ * @param path Path to the offending element from the root.
213
+ */
214
+ constructor(message: string, path: string);
215
+ }
173
216
  /**
174
217
  * Thrown by the object model when an operation cannot proceed, because the
175
218
  * document lacks the structure the operation needs (no objects dictionary,
@@ -207,6 +250,73 @@ declare class PbxprojBuildError extends Error {
207
250
  constructor(message: string, path: string);
208
251
  }
209
252
  //#endregion
253
+ //#region src/expansion.d.ts
254
+ /**
255
+ * Expansion of `$(NAME)` and `${NAME}` build-setting references.
256
+ *
257
+ * Values in the pbxproj, in xcconfig files, and in Info.plist templates
258
+ * reference other build settings, and every consumer that needs the
259
+ * resolved string ends up re-implementing the substitution informally.
260
+ * The expander here is a pure function over a caller-supplied lookup, so
261
+ * the same code serves all three formats. The model composes it with
262
+ * settings resolution in `Target.resolveBuildSetting`.
263
+ *
264
+ * @module
265
+ */
266
+ /**
267
+ * The value a reference expands to, or `undefined` to leave the
268
+ * reference in place. Returning the empty string expands to nothing,
269
+ * which is how Xcode itself treats settings that exist but are empty.
270
+ */
271
+ type BuildSettingLookup = (name: string) => string | undefined;
272
+ interface ExpandBuildSettingOptions {
273
+ /**
274
+ * Whether lookup answers are expanded again, which is the default and
275
+ * suits lookups reading raw stored values. A lookup that resolves
276
+ * references itself, like the model's layered resolution, turns this
277
+ * off so text it deliberately left verbatim is not reinterpreted in
278
+ * the outer value's context.
279
+ */
280
+ expandLookupValues?: boolean;
281
+ }
282
+ /**
283
+ * Expands every `$(NAME)` and `${NAME}` reference in a value through the
284
+ * lookup. Substituted text is expanded again, so references are followed
285
+ * through chains of values, and reference names may themselves contain
286
+ * references (`$(SETTING_$(VARIANT))`), which expand innermost first.
287
+ *
288
+ * A lookup answer of `undefined` leaves the reference in the output
289
+ * verbatim, so partial resolution loses no information. A reference
290
+ * whose expansion would recurse into itself also stays verbatim, which
291
+ * keeps cyclic definitions finite. Xcode's `:` operators are honored for
292
+ * the forms below, and a reference carrying any other operator stays
293
+ * verbatim rather than expanding to a wrongly transformed value.
294
+ *
295
+ * The supported operators are `lower` and `upper` for case mapping,
296
+ * `rfc1034identifier` and `c99extidentifier` for the identifier
297
+ * mappings bundle identifiers and product module names use, and
298
+ * `default=value` for substituting a fallback when the setting resolves
299
+ * empty or is not known to the lookup.
300
+ */
301
+ declare function expandBuildSettingReferences(value: string, lookup: BuildSettingLookup, options?: ExpandBuildSettingOptions): string;
302
+ /**
303
+ * The transforming operators the expander supports, keyed by the name
304
+ * they are written with. `default=` is not listed because it carries an
305
+ * argument and substitutes rather than transforms, so the reference
306
+ * expansion handles it structurally.
307
+ */
308
+ declare const OPERATOR_TRANSFORMS: {
309
+ c99extidentifier: (value: string) => string;
310
+ lower: (value: string) => string;
311
+ rfc1034identifier: (value: string) => string;
312
+ upper: (value: string) => string;
313
+ };
314
+ /**
315
+ * A transforming operator name honored in `$(NAME:operator)` references,
316
+ * alongside the structural `default=`.
317
+ */
318
+ type BuildSettingOperator = keyof typeof OPERATOR_TRANSFORMS;
319
+ //#endregion
210
320
  //#region src/model/isa.d.ts
211
321
  /**
212
322
  * Names and well-known values of the pbxproj object vocabulary.
@@ -593,6 +703,16 @@ interface BuildStyleProperties extends PbxprojObject {
593
703
  }
594
704
  //#endregion
595
705
  //#region src/model/target.d.ts
706
+ interface ResolveBuildSettingOptions {
707
+ /**
708
+ * Answers references the document itself cannot, for example
709
+ * `$(BUILT_PRODUCTS_DIR)` when the caller knows the build layout. The
710
+ * lookup is consulted after the setting layers and before the built-in
711
+ * `$(TARGET_NAME)` fallback, and a reference it leaves unanswered
712
+ * stays verbatim in the result.
713
+ */
714
+ lookup?: BuildSettingLookup;
715
+ }
596
716
  /**
597
717
  * The behavior every target kind shares. A target of any kind carries
598
718
  * build configurations and settings, build phases, and dependencies, and
@@ -637,6 +757,22 @@ declare class Target<Properties extends TargetProperties = TargetProperties> ext
637
757
  * reads as `undefined`.
638
758
  */
639
759
  getBuildSetting(key: string): string | undefined;
760
+ /**
761
+ * Reads a build setting like {@link getBuildSetting} and expands the
762
+ * `$(NAME)` and `${NAME}` references in it. Referenced settings resolve
763
+ * through the same layering, `$(inherited)` and a setting referencing
764
+ * itself continue from the next layer down the way Xcode composes
765
+ * values, and `$(TARGET_NAME)` falls back to the target's name, so the
766
+ * common `PRODUCT_NAME = "$(TARGET_NAME)"` resolves without any caller
767
+ * setup.
768
+ *
769
+ * References the model cannot resolve (build-system paths like
770
+ * `$(BUILT_PRODUCTS_DIR)`, environment values) stay in the result
771
+ * verbatim unless the caller's lookup answers them, so no information
772
+ * is invented. See {@link expandBuildSettingReferences} for the
773
+ * operator forms honored during expansion.
774
+ */
775
+ resolveBuildSetting(key: string, options?: ResolveBuildSettingOptions): string | undefined;
640
776
  /**
641
777
  * Writes a build setting on every configuration of the target, so Debug
642
778
  * and Release stay consistent.
@@ -2033,61 +2169,100 @@ declare class XcodeObject<Properties extends PbxprojObject = PbxprojObject> {
2033
2169
  */
2034
2170
  declare function parsePbxproj(text: string): PbxprojValue;
2035
2171
  //#endregion
2036
- //#region src/scheme/types.d.ts
2172
+ //#region src/xml/types.d.ts
2037
2173
  /**
2038
- * The node model of a scheme document.
2174
+ * The node model of Xcode's XML dialect, shared by scheme files
2175
+ * (`.xcscheme`) and workspace data files (`contents.xcworkspacedata`).
2039
2176
  *
2040
- * A parsed `.xcscheme` is a tree of plain objects. Elements carry ordered
2177
+ * A parsed document is a tree of plain objects. Elements carry ordered
2041
2178
  * attributes and child nodes, and comments survive as their own nodes.
2042
2179
  * All state lives in this tree. There is no wrapper to keep in sync, so
2043
- * callers mutate nodes directly and serialize whatever the tree currently
2044
- * says.
2180
+ * callers mutate nodes directly and serialize whatever the tree
2181
+ * currently says.
2045
2182
  *
2046
2183
  * @module
2047
2184
  */
2048
2185
  /**
2049
- * An XML element of a scheme document.
2186
+ * An XML element of a document.
2050
2187
  *
2051
2188
  * Attribute order is preserved and meaningful. The writer emits
2052
2189
  * attributes in insertion order, which is how Xcode-written files
2053
2190
  * round-trip byte-identically. Assigning an existing key keeps its
2054
2191
  * position, and adding a new key appends it.
2055
2192
  */
2056
- interface XcschemeElement {
2057
- /** Tag name, for example `Scheme` or `BuildableReference`. */
2193
+ interface XmlElement {
2194
+ /** Tag name, for example `Scheme` or `FileRef`. */
2058
2195
  name: string;
2059
2196
  /** Attribute values by name, in document order. */
2060
2197
  attributes: Record<string, string>;
2061
2198
  /** Child elements and comments, in document order. */
2062
- children: XcschemeNode[];
2199
+ children: XmlNode[];
2063
2200
  }
2064
2201
  /**
2065
- * A comment inside a scheme document. Xcode never writes comments, but
2066
- * hand-edited and tool-generated schemes can carry them, and dropping
2067
- * them would make round-trips lossy.
2202
+ * A comment inside a document. Xcode never writes comments, but
2203
+ * hand-edited and tool-generated files can carry them, and dropping them
2204
+ * would make round-trips lossy.
2068
2205
  */
2069
- interface XcschemeComment {
2206
+ interface XmlComment {
2070
2207
  /** The comment text between `<!--` and `-->`, verbatim. */
2071
2208
  comment: string;
2072
2209
  }
2210
+ /**
2211
+ * Any node an element can contain.
2212
+ */
2213
+ type XmlNode = XmlElement | XmlComment;
2214
+ /**
2215
+ * A parsed document, made of its root element plus any comments sitting
2216
+ * outside it. Xcode writes only the root, so the comment lists are
2217
+ * almost always empty, but files that carry them round-trip without
2218
+ * loss.
2219
+ */
2220
+ interface XmlDocument {
2221
+ /** Comments before the root element. */
2222
+ leading: XmlComment[];
2223
+ /** The root element. */
2224
+ root: XmlElement;
2225
+ /** Comments after the root element. */
2226
+ trailing: XmlComment[];
2227
+ }
2228
+ /**
2229
+ * Whether a node is an element rather than a comment.
2230
+ */
2231
+ declare function isXmlElement(node: XmlNode): node is XmlElement;
2232
+ /**
2233
+ * Collects elements of the given name anywhere under a root, in document
2234
+ * order, root included. Passing no name collects every element. Scheme
2235
+ * and workspace models both build their typed views over this query.
2236
+ */
2237
+ declare function xmlElements(root: XmlElement, name?: string): XmlElement[];
2238
+ //#endregion
2239
+ //#region src/scheme/types.d.ts
2240
+ /**
2241
+ * An XML element of a scheme document.
2242
+ *
2243
+ * Attribute order is preserved and meaningful. The writer emits
2244
+ * attributes in insertion order, which is how Xcode-written files
2245
+ * round-trip byte-identically. Assigning an existing key keeps its
2246
+ * position, and adding a new key appends it.
2247
+ */
2248
+ type XcschemeElement = XmlElement;
2249
+ /**
2250
+ * A comment inside a scheme document. Xcode never writes comments, but
2251
+ * hand-edited and tool-generated schemes can carry them, and dropping
2252
+ * them would make round-trips lossy.
2253
+ */
2254
+ type XcschemeComment = XmlComment;
2073
2255
  /**
2074
2256
  * Any node a scheme element can contain.
2075
2257
  */
2076
- type XcschemeNode = XcschemeElement | XcschemeComment;
2258
+ type XcschemeNode = XmlNode;
2077
2259
  /**
2078
2260
  * A parsed scheme file, made of its root element plus any comments
2079
2261
  * sitting outside it. Xcode writes only the root, so the comment lists
2080
2262
  * are almost always empty, but files that carry them round-trip without
2081
2263
  * loss.
2082
2264
  */
2083
- interface XcschemeDocument {
2084
- /** Comments before the root element. */
2085
- leading: XcschemeComment[];
2086
- /** The `Scheme` element. */
2087
- root: XcschemeElement;
2088
- /** Comments after the root element. */
2089
- trailing: XcschemeComment[];
2090
- }
2265
+ type XcschemeDocument = XmlDocument;
2091
2266
  /**
2092
2267
  * Whether a node is an element rather than a comment.
2093
2268
  */
@@ -2095,7 +2270,8 @@ declare function isXcschemeElement(node: XcschemeNode): node is XcschemeElement;
2095
2270
  //#endregion
2096
2271
  //#region src/scheme/build.d.ts
2097
2272
  /**
2098
- * Serializes a scheme document to the text of a `.xcscheme` file.
2273
+ * Serializes a scheme document to the text of a `.xcscheme` file in
2274
+ * Xcode's canonical layout.
2099
2275
  *
2100
2276
  * @throws XcschemeBuildError for element or attribute names that are not
2101
2277
  * XML names and for attribute values carrying unencodable control
@@ -2280,6 +2456,147 @@ declare function parseXcscheme(text: string): XcschemeDocument;
2280
2456
  */
2281
2457
  declare function generateObjectId(seed: string, existing: ReadonlySet<string>): string;
2282
2458
  //#endregion
2459
+ //#region src/workspace/build.d.ts
2460
+ /**
2461
+ * Serializes a workspace document to the text of a
2462
+ * `contents.xcworkspacedata` file in Xcode's canonical layout.
2463
+ *
2464
+ * @throws XcworkspaceBuildError for element or attribute names that are
2465
+ * not XML names and for attribute values carrying unencodable control
2466
+ * characters, with the path of the offending node.
2467
+ */
2468
+ declare function buildXcworkspace(document: XmlDocument): string;
2469
+ //#endregion
2470
+ //#region src/workspace/model.d.ts
2471
+ /**
2472
+ * A workspace location string split at its kind prefix, so
2473
+ * `group:Pods/Pods.xcodeproj` reads as the kind `group` and the path
2474
+ * `Pods/Pods.xcodeproj`. A location without a kind prefix reads as
2475
+ * `group`, which is how Xcode treats a bare path.
2476
+ */
2477
+ interface WorkspaceLocation {
2478
+ /** The anchor the path is relative to, for example `group`. */
2479
+ kind: string;
2480
+ /** The path after the kind prefix. */
2481
+ path: string;
2482
+ }
2483
+ /**
2484
+ * Splits a location attribute into its kind and path. Xcode writes the
2485
+ * kinds `group` (relative to the enclosing group), `container` (relative
2486
+ * to the directory containing the `.xcworkspace`), `absolute`, `self`
2487
+ * (the containing `.xcodeproj` itself), and `developer` (inside the
2488
+ * developer directory).
2489
+ */
2490
+ declare function parseWorkspaceLocation(location: string): WorkspaceLocation;
2491
+ /**
2492
+ * A `FileRef` element with property-style attribute access. File
2493
+ * references are the elements workspace edits touch, since each one
2494
+ * names a project or folder the workspace shows. The view reads and
2495
+ * writes the element's attributes directly, so it never goes stale and
2496
+ * needs no separate save step.
2497
+ */
2498
+ declare class WorkspaceFileRef {
2499
+ /** The underlying element inside the document tree. */
2500
+ readonly element: XmlElement;
2501
+ constructor(element: XmlElement);
2502
+ /**
2503
+ * The reference's location attribute, when present, for example
2504
+ * `group:Pods/Pods.xcodeproj`.
2505
+ */
2506
+ get location(): string | undefined;
2507
+ set location(value: string);
2508
+ }
2509
+ interface CreateXcworkspaceOptions {
2510
+ /**
2511
+ * The location of each file reference the workspace lists, in order,
2512
+ * for example `group:DemoApp.xcodeproj`. An omitted list creates an
2513
+ * empty workspace to add references to.
2514
+ */
2515
+ locations?: string[];
2516
+ }
2517
+ /**
2518
+ * A workspace document with typed access to the elements editing flows
2519
+ * touch.
2520
+ *
2521
+ * The model is a thin layer over the node tree. All state lives in the
2522
+ * document itself, and {@link build} serializes whatever the tree
2523
+ * currently says, so typed edits and direct tree edits compose freely.
2524
+ *
2525
+ * ```ts
2526
+ * const workspace = Xcworkspace.parse(xcworkspacedataText);
2527
+ * workspace.projectFilePaths(); // ["DemoApp.xcodeproj", "Pods/Pods.xcodeproj"]
2528
+ * ```
2529
+ */
2530
+ declare class Xcworkspace {
2531
+ /** The underlying parsed document. */
2532
+ readonly document: XmlDocument;
2533
+ constructor(document: XmlDocument);
2534
+ /**
2535
+ * Parses the text of a `contents.xcworkspacedata` file into a
2536
+ * workspace model.
2537
+ *
2538
+ * @throws XcworkspaceParseError when the text is not a well-formed
2539
+ * workspace document, with the line and column of the failure.
2540
+ */
2541
+ static parse(text: string): Xcworkspace;
2542
+ /**
2543
+ * Creates the workspace document Xcode writes, listing the given
2544
+ * locations as file references.
2545
+ */
2546
+ static create(options?: CreateXcworkspaceOptions): Xcworkspace;
2547
+ /**
2548
+ * The document's `Workspace` element.
2549
+ */
2550
+ get root(): XmlElement;
2551
+ /**
2552
+ * Serializes the workspace to the text of a `contents.xcworkspacedata`
2553
+ * file in Xcode's canonical layout.
2554
+ */
2555
+ build(): string;
2556
+ /**
2557
+ * Collects elements of the given name anywhere in the document, in
2558
+ * document order. Passing no name collects every element.
2559
+ */
2560
+ elements(name?: string): XmlElement[];
2561
+ /**
2562
+ * The views of every file reference in the document, in document
2563
+ * order, references nested inside groups included.
2564
+ */
2565
+ fileRefs(): WorkspaceFileRef[];
2566
+ /**
2567
+ * Appends a file reference to the workspace's top level and returns
2568
+ * its view.
2569
+ */
2570
+ addFileRef(location: string): WorkspaceFileRef;
2571
+ /**
2572
+ * Removes a file reference from whichever element holds it. Returns
2573
+ * whether the reference was found and removed.
2574
+ */
2575
+ removeFileRef(reference: WorkspaceFileRef): boolean;
2576
+ /**
2577
+ * The paths of every `.xcodeproj` the workspace references, in
2578
+ * document order, resolved relative to the directory containing the
2579
+ * `.xcworkspace`. Group locations compose through their enclosing
2580
+ * groups, container locations anchor at the workspace's directory, and
2581
+ * absolute locations pass through unchanged.
2582
+ *
2583
+ * The resolution is textual. The library never touches the
2584
+ * filesystem, so locations that only the running Xcode can resolve
2585
+ * (`self` and `developer`) are not listed.
2586
+ */
2587
+ projectFilePaths(): string[];
2588
+ }
2589
+ //#endregion
2590
+ //#region src/workspace/parse.d.ts
2591
+ /**
2592
+ * Parses the text of a `contents.xcworkspacedata` file into its node
2593
+ * tree.
2594
+ *
2595
+ * @throws XcworkspaceParseError when the text is not a well-formed
2596
+ * workspace document, with the line and column of the failure.
2597
+ */
2598
+ declare function parseXcworkspace(text: string): XmlDocument;
2599
+ //#endregion
2283
2600
  //#region src/xcconfig/build.d.ts
2284
2601
  /**
2285
2602
  * Serializes a document back to `.xcconfig` text.
@@ -2296,4 +2613,4 @@ declare function buildXcconfig(document: XcconfigDocument): string;
2296
2613
  */
2297
2614
  declare function parseXcconfig(source: string): XcconfigDocument;
2298
2615
  //#endregion
2299
- export { type AddNativeTargetOptions, AggregateTarget, type ApplePlatform, AppleScriptBuildPhase, BuildConfiguration, type BuildConfigurationProperties, BuildFile, BuildFileExceptionSet, type BuildFileProperties, BuildPhase, type BuildPhaseIsa, BuildPhaseMembershipExceptionSet, type BuildPhaseMembershipExceptionSetProperties, type BuildPhaseOf, type BuildPhaseProperties, BuildRule, type BuildRuleProperties, type BuildSettings, BuildStyle, type BuildStyleProperties, BuildableReference, ConfigurationList, type ConfigurationListProperties, ContainerItemProxy, type ContainerItemProxyProperties, CopyFilesBuildPhase, type CopyFilesBuildPhaseProperties, CopyFilesDestination, type CreateXcschemeOptions, ExceptionSet, type ExceptionSetProperties, FileReference, type FileReferenceProperties, FrameworksBuildPhase, Group, type GroupProperties, HeadersBuildPhase, Isa, type IsaValue, LegacyTarget, type LegacyTargetProperties, LocalSwiftPackageReference, type LocalSwiftPackageReferenceProperties, NativeTarget, type NativeTargetProperties, type PbxprojArray, PbxprojBuildError, type PbxprojErrorPosition, type PbxprojObject, PbxprojParseError, type PbxprojValue, ProductType, type ProjectIssue, type ProjectIssueKind, ReferenceProxy, type ReferenceProxyProperties, RemoteSwiftPackageReference, type RemoteSwiftPackageReferenceProperties, ResourcesBuildPhase, RezBuildPhase, RootProject, type RootProjectProperties, ShellScriptBuildPhase, type ShellScriptBuildPhaseProperties, SourcesBuildPhase, SwiftPackageProductDependency, type SwiftPackageProductDependencyProperties, SwiftPackageReference, type SwiftPackageReferenceProperties, SyncRootGroup, type SyncRootGroupProperties, Target, TargetDependency, type TargetDependencyProperties, type TargetProperties, VariantGroup, VersionGroup, type VersionGroupProperties, type ViewByIsa, type ViewOf, Xcconfig, type XcconfigAssignment, type XcconfigBlank, type XcconfigComment, type XcconfigCondition, type XcconfigDocument, type XcconfigInclude, type XcconfigIncludeResolver, XcconfigParseError, type XcconfigSettingsOptions, type XcconfigStatement, XcodeModelError, XcodeObject, XcodeProject, Xcscheme, XcschemeBuildError, type XcschemeComment, type XcschemeDocument, type XcschemeElement, type XcschemeNode, XcschemeParseError, buildPbxproj, buildXcconfig, buildXcscheme, createXcscheme, generateObjectId, isXcschemeElement, parseApplePlatform, parsePbxproj, parseXcconfig, parseXcscheme, xcschemeElements };
2616
+ export { type AddNativeTargetOptions, AggregateTarget, type ApplePlatform, AppleScriptBuildPhase, BuildConfiguration, type BuildConfigurationProperties, BuildFile, BuildFileExceptionSet, type BuildFileProperties, BuildPhase, type BuildPhaseIsa, BuildPhaseMembershipExceptionSet, type BuildPhaseMembershipExceptionSetProperties, type BuildPhaseOf, type BuildPhaseProperties, BuildRule, type BuildRuleProperties, type BuildSettingLookup, type BuildSettingOperator, type BuildSettings, BuildStyle, type BuildStyleProperties, BuildableReference, ConfigurationList, type ConfigurationListProperties, ContainerItemProxy, type ContainerItemProxyProperties, CopyFilesBuildPhase, type CopyFilesBuildPhaseProperties, CopyFilesDestination, type CreateXcschemeOptions, type CreateXcworkspaceOptions, ExceptionSet, type ExceptionSetProperties, type ExpandBuildSettingOptions, FileReference, type FileReferenceProperties, FrameworksBuildPhase, Group, type GroupProperties, HeadersBuildPhase, Isa, type IsaValue, LegacyTarget, type LegacyTargetProperties, LocalSwiftPackageReference, type LocalSwiftPackageReferenceProperties, NativeTarget, type NativeTargetProperties, type PbxprojArray, PbxprojBuildError, type PbxprojErrorPosition, type PbxprojObject, PbxprojParseError, type PbxprojValue, ProductType, type ProjectIssue, type ProjectIssueKind, ReferenceProxy, type ReferenceProxyProperties, RemoteSwiftPackageReference, type RemoteSwiftPackageReferenceProperties, type ResolveBuildSettingOptions, ResourcesBuildPhase, RezBuildPhase, RootProject, type RootProjectProperties, ShellScriptBuildPhase, type ShellScriptBuildPhaseProperties, SourcesBuildPhase, SwiftPackageProductDependency, type SwiftPackageProductDependencyProperties, SwiftPackageReference, type SwiftPackageReferenceProperties, SyncRootGroup, type SyncRootGroupProperties, Target, TargetDependency, type TargetDependencyProperties, type TargetProperties, type TextPosition, VariantGroup, VersionGroup, type VersionGroupProperties, type ViewByIsa, type ViewOf, WorkspaceFileRef, type WorkspaceLocation, Xcconfig, type XcconfigAssignment, type XcconfigBlank, type XcconfigComment, type XcconfigCondition, type XcconfigDocument, type XcconfigInclude, type XcconfigIncludeResolver, XcconfigParseError, type XcconfigSettingsOptions, type XcconfigStatement, XcodeModelError, XcodeObject, XcodeProject, Xcscheme, XcschemeBuildError, type XcschemeComment, type XcschemeDocument, type XcschemeElement, type XcschemeNode, XcschemeParseError, Xcworkspace, XcworkspaceBuildError, XcworkspaceParseError, type XmlComment, type XmlDocument, type XmlElement, type XmlNode, buildPbxproj, buildXcconfig, buildXcscheme, buildXcworkspace, createXcscheme, expandBuildSettingReferences, generateObjectId, isXcschemeElement, isXmlElement, parseApplePlatform, parsePbxproj, parseWorkspaceLocation, parseXcconfig, parseXcscheme, parseXcworkspace, xcschemeElements, xmlElements };