rork-xcode 0.8.0 → 0.9.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
@@ -266,6 +266,47 @@ const text = scheme.build();
266
266
 
267
267
  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.
268
268
 
269
+ ## Xcconfig files
270
+
271
+ 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 — comments, blank lines, column alignment, and line endings included. 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.
272
+
273
+ `Xcconfig` is the model. Reads follow the file top to bottom the way Xcode does, and writes edit single lines while leaving every other byte alone:
274
+
275
+ ```ts
276
+ import { Xcconfig } from "rork-xcode";
277
+
278
+ const config = Xcconfig.parse(xcconfigText);
279
+
280
+ config.get("PRODUCT_BUNDLE_IDENTIFIER"); // last unconditional assignment wins
281
+ config.set("MARKETING_VERSION", "1.2.0"); // rewrites in place, appends when new
282
+ const settings = config.settings(); // flattened, the way Xcode reads the file
283
+
284
+ const text = config.build();
285
+ ```
286
+
287
+ `#include` directives are exposed as data because the library never touches the filesystem. Flattening resolves them through a caller-supplied lookup and applies each file at its directive's position, cycle-safe, so lines after an include override it exactly like textual inclusion. Position matters: an include hoisted or reordered changes what the file means, so the model never moves one.
288
+
289
+ ```ts
290
+ const settings = config.settings({
291
+ resolveInclude: (path, optional) => loadedConfigs.get(path),
292
+ });
293
+ ```
294
+
295
+ Conditional assignments like `OTHER_LDFLAGS[sdk=iphoneos*][arch=arm64]` are parsed structurally with their conditions preserved verbatim on round-trip, unknown condition names included. Passing a build context applies them during flattening, with every condition required to match and trailing `*` wildcards honored; without a context they stay out, which mirrors reading the file with no build in mind. `$(inherited)` references splice in the value accumulated earlier in the chain and stay literal when there is none, so lower layers can still resolve them:
296
+
297
+ ```ts
298
+ const settings = config.settings({
299
+ context: { sdk: "iphoneos", arch: "arm64", config: "Release" },
300
+ });
301
+ ```
302
+
303
+ Registering a file on the project makes `getBuildSetting` resolve through it in Xcode's order — target settings, the target's xcconfig, project settings, the project's xcconfig:
304
+
305
+ ```ts
306
+ project.registerXcconfig(reference, Xcconfig.parse(text));
307
+ app.getBuildSetting("SDKROOT"); // now sees values the xcconfig defines
308
+ ```
309
+
269
310
  ## Performance
270
311
 
271
312
  `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.
@@ -297,7 +338,7 @@ Measured on an Apple M5 Max, Node.js 24, single thread, with `@bacons/xcode` 1.0
297
338
  - 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.
298
339
  - Documents already in current Xcode's layout must round-trip byte for byte; documents from other tool generations must normalize to a byte-stable fixed point with unchanged values.
299
340
  - 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.
300
- - A corpus sweep (`pnpm corpus`) walks every Xcode project and scheme on the machine, verifies each one parses and reaches a byte-stable fixed point, exercises the object model against every project, and cross-validates a sample against plutil's own reading.
341
+ - 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.
301
342
  - CI runs the full gate on Linux and macOS, and executes the built artifact on the oldest supported Node to enforce the `engines` floor.
302
343
 
303
344
  ## Releasing
package/dist/index.d.ts CHANGED
@@ -133,6 +133,25 @@ declare class XcschemeParseError extends Error {
133
133
  */
134
134
  constructor(message: string, source: string, offset: number);
135
135
  }
136
+ /**
137
+ * Thrown when the source text is not a well-formed build configuration
138
+ * file (the line-based format of `.xcconfig` files).
139
+ *
140
+ * The message always embeds the line and column of the failure, and the
141
+ * same information is available in structured form on {@link position}
142
+ * for programmatic use.
143
+ */
144
+ declare class XcconfigParseError extends Error {
145
+ /** Where in the source text parsing failed. */
146
+ readonly position: PbxprojErrorPosition;
147
+ /**
148
+ * @param message Failure description without location; the location is
149
+ * appended automatically.
150
+ * @param source Full source text, used to compute the position.
151
+ * @param offset Character offset of the failure inside `source`.
152
+ */
153
+ constructor(message: string, source: string, offset: number);
154
+ }
136
155
  /**
137
156
  * Thrown when a scheme element cannot be written as XML.
138
157
  *
@@ -608,6 +627,11 @@ declare class Target<Properties extends TargetProperties = TargetProperties> ext
608
627
  * generated app templates set values like `SDKROOT` only at the project
609
628
  * level.
610
629
  *
630
+ * Configurations based on `.xcconfig` files take part once the files
631
+ * are registered through {@link XcodeProject.registerXcconfig}, in
632
+ * Xcode's order: target settings, the target's xcconfig, project
633
+ * settings, the project's xcconfig.
634
+ *
611
635
  * Only string values are returned; a list- or number-valued setting reads
612
636
  * as `undefined`.
613
637
  */
@@ -1128,6 +1152,13 @@ declare class BuildConfiguration extends XcodeObject<BuildConfigurationPropertie
1128
1152
  * document.
1129
1153
  */
1130
1154
  get buildSettings(): BuildSettings | undefined;
1155
+ /**
1156
+ * The view of the `.xcconfig` file reference this configuration is
1157
+ * based on, when the configuration has one and it resolves. The file's
1158
+ * settings sit below the configuration's own `buildSettings` in
1159
+ * Xcode's resolution order.
1160
+ */
1161
+ baseConfigurationReference(): FileReference | undefined;
1131
1162
  }
1132
1163
  /**
1133
1164
  * A `PBXBuildStyle` is the pre-Xcode-2 predecessor of
@@ -1270,6 +1301,227 @@ declare class ReferenceProxy extends XcodeObject<ReferenceProxyProperties> {
1270
1301
  remoteReference(): ContainerItemProxy | undefined;
1271
1302
  }
1272
1303
  //#endregion
1304
+ //#region src/xcconfig/types.d.ts
1305
+ /**
1306
+ * Document types for Xcode build configuration files (`.xcconfig`).
1307
+ *
1308
+ * The format is line based, so the document is the ordered list of parsed
1309
+ * lines. Every statement keeps the exact text it was parsed from (`raw`)
1310
+ * and its line terminator (`eol`), which is what lets an untouched
1311
+ * document rebuild byte for byte even though the format is hand-authored
1312
+ * and has no canonical layout.
1313
+ *
1314
+ * @module
1315
+ */
1316
+ /**
1317
+ * One `[name=value]` condition attached to a setting assignment, as in
1318
+ * `LDFLAGS[sdk=iphoneos*] = -lfoo`.
1319
+ */
1320
+ interface XcconfigCondition {
1321
+ /** The condition name, for example `sdk`, `arch`, or `config`. */
1322
+ name: string;
1323
+ /** The condition value, which may carry a trailing `*` wildcard. */
1324
+ value: string;
1325
+ }
1326
+ /**
1327
+ * A `KEY = value` line, optionally with conditions between the key and
1328
+ * the equals sign. The value has surrounding whitespace, an optional
1329
+ * trailing semicolon, and any trailing `//` comment removed.
1330
+ */
1331
+ interface XcconfigAssignment {
1332
+ kind: "assignment";
1333
+ /** The setting name. */
1334
+ key: string;
1335
+ /** The `[name=value]` conditions, in written order. Usually empty. */
1336
+ conditions: readonly XcconfigCondition[];
1337
+ /** The assigned value with comment, semicolon, and padding stripped. */
1338
+ value: string;
1339
+ /** The exact source line, without its terminator. */
1340
+ raw: string;
1341
+ /** The line terminator, `"\n"`, `"\r\n"`, or `""` on a final line. */
1342
+ eol: string;
1343
+ }
1344
+ /**
1345
+ * An `#include "path"` line. The optional form `#include? "path"` tells
1346
+ * Xcode to ignore a missing file, and callers should mirror that when
1347
+ * resolving includes.
1348
+ */
1349
+ interface XcconfigInclude {
1350
+ kind: "include";
1351
+ /** The include path exactly as written between the quotes. */
1352
+ path: string;
1353
+ /** True for the `#include?` form. */
1354
+ optional: boolean;
1355
+ /** The exact source line, without its terminator. */
1356
+ raw: string;
1357
+ /** The line terminator, `"\n"`, `"\r\n"`, or `""` on a final line. */
1358
+ eol: string;
1359
+ }
1360
+ /**
1361
+ * A line holding only a `//` comment.
1362
+ */
1363
+ interface XcconfigComment {
1364
+ kind: "comment";
1365
+ /** The comment text after `//`, untrimmed. */
1366
+ text: string;
1367
+ /** The exact source line, without its terminator. */
1368
+ raw: string;
1369
+ /** The line terminator, `"\n"`, `"\r\n"`, or `""` on a final line. */
1370
+ eol: string;
1371
+ }
1372
+ /**
1373
+ * A line that is empty or holds only whitespace.
1374
+ */
1375
+ interface XcconfigBlank {
1376
+ kind: "blank";
1377
+ /** The exact source line, without its terminator. */
1378
+ raw: string;
1379
+ /** The line terminator, `"\n"`, `"\r\n"`, or `""` on a final line. */
1380
+ eol: string;
1381
+ }
1382
+ /**
1383
+ * Any parsed `.xcconfig` line.
1384
+ */
1385
+ type XcconfigStatement = XcconfigAssignment | XcconfigBlank | XcconfigComment | XcconfigInclude;
1386
+ /**
1387
+ * A parsed `.xcconfig` file: its lines in order.
1388
+ */
1389
+ interface XcconfigDocument {
1390
+ statements: XcconfigStatement[];
1391
+ }
1392
+ //#endregion
1393
+ //#region src/xcconfig/model.d.ts
1394
+ /**
1395
+ * Resolves an `#include` path to the included file's model. Returning
1396
+ * `undefined` skips the include, which is always legal for the
1397
+ * `#include?` form and mirrors a missing file for the strict form.
1398
+ *
1399
+ * Cycles are detected while a file is being expanded, by the include
1400
+ * path exactly as written and by model instance. A cycle reached through
1401
+ * two different spellings of the same path escapes the path check, so
1402
+ * resolvers that memoize per path make the instance check catch it.
1403
+ */
1404
+ type XcconfigIncludeResolver = (path: string, optional: boolean) => Xcconfig | undefined;
1405
+ /**
1406
+ * The build context conditional assignments are matched against. Keys
1407
+ * mirror the condition names of the format, so `KEY[sdk=iphoneos*]`
1408
+ * matches against {@link sdk}.
1409
+ */
1410
+ interface XcconfigBuildContext {
1411
+ /** The SDK identifier, for example `iphoneos` or `appletvsimulator`. */
1412
+ sdk?: string;
1413
+ /** The architecture, for example `arm64`. */
1414
+ arch?: string;
1415
+ /** The configuration name, for example `Debug`. */
1416
+ config?: string;
1417
+ }
1418
+ /**
1419
+ * Options for {@link Xcconfig.settings}.
1420
+ */
1421
+ interface XcconfigSettingsOptions {
1422
+ /**
1423
+ * Called for every `#include` directive, in document order. Without a
1424
+ * resolver, includes contribute nothing.
1425
+ */
1426
+ resolveInclude?: XcconfigIncludeResolver;
1427
+ /**
1428
+ * The build context conditional assignments apply under. An assignment
1429
+ * takes part when every one of its conditions matches, with trailing
1430
+ * `*` wildcards honored the way Xcode matches SDK names. Without a
1431
+ * context, and for dimensions the context leaves out, conditional
1432
+ * assignments are skipped.
1433
+ */
1434
+ context?: XcconfigBuildContext;
1435
+ }
1436
+ /**
1437
+ * A build configuration file with typed, mutable access to its settings.
1438
+ *
1439
+ * ```ts
1440
+ * const config = Xcconfig.parse(text);
1441
+ * config.get("PRODUCT_BUNDLE_IDENTIFIER");
1442
+ * config.set("MARKETING_VERSION", "1.2.0");
1443
+ * const updated = config.build();
1444
+ * ```
1445
+ */
1446
+ declare class Xcconfig {
1447
+ /** The parsed document this model wraps. */
1448
+ readonly document: XcconfigDocument;
1449
+ private constructor();
1450
+ /**
1451
+ * Parses `.xcconfig` text and wraps it in a model.
1452
+ *
1453
+ * @throws XcconfigParseError when the text is malformed.
1454
+ */
1455
+ static parse(text: string): Xcconfig;
1456
+ /**
1457
+ * Creates an empty configuration file.
1458
+ */
1459
+ static create(): Xcconfig;
1460
+ /**
1461
+ * Serializes the current document state to `.xcconfig` text.
1462
+ */
1463
+ build(): string;
1464
+ /**
1465
+ * The names of the settings this file assigns unconditionally, in
1466
+ * first-assignment order. Conditional assignments such as
1467
+ * `KEY[sdk=iphoneos*]` are reachable through {@link assignments}.
1468
+ */
1469
+ keys(): string[];
1470
+ /**
1471
+ * Every assignment of this file, conditional ones included, in
1472
+ * document order. The items are the document's own nodes, not copies,
1473
+ * so treat them as read-only views. Writes belong on {@link set},
1474
+ * which keeps a statement's value and its source text in step.
1475
+ */
1476
+ assignments(): readonly XcconfigAssignment[];
1477
+ /**
1478
+ * The `#include` directives of this file, in document order. The items
1479
+ * are the document's own nodes, not copies, so treat them as read-only
1480
+ * views.
1481
+ */
1482
+ includes(): readonly XcconfigInclude[];
1483
+ /**
1484
+ * Reads the value of a setting from this file alone. When the key is
1485
+ * assigned more than once the last assignment wins, matching how Xcode
1486
+ * reads the file top to bottom. Conditional assignments are ignored.
1487
+ */
1488
+ get(key: string): string | undefined;
1489
+ /**
1490
+ * Writes a setting. The last unconditional assignment of the key is
1491
+ * rewritten in place as a canonical `KEY = value` line, replacing any
1492
+ * trailing comment the line carried. A key the file does not assign
1493
+ * yet is appended at the end, following the document's line-ending
1494
+ * convention.
1495
+ */
1496
+ set(key: string, value: string): void;
1497
+ /**
1498
+ * Removes every unconditional assignment of a setting.
1499
+ *
1500
+ * @returns True when at least one assignment was removed.
1501
+ */
1502
+ remove(key: string): boolean;
1503
+ /**
1504
+ * Flattens the file into a settings dictionary the way Xcode reads it:
1505
+ * top to bottom with later assignments winning, and every `#include`
1506
+ * contributing its settings at the point of the directive, so lines
1507
+ * after an include override it.
1508
+ *
1509
+ * Conditional assignments apply when every condition matches
1510
+ * {@link XcconfigSettingsOptions.context}; without a context they are
1511
+ * skipped. `$(inherited)` references splice in the value accumulated
1512
+ * earlier in the chain, and stay literal when there is none, since
1513
+ * they then refer to layers below the file, which resolve later.
1514
+ *
1515
+ * Includes only take part when {@link XcconfigSettingsOptions.resolveInclude}
1516
+ * is provided, since the library never touches the filesystem itself.
1517
+ * A file included again later re-applies, exactly like pasting its text
1518
+ * a second time. Only re-entry while a file is still being expanded is
1519
+ * skipped, tracked by include path and by instance, so cyclic includes
1520
+ * terminate even when the resolver parses a fresh instance per call.
1521
+ */
1522
+ settings(options?: XcconfigSettingsOptions): Record<string, string>;
1523
+ }
1524
+ //#endregion
1273
1525
  //#region src/model/project.d.ts
1274
1526
  /**
1275
1527
  * The `PBXProject` object at the document root. It owns the target list,
@@ -1351,6 +1603,12 @@ declare class XcodeProject {
1351
1603
  * access, so views of the same object compare with `===`.
1352
1604
  */
1353
1605
  private readonly views;
1606
+ /**
1607
+ * Flattened settings of registered `.xcconfig` files, keyed by the id
1608
+ * of the file reference configurations name in
1609
+ * `baseConfigurationReference`.
1610
+ */
1611
+ private readonly xcconfigSettings;
1354
1612
  private constructor();
1355
1613
  /**
1356
1614
  * Parses pbxproj text and wraps it in a model.
@@ -1414,6 +1672,22 @@ declare class XcodeProject {
1414
1672
  * @returns The view of the created object.
1415
1673
  */
1416
1674
  add<I extends string>(isa: I, properties: PbxprojObject, seed?: string): ViewOf<I>;
1675
+ /**
1676
+ * Registers the contents of a `.xcconfig` file so build-setting reads
1677
+ * can layer it below the configurations that are based on it. The
1678
+ * library never touches the filesystem, so the caller loads the file
1679
+ * and hands it over together with the file reference that
1680
+ * configurations name in `baseConfigurationReference`. Included files
1681
+ * take part through {@link XcconfigSettingsOptions.resolveInclude};
1682
+ * the settings are flattened once, at registration.
1683
+ */
1684
+ registerXcconfig(reference: FileReference, config: Xcconfig, options?: XcconfigSettingsOptions): void;
1685
+ /**
1686
+ * The flattened settings registered for the `.xcconfig` file a
1687
+ * configuration is based on, or `undefined` when the configuration
1688
+ * names none or the file was not registered.
1689
+ */
1690
+ xcconfigSettingsOf(configuration: BuildConfiguration): Record<string, string> | undefined;
1417
1691
  /**
1418
1692
  * The view of the document's root `PBXProject` object.
1419
1693
  *
@@ -1968,4 +2242,20 @@ declare function parseXcscheme(text: string): XcschemeDocument;
1968
2242
  */
1969
2243
  declare function generateObjectId(seed: string, existing: ReadonlySet<string>): string;
1970
2244
  //#endregion
1971
- 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, XcodeModelError, XcodeObject, XcodeProject, Xcscheme, XcschemeBuildError, type XcschemeComment, type XcschemeDocument, type XcschemeElement, type XcschemeNode, XcschemeParseError, buildPbxproj, buildXcscheme, createXcscheme, generateObjectId, isXcschemeElement, parseApplePlatform, parsePbxproj, parseXcscheme, xcschemeElements };
2245
+ //#region src/xcconfig/build.d.ts
2246
+ /**
2247
+ * Serializes a document back to `.xcconfig` text.
2248
+ */
2249
+ declare function buildXcconfig(document: XcconfigDocument): string;
2250
+ //#endregion
2251
+ //#region src/xcconfig/parse.d.ts
2252
+ /**
2253
+ * Parses `.xcconfig` text into its document form.
2254
+ *
2255
+ * @throws XcconfigParseError when a line is not a blank, a comment, an
2256
+ * include, or a well-formed assignment. The error carries the line and
2257
+ * column of the failure.
2258
+ */
2259
+ declare function parseXcconfig(source: string): XcconfigDocument;
2260
+ //#endregion
2261
+ 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 };
package/dist/index.js CHANGED
@@ -283,6 +283,30 @@ var XcschemeParseError = class extends Error {
283
283
  }
284
284
  };
285
285
  /**
286
+ * Thrown when the source text is not a well-formed build configuration
287
+ * file (the line-based format of `.xcconfig` files).
288
+ *
289
+ * The message always embeds the line and column of the failure, and the
290
+ * same information is available in structured form on {@link position}
291
+ * for programmatic use.
292
+ */
293
+ var XcconfigParseError = class extends Error {
294
+ /** Where in the source text parsing failed. */
295
+ position;
296
+ /**
297
+ * @param message Failure description without location; the location is
298
+ * appended automatically.
299
+ * @param source Full source text, used to compute the position.
300
+ * @param offset Character offset of the failure inside `source`.
301
+ */
302
+ constructor(message, source, offset) {
303
+ const position = positionAt(source, offset);
304
+ super(`${message} (line ${position.line}, column ${position.column})`);
305
+ this.name = "XcconfigParseError";
306
+ this.position = position;
307
+ }
308
+ };
309
+ /**
286
310
  * Thrown when a scheme element cannot be written as XML.
287
311
  *
288
312
  * Raised for element and attribute names that are not valid XML names and
@@ -1587,6 +1611,16 @@ var BuildConfiguration = class extends XcodeObject {
1587
1611
  get buildSettings() {
1588
1612
  return asDictionary(this.properties["buildSettings"]);
1589
1613
  }
1614
+ /**
1615
+ * The view of the `.xcconfig` file reference this configuration is
1616
+ * based on, when the configuration has one and it resolves. The file's
1617
+ * settings sit below the configuration's own `buildSettings` in
1618
+ * Xcode's resolution order.
1619
+ */
1620
+ baseConfigurationReference() {
1621
+ const view = this.project.get(this.getString("baseConfigurationReference"));
1622
+ return FileReference.is(view) ? view : void 0;
1623
+ }
1590
1624
  };
1591
1625
  /**
1592
1626
  * A `PBXBuildStyle` is the pre-Xcode-2 predecessor of
@@ -2880,16 +2914,23 @@ function configurationsOf(project, configurationListId) {
2880
2914
  return configurations;
2881
2915
  }
2882
2916
  /**
2883
- * The settings dictionary of a configuration list's default configuration:
2884
- * the one named by `defaultConfigurationName`, falling back to the first
2885
- * configuration. Returns `undefined` when the list has no configurations
2886
- * or the default carries no settings dictionary.
2917
+ * The view of a configuration list's default configuration, which is the
2918
+ * one named by `defaultConfigurationName`, falling back to the first
2919
+ * configuration. Returns `undefined` when the list has no configurations.
2887
2920
  */
2888
- function defaultConfigurationSettingsOf(project, configurationListId) {
2921
+ function defaultConfigurationOf(project, configurationListId) {
2889
2922
  const list = asDictionary(project.propertiesOfOptional(configurationListId));
2890
2923
  const configurations = configurationsOf(project, configurationListId);
2891
2924
  const defaultName = asString(list?.["defaultConfigurationName"]);
2892
- return asDictionary((configurations.find((configuration) => configuration.getString("name") === defaultName) ?? configurations[0])?.properties["buildSettings"]);
2925
+ return configurations.find((configuration) => configuration.getString("name") === defaultName) ?? configurations[0];
2926
+ }
2927
+ /**
2928
+ * The settings dictionary of a configuration list's default configuration
2929
+ * (see {@link defaultConfigurationOf}). Returns `undefined` when the list
2930
+ * has no configurations or the default carries no settings dictionary.
2931
+ */
2932
+ function defaultConfigurationSettingsOf(project, configurationListId) {
2933
+ return asDictionary(defaultConfigurationOf(project, configurationListId)?.properties["buildSettings"]);
2893
2934
  }
2894
2935
  //#endregion
2895
2936
  //#region src/model/target.ts
@@ -2950,13 +2991,24 @@ var Target = class extends XcodeObject {
2950
2991
  * generated app templates set values like `SDKROOT` only at the project
2951
2992
  * level.
2952
2993
  *
2994
+ * Configurations based on `.xcconfig` files take part once the files
2995
+ * are registered through {@link XcodeProject.registerXcconfig}, in
2996
+ * Xcode's order: target settings, the target's xcconfig, project
2997
+ * settings, the project's xcconfig.
2998
+ *
2953
2999
  * Only string values are returned; a list- or number-valued setting reads
2954
3000
  * as `undefined`.
2955
3001
  */
2956
3002
  getBuildSetting(key) {
2957
- const targetSettings = this.defaultConfigurationSettings();
3003
+ const targetConfiguration = defaultConfigurationOf(this.project, this.getString("buildConfigurationList"));
3004
+ const targetSettings = asDictionary(targetConfiguration?.properties["buildSettings"]);
2958
3005
  if (targetSettings != null && key in targetSettings) return asString(targetSettings[key]);
2959
- return asString(this.project.rootProject.defaultConfigurationSettings()?.[key]);
3006
+ const targetXcconfig = targetConfiguration == null ? void 0 : this.project.xcconfigSettingsOf(targetConfiguration);
3007
+ if (targetXcconfig != null && key in targetXcconfig) return targetXcconfig[key];
3008
+ const projectConfiguration = defaultConfigurationOf(this.project, this.project.rootProject.getString("buildConfigurationList"));
3009
+ const projectSettings = asDictionary(projectConfiguration?.properties["buildSettings"]);
3010
+ if (projectSettings != null && key in projectSettings) return asString(projectSettings[key]);
3011
+ return (projectConfiguration == null ? void 0 : this.project.xcconfigSettingsOf(projectConfiguration))?.[key];
2960
3012
  }
2961
3013
  /**
2962
3014
  * Writes a build setting on every configuration of the target, so Debug
@@ -3400,6 +3452,12 @@ var XcodeProject = class XcodeProject {
3400
3452
  * access, so views of the same object compare with `===`.
3401
3453
  */
3402
3454
  views = /* @__PURE__ */ new Map();
3455
+ /**
3456
+ * Flattened settings of registered `.xcconfig` files, keyed by the id
3457
+ * of the file reference configurations name in
3458
+ * `baseConfigurationReference`.
3459
+ */
3460
+ xcconfigSettings = /* @__PURE__ */ new Map();
3403
3461
  constructor(document) {
3404
3462
  const objects = asDictionary(document["objects"]);
3405
3463
  if (objects == null) throw new XcodeModelError("The document has no objects dictionary");
@@ -3508,6 +3566,27 @@ var XcodeProject = class XcodeProject {
3508
3566
  return view;
3509
3567
  }
3510
3568
  /**
3569
+ * Registers the contents of a `.xcconfig` file so build-setting reads
3570
+ * can layer it below the configurations that are based on it. The
3571
+ * library never touches the filesystem, so the caller loads the file
3572
+ * and hands it over together with the file reference that
3573
+ * configurations name in `baseConfigurationReference`. Included files
3574
+ * take part through {@link XcconfigSettingsOptions.resolveInclude};
3575
+ * the settings are flattened once, at registration.
3576
+ */
3577
+ registerXcconfig(reference, config, options = {}) {
3578
+ this.xcconfigSettings.set(reference.id, config.settings(options));
3579
+ }
3580
+ /**
3581
+ * The flattened settings registered for the `.xcconfig` file a
3582
+ * configuration is based on, or `undefined` when the configuration
3583
+ * names none or the file was not registered.
3584
+ */
3585
+ xcconfigSettingsOf(configuration) {
3586
+ const referenceId = configuration.getString("baseConfigurationReference");
3587
+ return referenceId == null ? void 0 : this.xcconfigSettings.get(referenceId);
3588
+ }
3589
+ /**
3511
3590
  * The view of the document's root `PBXProject` object.
3512
3591
  *
3513
3592
  * @throws XcodeModelError when `rootObject` is missing or dangling,
@@ -4557,4 +4636,328 @@ function createXcscheme(options) {
4557
4636
  };
4558
4637
  }
4559
4638
  //#endregion
4560
- export { AggregateTarget, AppleScriptBuildPhase, BuildConfiguration, BuildFile, BuildFileExceptionSet, BuildPhase, BuildPhaseMembershipExceptionSet, BuildRule, BuildStyle, BuildableReference, ConfigurationList, ContainerItemProxy, CopyFilesBuildPhase, CopyFilesDestination, ExceptionSet, FileReference, FrameworksBuildPhase, Group, HeadersBuildPhase, Isa, LegacyTarget, LocalSwiftPackageReference, NativeTarget, PbxprojBuildError, PbxprojParseError, ProductType, ReferenceProxy, RemoteSwiftPackageReference, ResourcesBuildPhase, RezBuildPhase, RootProject, ShellScriptBuildPhase, SourcesBuildPhase, SwiftPackageProductDependency, SwiftPackageReference, SyncRootGroup, Target, TargetDependency, VariantGroup, VersionGroup, XcodeModelError, XcodeObject, XcodeProject, Xcscheme, XcschemeBuildError, XcschemeParseError, buildPbxproj, buildXcscheme, createXcscheme, generateObjectId, isXcschemeElement, parseApplePlatform, parsePbxproj, parseXcscheme, xcschemeElements };
4639
+ //#region src/xcconfig/build.ts
4640
+ /**
4641
+ * Serializes a document back to `.xcconfig` text.
4642
+ */
4643
+ function buildXcconfig(document) {
4644
+ let text = "";
4645
+ for (const statement of document.statements) text += statement.raw + statement.eol;
4646
+ return text;
4647
+ }
4648
+ //#endregion
4649
+ //#region src/xcconfig/parse.ts
4650
+ /**
4651
+ * Parser for Xcode build configuration files (`.xcconfig`).
4652
+ *
4653
+ * The grammar is line based. A line is blank, a `//` comment, an
4654
+ * `#include "path"` directive, or a `KEY[conditions] = value` assignment.
4655
+ * `//` starts a comment anywhere on a line, including inside values, which
4656
+ * matches Xcode's reading of the format. Every parsed statement keeps its
4657
+ * exact source text, so an untouched document rebuilds byte for byte.
4658
+ *
4659
+ * @module
4660
+ */
4661
+ /**
4662
+ * Matches `#include "path"` and `#include? "path"`, with an optional
4663
+ * trailing comment.
4664
+ */
4665
+ const INCLUDE_PATTERN = /^#include(\?)?\s*"([^"]*)"\s*(?:\/\/.*)?$/u;
4666
+ /**
4667
+ * Matches the head of an assignment: leading whitespace, the setting
4668
+ * name, and the raw conditions block up to the equals sign.
4669
+ */
4670
+ const ASSIGNMENT_HEAD_PATTERN = /^\s*([A-Za-z_][A-Za-z0-9_]*)\s*((?:\[[^\]]*\])*)\s*=/u;
4671
+ /**
4672
+ * Matches one `[name=value]` condition group inside the conditions block.
4673
+ */
4674
+ const CONDITION_PATTERN = /\[([^=\]]+)=([^\]]*)\]/gu;
4675
+ /**
4676
+ * Strips the trailing comment, surrounding whitespace, and one trailing
4677
+ * semicolon from an assignment's right-hand side. Xcode tolerates the
4678
+ * semicolon as a leftover from property-list habits and ignores it.
4679
+ */
4680
+ function cleanValue(rightHandSide) {
4681
+ const commentStart = rightHandSide.indexOf("//");
4682
+ const trimmed = (commentStart === -1 ? rightHandSide : rightHandSide.slice(0, commentStart)).trim();
4683
+ return trimmed.endsWith(";") ? trimmed.slice(0, -1).trimEnd() : trimmed;
4684
+ }
4685
+ /**
4686
+ * Parses the conditions block of an assignment, for example
4687
+ * `[sdk=iphoneos*][arch=arm64]`.
4688
+ *
4689
+ * @throws XcconfigParseError when the block has content that is not a
4690
+ * well-formed `[name=value]` sequence.
4691
+ */
4692
+ function parseConditions(block, source, blockOffset) {
4693
+ const conditions = [];
4694
+ let consumed = 0;
4695
+ for (const match of block.matchAll(CONDITION_PATTERN)) {
4696
+ if (match.index !== consumed) throw new XcconfigParseError("Malformed setting condition", source, blockOffset + consumed);
4697
+ conditions.push({
4698
+ name: match[1].trim(),
4699
+ value: match[2].trim()
4700
+ });
4701
+ consumed = match.index + match[0].length;
4702
+ }
4703
+ if (consumed !== block.length) throw new XcconfigParseError("Malformed setting condition", source, blockOffset + consumed);
4704
+ return conditions;
4705
+ }
4706
+ /**
4707
+ * Parses one line into a statement.
4708
+ *
4709
+ * @param content The line without its terminator.
4710
+ * @param source The full source text, for error positions.
4711
+ * @param lineOffset Offset of the line inside `source`.
4712
+ */
4713
+ function parseLine(content, eol, source, lineOffset) {
4714
+ const trimmed = content.trim();
4715
+ if (trimmed === "") return {
4716
+ kind: "blank",
4717
+ raw: content,
4718
+ eol
4719
+ };
4720
+ if (trimmed.startsWith("//")) return {
4721
+ kind: "comment",
4722
+ text: trimmed.slice(2),
4723
+ raw: content,
4724
+ eol
4725
+ };
4726
+ if (trimmed.startsWith("#")) {
4727
+ const include = INCLUDE_PATTERN.exec(trimmed);
4728
+ if (include == null) throw new XcconfigParseError("Malformed #include directive", source, lineOffset + content.indexOf("#"));
4729
+ return {
4730
+ kind: "include",
4731
+ path: include[2],
4732
+ optional: include[1] === "?",
4733
+ raw: content,
4734
+ eol
4735
+ };
4736
+ }
4737
+ const head = ASSIGNMENT_HEAD_PATTERN.exec(content);
4738
+ if (head == null) throw new XcconfigParseError("Expected a setting assignment, an #include directive, or a // comment", source, lineOffset + (content.length - content.trimStart().length));
4739
+ const conditionsBlock = head[2];
4740
+ const conditionsOffset = lineOffset + head[0].indexOf(conditionsBlock, head[1].length);
4741
+ const conditions = conditionsBlock === "" ? [] : parseConditions(conditionsBlock, source, conditionsOffset);
4742
+ return {
4743
+ kind: "assignment",
4744
+ key: head[1],
4745
+ conditions,
4746
+ value: cleanValue(content.slice(head[0].length)),
4747
+ raw: content,
4748
+ eol
4749
+ };
4750
+ }
4751
+ /**
4752
+ * Parses `.xcconfig` text into its document form.
4753
+ *
4754
+ * @throws XcconfigParseError when a line is not a blank, a comment, an
4755
+ * include, or a well-formed assignment. The error carries the line and
4756
+ * column of the failure.
4757
+ */
4758
+ function parseXcconfig(source) {
4759
+ if (source === "") return { statements: [] };
4760
+ const statements = [];
4761
+ let offset = 0;
4762
+ while (offset < source.length) {
4763
+ const lineFeed = source.indexOf("\n", offset);
4764
+ const end = lineFeed === -1 ? source.length : lineFeed;
4765
+ const hasCarriageReturn = end > offset && source.charCodeAt(end - 1) === 13;
4766
+ const content = source.slice(offset, hasCarriageReturn ? end - 1 : end);
4767
+ const eol = lineFeed === -1 ? "" : hasCarriageReturn ? "\r\n" : "\n";
4768
+ statements.push(parseLine(content, eol, source, offset));
4769
+ if (lineFeed === -1) break;
4770
+ offset = lineFeed + 1;
4771
+ }
4772
+ return { statements };
4773
+ }
4774
+ //#endregion
4775
+ //#region src/xcconfig/model.ts
4776
+ /**
4777
+ * Object model for Xcode build configuration files (`.xcconfig`).
4778
+ *
4779
+ * {@link Xcconfig} wraps a parsed document the way `XcodeProject` wraps a
4780
+ * pbxproj: the document stays the single source of truth, reads and
4781
+ * writes go through it, and {@link Xcconfig.build} emits it back with
4782
+ * untouched lines preserved byte for byte.
4783
+ *
4784
+ * @module
4785
+ */
4786
+ /**
4787
+ * Whether a condition value matches a context value. A bare `*` matches
4788
+ * anything, a trailing `*` matches by prefix, and anything else matches
4789
+ * exactly.
4790
+ */
4791
+ function matchesCondition(conditionValue, contextValue) {
4792
+ if (conditionValue === "*") return true;
4793
+ if (conditionValue.endsWith("*")) return contextValue.startsWith(conditionValue.slice(0, -1));
4794
+ return conditionValue === contextValue;
4795
+ }
4796
+ /**
4797
+ * Splices a prior value into `$(inherited)` and `${inherited}`
4798
+ * references. With no prior value the references stay literal, because
4799
+ * they then refer to layers below the file chain, which resolve later.
4800
+ */
4801
+ function spliceInherited(value, prior) {
4802
+ if (prior == null) return value;
4803
+ return value.replaceAll("$(inherited)", prior).replaceAll("${inherited}", prior);
4804
+ }
4805
+ /**
4806
+ * A build configuration file with typed, mutable access to its settings.
4807
+ *
4808
+ * ```ts
4809
+ * const config = Xcconfig.parse(text);
4810
+ * config.get("PRODUCT_BUNDLE_IDENTIFIER");
4811
+ * config.set("MARKETING_VERSION", "1.2.0");
4812
+ * const updated = config.build();
4813
+ * ```
4814
+ */
4815
+ var Xcconfig = class Xcconfig {
4816
+ /** The parsed document this model wraps. */
4817
+ document;
4818
+ constructor(document) {
4819
+ this.document = document;
4820
+ }
4821
+ /**
4822
+ * Parses `.xcconfig` text and wraps it in a model.
4823
+ *
4824
+ * @throws XcconfigParseError when the text is malformed.
4825
+ */
4826
+ static parse(text) {
4827
+ return new Xcconfig(parseXcconfig(text));
4828
+ }
4829
+ /**
4830
+ * Creates an empty configuration file.
4831
+ */
4832
+ static create() {
4833
+ return new Xcconfig({ statements: [] });
4834
+ }
4835
+ /**
4836
+ * Serializes the current document state to `.xcconfig` text.
4837
+ */
4838
+ build() {
4839
+ return buildXcconfig(this.document);
4840
+ }
4841
+ /**
4842
+ * The names of the settings this file assigns unconditionally, in
4843
+ * first-assignment order. Conditional assignments such as
4844
+ * `KEY[sdk=iphoneos*]` are reachable through {@link assignments}.
4845
+ */
4846
+ keys() {
4847
+ const keys = [];
4848
+ for (const statement of this.document.statements) if (statement.kind === "assignment" && statement.conditions.length === 0 && !keys.includes(statement.key)) keys.push(statement.key);
4849
+ return keys;
4850
+ }
4851
+ /**
4852
+ * Every assignment of this file, conditional ones included, in
4853
+ * document order. The items are the document's own nodes, not copies,
4854
+ * so treat them as read-only views. Writes belong on {@link set},
4855
+ * which keeps a statement's value and its source text in step.
4856
+ */
4857
+ assignments() {
4858
+ return this.document.statements.filter((statement) => statement.kind === "assignment");
4859
+ }
4860
+ /**
4861
+ * The `#include` directives of this file, in document order. The items
4862
+ * are the document's own nodes, not copies, so treat them as read-only
4863
+ * views.
4864
+ */
4865
+ includes() {
4866
+ return this.document.statements.filter((statement) => statement.kind === "include");
4867
+ }
4868
+ /**
4869
+ * Reads the value of a setting from this file alone. When the key is
4870
+ * assigned more than once the last assignment wins, matching how Xcode
4871
+ * reads the file top to bottom. Conditional assignments are ignored.
4872
+ */
4873
+ get(key) {
4874
+ let value;
4875
+ for (const statement of this.document.statements) if (statement.kind === "assignment" && statement.key === key && statement.conditions.length === 0) value = statement.value;
4876
+ return value;
4877
+ }
4878
+ /**
4879
+ * Writes a setting. The last unconditional assignment of the key is
4880
+ * rewritten in place as a canonical `KEY = value` line, replacing any
4881
+ * trailing comment the line carried. A key the file does not assign
4882
+ * yet is appended at the end, following the document's line-ending
4883
+ * convention.
4884
+ */
4885
+ set(key, value) {
4886
+ let target;
4887
+ for (const statement of this.document.statements) if (statement.kind === "assignment" && statement.key === key && statement.conditions.length === 0) target = statement;
4888
+ if (target != null) {
4889
+ target.value = value;
4890
+ target.raw = `${key} = ${value}`;
4891
+ return;
4892
+ }
4893
+ const eol = this.document.statements.find((statement) => statement.eol !== "")?.eol ?? "\n";
4894
+ const last = this.document.statements.at(-1);
4895
+ if (last != null && last.eol === "") last.eol = eol;
4896
+ this.document.statements.push({
4897
+ kind: "assignment",
4898
+ key,
4899
+ conditions: [],
4900
+ value,
4901
+ raw: `${key} = ${value}`,
4902
+ eol
4903
+ });
4904
+ }
4905
+ /**
4906
+ * Removes every unconditional assignment of a setting.
4907
+ *
4908
+ * @returns True when at least one assignment was removed.
4909
+ */
4910
+ remove(key) {
4911
+ const kept = this.document.statements.filter((statement) => statement.kind !== "assignment" || statement.key !== key || statement.conditions.length > 0);
4912
+ const removed = kept.length !== this.document.statements.length;
4913
+ this.document.statements = kept;
4914
+ return removed;
4915
+ }
4916
+ /**
4917
+ * Flattens the file into a settings dictionary the way Xcode reads it:
4918
+ * top to bottom with later assignments winning, and every `#include`
4919
+ * contributing its settings at the point of the directive, so lines
4920
+ * after an include override it.
4921
+ *
4922
+ * Conditional assignments apply when every condition matches
4923
+ * {@link XcconfigSettingsOptions.context}; without a context they are
4924
+ * skipped. `$(inherited)` references splice in the value accumulated
4925
+ * earlier in the chain, and stay literal when there is none, since
4926
+ * they then refer to layers below the file, which resolve later.
4927
+ *
4928
+ * Includes only take part when {@link XcconfigSettingsOptions.resolveInclude}
4929
+ * is provided, since the library never touches the filesystem itself.
4930
+ * A file included again later re-applies, exactly like pasting its text
4931
+ * a second time. Only re-entry while a file is still being expanded is
4932
+ * skipped, tracked by include path and by instance, so cyclic includes
4933
+ * terminate even when the resolver parses a fresh instance per call.
4934
+ */
4935
+ settings(options = {}) {
4936
+ const merged = {};
4937
+ const pathStack = /* @__PURE__ */ new Set();
4938
+ const instanceStack = /* @__PURE__ */ new Set();
4939
+ const context = options.context;
4940
+ const applies = (statement) => statement.conditions.every((condition) => {
4941
+ const contextValue = condition.name === "sdk" || condition.name === "arch" || condition.name === "config" ? context?.[condition.name] : void 0;
4942
+ return contextValue != null && matchesCondition(condition.value, contextValue);
4943
+ });
4944
+ const visit = (config) => {
4945
+ if (instanceStack.has(config)) return;
4946
+ instanceStack.add(config);
4947
+ for (const statement of config.document.statements) if (statement.kind === "include") {
4948
+ if (pathStack.has(statement.path)) continue;
4949
+ const included = options.resolveInclude?.(statement.path, statement.optional);
4950
+ if (included != null) {
4951
+ pathStack.add(statement.path);
4952
+ visit(included);
4953
+ pathStack.delete(statement.path);
4954
+ }
4955
+ } else if (statement.kind === "assignment" && applies(statement)) merged[statement.key] = spliceInherited(statement.value, merged[statement.key]);
4956
+ instanceStack.delete(config);
4957
+ };
4958
+ visit(this);
4959
+ return merged;
4960
+ }
4961
+ };
4962
+ //#endregion
4963
+ export { AggregateTarget, AppleScriptBuildPhase, BuildConfiguration, BuildFile, BuildFileExceptionSet, BuildPhase, BuildPhaseMembershipExceptionSet, BuildRule, BuildStyle, BuildableReference, ConfigurationList, ContainerItemProxy, CopyFilesBuildPhase, CopyFilesDestination, ExceptionSet, FileReference, FrameworksBuildPhase, Group, HeadersBuildPhase, Isa, LegacyTarget, LocalSwiftPackageReference, NativeTarget, PbxprojBuildError, PbxprojParseError, ProductType, ReferenceProxy, RemoteSwiftPackageReference, ResourcesBuildPhase, RezBuildPhase, RootProject, ShellScriptBuildPhase, SourcesBuildPhase, SwiftPackageProductDependency, SwiftPackageReference, SyncRootGroup, Target, TargetDependency, VariantGroup, VersionGroup, Xcconfig, XcconfigParseError, XcodeModelError, XcodeObject, XcodeProject, Xcscheme, XcschemeBuildError, XcschemeParseError, buildPbxproj, buildXcconfig, buildXcscheme, createXcscheme, generateObjectId, isXcschemeElement, parseApplePlatform, parsePbxproj, parseXcconfig, parseXcscheme, xcschemeElements };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rork-xcode",
3
- "version": "0.8.0",
3
+ "version": "0.9.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",