rork-xcode 0.3.0 → 0.5.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 +24 -21
- package/dist/index.d.ts +518 -72
- package/dist/index.js +804 -235
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -808,20 +808,26 @@ function buildPbxproj(root) {
|
|
|
808
808
|
*/
|
|
809
809
|
const Isa = {
|
|
810
810
|
aggregateTarget: "PBXAggregateTarget",
|
|
811
|
+
appleScriptBuildPhase: "PBXAppleScriptBuildPhase",
|
|
811
812
|
buildFile: "PBXBuildFile",
|
|
812
813
|
buildRule: "PBXBuildRule",
|
|
814
|
+
buildStyle: "PBXBuildStyle",
|
|
813
815
|
containerItemProxy: "PBXContainerItemProxy",
|
|
814
816
|
copyFilesBuildPhase: "PBXCopyFilesBuildPhase",
|
|
815
817
|
fileReference: "PBXFileReference",
|
|
816
818
|
fileSystemSynchronizedBuildFileExceptionSet: "PBXFileSystemSynchronizedBuildFileExceptionSet",
|
|
819
|
+
fileSystemSynchronizedGroupBuildPhaseMembershipExceptionSet: "PBXFileSystemSynchronizedGroupBuildPhaseMembershipExceptionSet",
|
|
817
820
|
fileSystemSynchronizedRootGroup: "PBXFileSystemSynchronizedRootGroup",
|
|
818
821
|
frameworksBuildPhase: "PBXFrameworksBuildPhase",
|
|
819
822
|
group: "PBXGroup",
|
|
823
|
+
headersBuildPhase: "PBXHeadersBuildPhase",
|
|
820
824
|
legacyTarget: "PBXLegacyTarget",
|
|
821
825
|
nativeTarget: "PBXNativeTarget",
|
|
822
826
|
project: "PBXProject",
|
|
823
827
|
referenceProxy: "PBXReferenceProxy",
|
|
824
828
|
resourcesBuildPhase: "PBXResourcesBuildPhase",
|
|
829
|
+
rezBuildPhase: "PBXRezBuildPhase",
|
|
830
|
+
shellScriptBuildPhase: "PBXShellScriptBuildPhase",
|
|
825
831
|
sourcesBuildPhase: "PBXSourcesBuildPhase",
|
|
826
832
|
targetDependency: "PBXTargetDependency",
|
|
827
833
|
variantGroup: "PBXVariantGroup",
|
|
@@ -1006,9 +1012,9 @@ function stringItems(value) {
|
|
|
1006
1012
|
*
|
|
1007
1013
|
* Views are lightweight, identity-mapped facades over entries of the
|
|
1008
1014
|
* document's `objects` dictionary. All state lives in the parsed document
|
|
1009
|
-
* itself
|
|
1010
|
-
* document text produced from the model reflects every
|
|
1011
|
-
* separate serialization step.
|
|
1015
|
+
* itself, and a view holds only its id and a reference back to the
|
|
1016
|
+
* project, so document text produced from the model reflects every
|
|
1017
|
+
* mutation with no separate serialization step.
|
|
1012
1018
|
*
|
|
1013
1019
|
* @module
|
|
1014
1020
|
*/
|
|
@@ -1025,12 +1031,20 @@ function stringItems(value) {
|
|
|
1025
1031
|
* itself always reads through the narrowing accessors.
|
|
1026
1032
|
*/
|
|
1027
1033
|
var XcodeObject = class {
|
|
1034
|
+
/**
|
|
1035
|
+
* The `isa` name this view class models. Each concrete view declares
|
|
1036
|
+
* its own, and the project's view factory dispatches on it, so the
|
|
1037
|
+
* class itself is the source of truth for which objects it covers.
|
|
1038
|
+
* Classes that only share behavior, like this base class and the
|
|
1039
|
+
* abstract target and phase bases, declare `null` and never route.
|
|
1040
|
+
*/
|
|
1041
|
+
static isa = null;
|
|
1028
1042
|
/** The project this object belongs to. */
|
|
1029
1043
|
project;
|
|
1030
1044
|
/** The object's 24-character identifier (its key in `objects`). */
|
|
1031
1045
|
id;
|
|
1032
1046
|
/**
|
|
1033
|
-
* Views are created by the project's identity map
|
|
1047
|
+
* Views are created by the project's identity map. Use
|
|
1034
1048
|
* {@link XcodeProject.get} or a typed query instead of constructing
|
|
1035
1049
|
* views directly.
|
|
1036
1050
|
*/
|
|
@@ -1039,9 +1053,28 @@ var XcodeObject = class {
|
|
|
1039
1053
|
this.id = id;
|
|
1040
1054
|
}
|
|
1041
1055
|
/**
|
|
1042
|
-
*
|
|
1043
|
-
*
|
|
1044
|
-
*
|
|
1056
|
+
* Whether a value is a view of this class, narrowing it when so. Views
|
|
1057
|
+
* come typed out of the factory, and this is the readable way to
|
|
1058
|
+
* discriminate them when iterating mixed objects.
|
|
1059
|
+
*
|
|
1060
|
+
* ```ts
|
|
1061
|
+
* for (const [, object] of project.objects()) {
|
|
1062
|
+
* if (NativeTarget.is(object)) {
|
|
1063
|
+
* console.log(object.name);
|
|
1064
|
+
* }
|
|
1065
|
+
* }
|
|
1066
|
+
* ```
|
|
1067
|
+
*
|
|
1068
|
+
* Subclass views match their parent class too, the way `instanceof`
|
|
1069
|
+
* does, so a `VersionGroup` is a `Group`.
|
|
1070
|
+
*/
|
|
1071
|
+
static is(value) {
|
|
1072
|
+
return value instanceof this;
|
|
1073
|
+
}
|
|
1074
|
+
/**
|
|
1075
|
+
* The object's raw dictionary inside the document. Mutations through
|
|
1076
|
+
* the model write here, direct writes are equally valid, and the model
|
|
1077
|
+
* adds no caching over these properties.
|
|
1045
1078
|
*
|
|
1046
1079
|
* The typed shape is asserted, not checked. It describes what a
|
|
1047
1080
|
* well-formed object of this kind carries (see `properties.ts`).
|
|
@@ -1116,11 +1149,11 @@ var XcodeObject = class {
|
|
|
1116
1149
|
*/
|
|
1117
1150
|
/**
|
|
1118
1151
|
* A `PBXGroup` is a folder in Xcode's navigator, holding references to
|
|
1119
|
-
* files and other groups.
|
|
1120
|
-
*
|
|
1121
|
-
* shape.
|
|
1152
|
+
* files and other groups. The type parameter lets subclasses carry a more
|
|
1153
|
+
* specific property shape.
|
|
1122
1154
|
*/
|
|
1123
1155
|
var Group = class Group extends XcodeObject {
|
|
1156
|
+
static isa = Isa.group;
|
|
1124
1157
|
/**
|
|
1125
1158
|
* Ids of the group's children, in navigator order. Non-string entries of
|
|
1126
1159
|
* a malformed document are skipped.
|
|
@@ -1192,8 +1225,18 @@ var Group = class Group extends XcodeObject {
|
|
|
1192
1225
|
}
|
|
1193
1226
|
};
|
|
1194
1227
|
/**
|
|
1228
|
+
* A `PBXVariantGroup` holds the localized variants of one file, one child
|
|
1229
|
+
* per language. Everything else behaves like a plain group.
|
|
1230
|
+
*/
|
|
1231
|
+
var VariantGroup = class extends Group {
|
|
1232
|
+
static isa = Isa.variantGroup;
|
|
1233
|
+
};
|
|
1234
|
+
/**
|
|
1195
1235
|
* A build phase is an ordered list of build files processed by one step
|
|
1196
|
-
* of a target's build. Every `PBX*BuildPhase` kind
|
|
1236
|
+
* of a target's build. Every `PBX*BuildPhase` kind extends this view, and
|
|
1237
|
+
* kinds without a class of their own still map here through the factory's
|
|
1238
|
+
* suffix fallback. The type parameter lets subclasses carry a more
|
|
1239
|
+
* specific property shape.
|
|
1197
1240
|
*/
|
|
1198
1241
|
var BuildPhase = class extends XcodeObject {
|
|
1199
1242
|
/**
|
|
@@ -1249,7 +1292,7 @@ var BuildPhase = class extends XcodeObject {
|
|
|
1249
1292
|
const referenceKey = options.referenceKey ?? "fileRef";
|
|
1250
1293
|
for (const buildFileId of this.buildFileIds) {
|
|
1251
1294
|
const existing = this.project.get(buildFileId);
|
|
1252
|
-
if (existing
|
|
1295
|
+
if (BuildFile.is(existing) && existing.getString(referenceKey) === reference.id) return existing;
|
|
1253
1296
|
}
|
|
1254
1297
|
const buildFile = this.project.add(Isa.buildFile, {
|
|
1255
1298
|
[referenceKey]: reference.id,
|
|
@@ -1260,10 +1303,110 @@ var BuildPhase = class extends XcodeObject {
|
|
|
1260
1303
|
}
|
|
1261
1304
|
};
|
|
1262
1305
|
/**
|
|
1306
|
+
* A `PBXSourcesBuildPhase` compiles the target's source files.
|
|
1307
|
+
*/
|
|
1308
|
+
var SourcesBuildPhase = class extends BuildPhase {
|
|
1309
|
+
static isa = Isa.sourcesBuildPhase;
|
|
1310
|
+
};
|
|
1311
|
+
/**
|
|
1312
|
+
* A `PBXFrameworksBuildPhase` links the target against frameworks,
|
|
1313
|
+
* libraries, and Swift package products.
|
|
1314
|
+
*/
|
|
1315
|
+
var FrameworksBuildPhase = class extends BuildPhase {
|
|
1316
|
+
static isa = Isa.frameworksBuildPhase;
|
|
1317
|
+
};
|
|
1318
|
+
/**
|
|
1319
|
+
* A `PBXResourcesBuildPhase` copies the target's resources into the
|
|
1320
|
+
* built product.
|
|
1321
|
+
*/
|
|
1322
|
+
var ResourcesBuildPhase = class extends BuildPhase {
|
|
1323
|
+
static isa = Isa.resourcesBuildPhase;
|
|
1324
|
+
};
|
|
1325
|
+
/**
|
|
1326
|
+
* A `PBXHeadersBuildPhase` installs a framework target's headers with
|
|
1327
|
+
* their public, private, or project visibility.
|
|
1328
|
+
*/
|
|
1329
|
+
var HeadersBuildPhase = class extends BuildPhase {
|
|
1330
|
+
static isa = Isa.headersBuildPhase;
|
|
1331
|
+
};
|
|
1332
|
+
/**
|
|
1333
|
+
* A `PBXCopyFilesBuildPhase` copies its build files to a destination
|
|
1334
|
+
* inside the built product, which is how extensions and watch apps embed.
|
|
1335
|
+
*/
|
|
1336
|
+
var CopyFilesBuildPhase = class extends BuildPhase {
|
|
1337
|
+
static isa = Isa.copyFilesBuildPhase;
|
|
1338
|
+
/**
|
|
1339
|
+
* The destination path inside the folder `dstSubfolderSpec` selects,
|
|
1340
|
+
* when present.
|
|
1341
|
+
*/
|
|
1342
|
+
get dstPath() {
|
|
1343
|
+
return this.getString("dstPath");
|
|
1344
|
+
}
|
|
1345
|
+
};
|
|
1346
|
+
/**
|
|
1347
|
+
* A `PBXShellScriptBuildPhase` runs a script during the build.
|
|
1348
|
+
*/
|
|
1349
|
+
var ShellScriptBuildPhase = class extends BuildPhase {
|
|
1350
|
+
static isa = Isa.shellScriptBuildPhase;
|
|
1351
|
+
/**
|
|
1352
|
+
* The script's source text, when present.
|
|
1353
|
+
*/
|
|
1354
|
+
get shellScript() {
|
|
1355
|
+
return this.getString("shellScript");
|
|
1356
|
+
}
|
|
1357
|
+
/**
|
|
1358
|
+
* The interpreter the script runs under, when present. Xcode's default
|
|
1359
|
+
* is `/bin/sh`.
|
|
1360
|
+
*/
|
|
1361
|
+
get shellPath() {
|
|
1362
|
+
return this.getString("shellPath");
|
|
1363
|
+
}
|
|
1364
|
+
};
|
|
1365
|
+
/**
|
|
1366
|
+
* A `PBXRezBuildPhase` runs Rez, the classic Mac OS resource compiler,
|
|
1367
|
+
* over `.r` files. Xcode's UI called it "Build Carbon Resources".
|
|
1368
|
+
* Current Xcode no longer creates these phases, but old documents still
|
|
1369
|
+
* carry them.
|
|
1370
|
+
*/
|
|
1371
|
+
var RezBuildPhase = class extends BuildPhase {
|
|
1372
|
+
static isa = Isa.rezBuildPhase;
|
|
1373
|
+
};
|
|
1374
|
+
/**
|
|
1375
|
+
* A `PBXAppleScriptBuildPhase` compiles AppleScript sources. Current
|
|
1376
|
+
* Xcode no longer creates these, but old documents still carry them.
|
|
1377
|
+
*/
|
|
1378
|
+
var AppleScriptBuildPhase = class extends BuildPhase {
|
|
1379
|
+
static isa = Isa.appleScriptBuildPhase;
|
|
1380
|
+
};
|
|
1381
|
+
/**
|
|
1382
|
+
* A `PBXBuildFile` places one file reference or package product inside
|
|
1383
|
+
* one build phase, optionally with per-file settings.
|
|
1384
|
+
*/
|
|
1385
|
+
var BuildFile = class extends XcodeObject {
|
|
1386
|
+
static isa = Isa.buildFile;
|
|
1387
|
+
/**
|
|
1388
|
+
* The view of the file reference the build file points at, when it
|
|
1389
|
+
* points at one. Build files for Swift package products carry a
|
|
1390
|
+
* `productRef` instead; see {@link productDependency}.
|
|
1391
|
+
*/
|
|
1392
|
+
fileReference() {
|
|
1393
|
+
return this.project.get(this.getString("fileRef"));
|
|
1394
|
+
}
|
|
1395
|
+
/**
|
|
1396
|
+
* The view of the Swift package product dependency the build file
|
|
1397
|
+
* points at, when it points at one.
|
|
1398
|
+
*/
|
|
1399
|
+
productDependency() {
|
|
1400
|
+
const view = this.project.get(this.getString("productRef"));
|
|
1401
|
+
return SwiftPackageProductDependency.is(view) ? view : void 0;
|
|
1402
|
+
}
|
|
1403
|
+
};
|
|
1404
|
+
/**
|
|
1263
1405
|
* A `PBXFileSystemSynchronizedRootGroup` is an Xcode 16 folder whose
|
|
1264
1406
|
* members are synchronized from disk instead of listed individually.
|
|
1265
1407
|
*/
|
|
1266
1408
|
var SyncRootGroup = class extends XcodeObject {
|
|
1409
|
+
static isa = Isa.fileSystemSynchronizedRootGroup;
|
|
1267
1410
|
/**
|
|
1268
1411
|
* The group's on-disk folder path, when present.
|
|
1269
1412
|
*/
|
|
@@ -1291,7 +1434,7 @@ var SyncRootGroup = class extends XcodeObject {
|
|
|
1291
1434
|
addMembershipExceptions(target, membershipExceptions) {
|
|
1292
1435
|
for (const id of stringItems(this.properties["exceptions"])) {
|
|
1293
1436
|
const existing = this.project.get(id);
|
|
1294
|
-
if (existing
|
|
1437
|
+
if (BuildFileExceptionSet.is(existing) && existing.getString("target") === target.id) {
|
|
1295
1438
|
const names = ensureArray(existing.properties, "membershipExceptions");
|
|
1296
1439
|
for (const name of membershipExceptions) if (!names.includes(name)) names.push(name);
|
|
1297
1440
|
return existing;
|
|
@@ -1306,10 +1449,55 @@ var SyncRootGroup = class extends XcodeObject {
|
|
|
1306
1449
|
}
|
|
1307
1450
|
};
|
|
1308
1451
|
/**
|
|
1452
|
+
* Behavior shared by the synchronized-folder exception set kinds, which
|
|
1453
|
+
* carve files out of a folder's automatic membership for one target. The
|
|
1454
|
+
* type parameter lets subclasses carry a more specific property shape.
|
|
1455
|
+
*/
|
|
1456
|
+
var ExceptionSet = class extends XcodeObject {
|
|
1457
|
+
/**
|
|
1458
|
+
* The file names the set excludes, in declaration order. Non-string
|
|
1459
|
+
* entries of a malformed document are skipped.
|
|
1460
|
+
*/
|
|
1461
|
+
get membershipExceptions() {
|
|
1462
|
+
return stringItems(this.properties["membershipExceptions"]);
|
|
1463
|
+
}
|
|
1464
|
+
/**
|
|
1465
|
+
* The view of the target whose membership the set restricts, when the
|
|
1466
|
+
* reference resolves.
|
|
1467
|
+
*/
|
|
1468
|
+
target() {
|
|
1469
|
+
return this.project.get(this.getString("target"));
|
|
1470
|
+
}
|
|
1471
|
+
};
|
|
1472
|
+
/**
|
|
1473
|
+
* A `PBXFileSystemSynchronizedBuildFileExceptionSet` excludes files from
|
|
1474
|
+
* a synchronized folder's automatic target membership.
|
|
1475
|
+
*/
|
|
1476
|
+
var BuildFileExceptionSet = class extends ExceptionSet {
|
|
1477
|
+
static isa = Isa.fileSystemSynchronizedBuildFileExceptionSet;
|
|
1478
|
+
};
|
|
1479
|
+
/**
|
|
1480
|
+
* A `PBXFileSystemSynchronizedGroupBuildPhaseMembershipExceptionSet`
|
|
1481
|
+
* assigns some of a synchronized folder's files to a different build
|
|
1482
|
+
* phase than the automatic one.
|
|
1483
|
+
*/
|
|
1484
|
+
var BuildPhaseMembershipExceptionSet = class extends ExceptionSet {
|
|
1485
|
+
static isa = Isa.fileSystemSynchronizedGroupBuildPhaseMembershipExceptionSet;
|
|
1486
|
+
/**
|
|
1487
|
+
* The view of the build phase the listed files belong to, when the
|
|
1488
|
+
* reference resolves.
|
|
1489
|
+
*/
|
|
1490
|
+
buildPhase() {
|
|
1491
|
+
const view = this.project.get(this.getString("buildPhase"));
|
|
1492
|
+
return BuildPhase.is(view) ? view : void 0;
|
|
1493
|
+
}
|
|
1494
|
+
};
|
|
1495
|
+
/**
|
|
1309
1496
|
* A `PBXBuildRule` tells a target which compiler or script processes a
|
|
1310
1497
|
* kind of file.
|
|
1311
1498
|
*/
|
|
1312
1499
|
var BuildRule = class extends XcodeObject {
|
|
1500
|
+
static isa = Isa.buildRule;
|
|
1313
1501
|
/**
|
|
1314
1502
|
* The rule's script, when it is a script rule rather than a reference
|
|
1315
1503
|
* to a compiler specification.
|
|
@@ -1324,6 +1512,7 @@ var BuildRule = class extends XcodeObject {
|
|
|
1324
1512
|
* `currentVersion` names the active one.
|
|
1325
1513
|
*/
|
|
1326
1514
|
var VersionGroup = class extends Group {
|
|
1515
|
+
static isa = Isa.versionGroup;
|
|
1327
1516
|
/**
|
|
1328
1517
|
* The view of the active model version's file reference, when the group
|
|
1329
1518
|
* names one.
|
|
@@ -1342,10 +1531,189 @@ var VersionGroup = class extends Group {
|
|
|
1342
1531
|
}
|
|
1343
1532
|
};
|
|
1344
1533
|
/**
|
|
1534
|
+
* An `XCBuildConfiguration` holds one named settings dictionary of a
|
|
1535
|
+
* target or of the project, for example Debug or Release.
|
|
1536
|
+
*/
|
|
1537
|
+
var BuildConfiguration = class extends XcodeObject {
|
|
1538
|
+
static isa = Isa.buildConfiguration;
|
|
1539
|
+
/**
|
|
1540
|
+
* The configuration's name, when present.
|
|
1541
|
+
*/
|
|
1542
|
+
get name() {
|
|
1543
|
+
return this.getString("name");
|
|
1544
|
+
}
|
|
1545
|
+
/**
|
|
1546
|
+
* The configuration's settings dictionary, typed with the keys
|
|
1547
|
+
* programmatic edits touch most, or `undefined` when the configuration
|
|
1548
|
+
* carries none. The dictionary is live. Writes through it land in the
|
|
1549
|
+
* document.
|
|
1550
|
+
*/
|
|
1551
|
+
get buildSettings() {
|
|
1552
|
+
return asDictionary(this.properties["buildSettings"]);
|
|
1553
|
+
}
|
|
1554
|
+
};
|
|
1555
|
+
/**
|
|
1556
|
+
* A `PBXBuildStyle` is the pre-Xcode-2 predecessor of
|
|
1557
|
+
* `XCBuildConfiguration`. Current Xcode neither creates nor reads them,
|
|
1558
|
+
* but old documents still carry them.
|
|
1559
|
+
*/
|
|
1560
|
+
var BuildStyle = class extends XcodeObject {
|
|
1561
|
+
static isa = Isa.buildStyle;
|
|
1562
|
+
/**
|
|
1563
|
+
* The style's name, when present.
|
|
1564
|
+
*/
|
|
1565
|
+
get name() {
|
|
1566
|
+
return this.getString("name");
|
|
1567
|
+
}
|
|
1568
|
+
/**
|
|
1569
|
+
* The style's settings dictionary, or `undefined` when the style
|
|
1570
|
+
* carries none. The dictionary is live. Writes through it land in the
|
|
1571
|
+
* document.
|
|
1572
|
+
*/
|
|
1573
|
+
get buildSettings() {
|
|
1574
|
+
return asDictionary(this.properties["buildSettings"]);
|
|
1575
|
+
}
|
|
1576
|
+
};
|
|
1577
|
+
/**
|
|
1578
|
+
* A `PBXFileReference` names one file on disk, from source files to the
|
|
1579
|
+
* built products themselves.
|
|
1580
|
+
*/
|
|
1581
|
+
var FileReference = class extends XcodeObject {
|
|
1582
|
+
static isa = Isa.fileReference;
|
|
1583
|
+
/**
|
|
1584
|
+
* The reference's path, relative to its `sourceTree`, when present.
|
|
1585
|
+
*/
|
|
1586
|
+
get path() {
|
|
1587
|
+
return this.getString("path");
|
|
1588
|
+
}
|
|
1589
|
+
/**
|
|
1590
|
+
* The reference's display name, when it carries one distinct from the
|
|
1591
|
+
* path.
|
|
1592
|
+
*/
|
|
1593
|
+
get name() {
|
|
1594
|
+
return this.getString("name");
|
|
1595
|
+
}
|
|
1596
|
+
};
|
|
1597
|
+
/**
|
|
1598
|
+
* A `PBXContainerItemProxy` is the indirection Xcode places between a
|
|
1599
|
+
* target dependency and the target it points at.
|
|
1600
|
+
*/
|
|
1601
|
+
var ContainerItemProxy = class extends XcodeObject {
|
|
1602
|
+
static isa = Isa.containerItemProxy;
|
|
1603
|
+
/**
|
|
1604
|
+
* The display name of the object the proxy points at, when present.
|
|
1605
|
+
* For target dependencies this is the target's name.
|
|
1606
|
+
*/
|
|
1607
|
+
get remoteInfo() {
|
|
1608
|
+
return this.getString("remoteInfo");
|
|
1609
|
+
}
|
|
1610
|
+
};
|
|
1611
|
+
/**
|
|
1612
|
+
* A `PBXTargetDependency` records that one target must build before
|
|
1613
|
+
* another, through a container item proxy naming the prerequisite.
|
|
1614
|
+
*/
|
|
1615
|
+
var TargetDependency = class extends XcodeObject {
|
|
1616
|
+
static isa = Isa.targetDependency;
|
|
1617
|
+
/**
|
|
1618
|
+
* The view of the target this dependency points at, when the reference
|
|
1619
|
+
* resolves to one inside this document.
|
|
1620
|
+
*/
|
|
1621
|
+
target() {
|
|
1622
|
+
return this.project.get(this.getString("target"));
|
|
1623
|
+
}
|
|
1624
|
+
/**
|
|
1625
|
+
* The view of the dependency's container item proxy, when the reference
|
|
1626
|
+
* resolves.
|
|
1627
|
+
*/
|
|
1628
|
+
targetProxy() {
|
|
1629
|
+
const view = this.project.get(this.getString("targetProxy"));
|
|
1630
|
+
return ContainerItemProxy.is(view) ? view : void 0;
|
|
1631
|
+
}
|
|
1632
|
+
};
|
|
1633
|
+
/**
|
|
1634
|
+
* An `XCConfigurationList` owns the named build configurations of one
|
|
1635
|
+
* target or of the project, plus the default configuration choice.
|
|
1636
|
+
*/
|
|
1637
|
+
var ConfigurationList = class extends XcodeObject {
|
|
1638
|
+
static isa = Isa.configurationList;
|
|
1639
|
+
/**
|
|
1640
|
+
* The name of the configuration builds use when none is specified, when
|
|
1641
|
+
* present.
|
|
1642
|
+
*/
|
|
1643
|
+
get defaultConfigurationName() {
|
|
1644
|
+
return this.getString("defaultConfigurationName");
|
|
1645
|
+
}
|
|
1646
|
+
/**
|
|
1647
|
+
* The views of the list's build configurations, in list order. Dangling
|
|
1648
|
+
* ids and objects of other kinds are skipped.
|
|
1649
|
+
*/
|
|
1650
|
+
configurations() {
|
|
1651
|
+
const configurations = [];
|
|
1652
|
+
for (const id of stringItems(this.properties["buildConfigurations"])) {
|
|
1653
|
+
const view = this.project.get(id);
|
|
1654
|
+
if (BuildConfiguration.is(view)) configurations.push(view);
|
|
1655
|
+
}
|
|
1656
|
+
return configurations;
|
|
1657
|
+
}
|
|
1658
|
+
};
|
|
1659
|
+
/**
|
|
1660
|
+
* Behavior shared by the Swift package reference kinds. The type
|
|
1661
|
+
* parameter lets subclasses carry a more specific property shape.
|
|
1662
|
+
*/
|
|
1663
|
+
var SwiftPackageReference = class extends XcodeObject {};
|
|
1664
|
+
/**
|
|
1665
|
+
* An `XCRemoteSwiftPackageReference` names a package repository and a
|
|
1666
|
+
* version requirement.
|
|
1667
|
+
*/
|
|
1668
|
+
var RemoteSwiftPackageReference = class extends SwiftPackageReference {
|
|
1669
|
+
static isa = Isa.remoteSwiftPackageReference;
|
|
1670
|
+
/**
|
|
1671
|
+
* The package's repository URL, when present.
|
|
1672
|
+
*/
|
|
1673
|
+
get repositoryURL() {
|
|
1674
|
+
return this.getString("repositoryURL");
|
|
1675
|
+
}
|
|
1676
|
+
};
|
|
1677
|
+
/**
|
|
1678
|
+
* An `XCLocalSwiftPackageReference` names a package directory relative
|
|
1679
|
+
* to the project.
|
|
1680
|
+
*/
|
|
1681
|
+
var LocalSwiftPackageReference = class extends SwiftPackageReference {
|
|
1682
|
+
static isa = Isa.localSwiftPackageReference;
|
|
1683
|
+
/**
|
|
1684
|
+
* The package's path relative to the project, when present.
|
|
1685
|
+
*/
|
|
1686
|
+
get relativePath() {
|
|
1687
|
+
return this.getString("relativePath");
|
|
1688
|
+
}
|
|
1689
|
+
};
|
|
1690
|
+
/**
|
|
1691
|
+
* An `XCSwiftPackageProductDependency` links one product of a Swift
|
|
1692
|
+
* package to the target that consumes it.
|
|
1693
|
+
*/
|
|
1694
|
+
var SwiftPackageProductDependency = class extends XcodeObject {
|
|
1695
|
+
static isa = Isa.swiftPackageProductDependency;
|
|
1696
|
+
/**
|
|
1697
|
+
* The product's name as the package manifest declares it, when present.
|
|
1698
|
+
*/
|
|
1699
|
+
get productName() {
|
|
1700
|
+
return this.getString("productName");
|
|
1701
|
+
}
|
|
1702
|
+
/**
|
|
1703
|
+
* The view of the package reference the product comes from, when the
|
|
1704
|
+
* reference resolves. Products of local packages can omit it.
|
|
1705
|
+
*/
|
|
1706
|
+
packageReference() {
|
|
1707
|
+
const view = this.project.get(this.getString("package"));
|
|
1708
|
+
return SwiftPackageReference.is(view) ? view : void 0;
|
|
1709
|
+
}
|
|
1710
|
+
};
|
|
1711
|
+
/**
|
|
1345
1712
|
* A `PBXReferenceProxy` stands in for a product built by a target of
|
|
1346
1713
|
* another project referenced from this one.
|
|
1347
1714
|
*/
|
|
1348
1715
|
var ReferenceProxy = class extends XcodeObject {
|
|
1716
|
+
static isa = Isa.referenceProxy;
|
|
1349
1717
|
/**
|
|
1350
1718
|
* The proxy's product path inside the other project's build directory,
|
|
1351
1719
|
* when present.
|
|
@@ -1358,8 +1726,8 @@ var ReferenceProxy = class extends XcodeObject {
|
|
|
1358
1726
|
* when the reference resolves.
|
|
1359
1727
|
*/
|
|
1360
1728
|
remoteReference() {
|
|
1361
|
-
const
|
|
1362
|
-
return
|
|
1729
|
+
const view = this.project.get(this.getString("remoteRef"));
|
|
1730
|
+
return ContainerItemProxy.is(view) ? view : void 0;
|
|
1363
1731
|
}
|
|
1364
1732
|
};
|
|
1365
1733
|
//#endregion
|
|
@@ -2336,6 +2704,7 @@ const LIST_REFERENCE_PROPERTIES = [
|
|
|
2336
2704
|
"buildConfigurations",
|
|
2337
2705
|
"buildPhases",
|
|
2338
2706
|
"buildRules",
|
|
2707
|
+
"buildStyles",
|
|
2339
2708
|
"children",
|
|
2340
2709
|
"dependencies",
|
|
2341
2710
|
"exceptions",
|
|
@@ -2462,7 +2831,7 @@ function pruneOrphanObjects(project) {
|
|
|
2462
2831
|
*/
|
|
2463
2832
|
/**
|
|
2464
2833
|
* The views of a configuration list's build configurations, in list order.
|
|
2465
|
-
* Dangling ids and
|
|
2834
|
+
* Dangling ids and objects of other kinds in malformed documents are
|
|
2466
2835
|
* skipped.
|
|
2467
2836
|
*/
|
|
2468
2837
|
function configurationsOf(project, configurationListId) {
|
|
@@ -2470,7 +2839,7 @@ function configurationsOf(project, configurationListId) {
|
|
|
2470
2839
|
const configurations = [];
|
|
2471
2840
|
for (const id of stringItems(list?.["buildConfigurations"])) {
|
|
2472
2841
|
const configuration = project.get(id);
|
|
2473
|
-
if (configuration
|
|
2842
|
+
if (BuildConfiguration.is(configuration)) configurations.push(configuration);
|
|
2474
2843
|
}
|
|
2475
2844
|
return configurations;
|
|
2476
2845
|
}
|
|
@@ -2516,16 +2885,24 @@ var Target = class extends XcodeObject {
|
|
|
2516
2885
|
return this.getString("name");
|
|
2517
2886
|
}
|
|
2518
2887
|
/**
|
|
2888
|
+
* The view of the target's configuration list, when the reference
|
|
2889
|
+
* resolves.
|
|
2890
|
+
*/
|
|
2891
|
+
configurationList() {
|
|
2892
|
+
const view = this.project.get(this.getString("buildConfigurationList"));
|
|
2893
|
+
return ConfigurationList.is(view) ? view : void 0;
|
|
2894
|
+
}
|
|
2895
|
+
/**
|
|
2519
2896
|
* The views of the target's build configurations, in list order.
|
|
2520
2897
|
*/
|
|
2521
2898
|
buildConfigurations() {
|
|
2522
2899
|
return configurationsOf(this.project, this.getString("buildConfigurationList"));
|
|
2523
2900
|
}
|
|
2524
2901
|
/**
|
|
2525
|
-
* The settings dictionary of the target's default configuration
|
|
2526
|
-
* named by the list's `defaultConfigurationName`, falling
|
|
2527
|
-
* first configuration. Returns `undefined` when the target
|
|
2528
|
-
* configurations or the default carries no settings dictionary.
|
|
2902
|
+
* The settings dictionary of the target's default configuration, which
|
|
2903
|
+
* is the one named by the list's `defaultConfigurationName`, falling
|
|
2904
|
+
* back to the first configuration. Returns `undefined` when the target
|
|
2905
|
+
* has no configurations or the default carries no settings dictionary.
|
|
2529
2906
|
*/
|
|
2530
2907
|
defaultConfigurationSettings() {
|
|
2531
2908
|
return defaultConfigurationSettingsOf(this.project, this.getString("buildConfigurationList"));
|
|
@@ -2551,8 +2928,8 @@ var Target = class extends XcodeObject {
|
|
|
2551
2928
|
*/
|
|
2552
2929
|
setBuildSetting(key, value) {
|
|
2553
2930
|
for (const configuration of this.buildConfigurations()) {
|
|
2554
|
-
const settings =
|
|
2555
|
-
if (settings == null) configuration.properties
|
|
2931
|
+
const settings = configuration.buildSettings;
|
|
2932
|
+
if (settings == null) configuration.properties.buildSettings = { [key]: value };
|
|
2556
2933
|
else settings[key] = value;
|
|
2557
2934
|
}
|
|
2558
2935
|
}
|
|
@@ -2561,17 +2938,16 @@ var Target = class extends XcodeObject {
|
|
|
2561
2938
|
*/
|
|
2562
2939
|
removeBuildSetting(key) {
|
|
2563
2940
|
for (const configuration of this.buildConfigurations()) {
|
|
2564
|
-
const settings =
|
|
2941
|
+
const settings = configuration.buildSettings;
|
|
2565
2942
|
if (settings != null) delete settings[key];
|
|
2566
2943
|
}
|
|
2567
2944
|
}
|
|
2568
2945
|
/**
|
|
2569
|
-
* The views of the target's
|
|
2570
|
-
*
|
|
2571
|
-
* target through its `target` property.
|
|
2946
|
+
* The views of the target's dependencies, in declaration order. Resolve
|
|
2947
|
+
* a dependency's target through {@link TargetDependency.target}.
|
|
2572
2948
|
*/
|
|
2573
2949
|
dependencies() {
|
|
2574
|
-
return this.referencedViews("dependencies");
|
|
2950
|
+
return this.referencedViews("dependencies").filter((view) => TargetDependency.is(view));
|
|
2575
2951
|
}
|
|
2576
2952
|
/**
|
|
2577
2953
|
* The views of the target's build phases, in build order.
|
|
@@ -2622,7 +2998,7 @@ var Target = class extends XcodeObject {
|
|
|
2622
2998
|
* @param properties Phase properties, most usefully `shellScript`.
|
|
2623
2999
|
*/
|
|
2624
3000
|
ensureShellScriptPhase(name, properties = {}) {
|
|
2625
|
-
return this.ensureBuildPhase(
|
|
3001
|
+
return this.ensureBuildPhase(Isa.shellScriptBuildPhase, {
|
|
2626
3002
|
inputFileListPaths: [],
|
|
2627
3003
|
inputPaths: [],
|
|
2628
3004
|
name,
|
|
@@ -2641,10 +3017,7 @@ var Target = class extends XcodeObject {
|
|
|
2641
3017
|
* @returns The view of the target dependency object.
|
|
2642
3018
|
*/
|
|
2643
3019
|
addDependency(dependency) {
|
|
2644
|
-
for (const
|
|
2645
|
-
const existing = this.project.get(id);
|
|
2646
|
-
if (existing?.getString("target") === dependency.id) return existing;
|
|
2647
|
-
}
|
|
3020
|
+
for (const dependencyView of this.dependencies()) if (dependencyView.getString("target") === dependency.id) return dependencyView;
|
|
2648
3021
|
const proxy = this.project.add(Isa.containerItemProxy, {
|
|
2649
3022
|
containerPortal: this.project.rootProject.id,
|
|
2650
3023
|
proxyType: 1,
|
|
@@ -2664,6 +3037,7 @@ var Target = class extends XcodeObject {
|
|
|
2664
3037
|
* itself, such as an application or an app extension.
|
|
2665
3038
|
*/
|
|
2666
3039
|
var NativeTarget = class extends Target {
|
|
3040
|
+
static isa = Isa.nativeTarget;
|
|
2667
3041
|
/**
|
|
2668
3042
|
* The target's product type identifier, for example
|
|
2669
3043
|
* `com.apple.product-type.application`.
|
|
@@ -2683,8 +3057,8 @@ var NativeTarget = class extends Target {
|
|
|
2683
3057
|
* one.
|
|
2684
3058
|
*/
|
|
2685
3059
|
get productReference() {
|
|
2686
|
-
const
|
|
2687
|
-
return
|
|
3060
|
+
const view = this.project.get(this.getString("productReference"));
|
|
3061
|
+
return FileReference.is(view) ? view : void 0;
|
|
2688
3062
|
}
|
|
2689
3063
|
/**
|
|
2690
3064
|
* Whether the target builds for watchOS, decided by its product type or
|
|
@@ -2700,21 +3074,21 @@ var NativeTarget = class extends Target {
|
|
|
2700
3074
|
* declaration order.
|
|
2701
3075
|
*/
|
|
2702
3076
|
packageProductDependencies() {
|
|
2703
|
-
return this.referencedViews("packageProductDependencies");
|
|
3077
|
+
return this.referencedViews("packageProductDependencies").filter((view) => SwiftPackageProductDependency.is(view));
|
|
2704
3078
|
}
|
|
2705
3079
|
/**
|
|
2706
3080
|
* The views of the target's file-system-synchronized folders, in
|
|
2707
3081
|
* declaration order.
|
|
2708
3082
|
*/
|
|
2709
3083
|
syncGroups() {
|
|
2710
|
-
return this.referencedViews("fileSystemSynchronizedGroups").filter((view) => view
|
|
3084
|
+
return this.referencedViews("fileSystemSynchronizedGroups").filter((view) => SyncRootGroup.is(view));
|
|
2711
3085
|
}
|
|
2712
3086
|
/**
|
|
2713
3087
|
* The views of the target's build rules, in evaluation order. Empty for
|
|
2714
3088
|
* targets without custom rules, which is nearly all of them.
|
|
2715
3089
|
*/
|
|
2716
3090
|
buildRules() {
|
|
2717
|
-
return this.referencedViews("buildRules").filter((view) => view
|
|
3091
|
+
return this.referencedViews("buildRules").filter((view) => BuildRule.is(view));
|
|
2718
3092
|
}
|
|
2719
3093
|
/**
|
|
2720
3094
|
* The target's sources phase, created when missing.
|
|
@@ -2764,9 +3138,8 @@ var NativeTarget = class extends Target {
|
|
|
2764
3138
|
*/
|
|
2765
3139
|
syncGroupPaths() {
|
|
2766
3140
|
const paths = [];
|
|
2767
|
-
for (const
|
|
2768
|
-
const
|
|
2769
|
-
const path = group instanceof SyncRootGroup ? group.path : void 0;
|
|
3141
|
+
for (const group of this.syncGroups()) {
|
|
3142
|
+
const path = group.path;
|
|
2770
3143
|
if (path != null) paths.push(path);
|
|
2771
3144
|
}
|
|
2772
3145
|
return paths;
|
|
@@ -2783,10 +3156,7 @@ var NativeTarget = class extends Target {
|
|
|
2783
3156
|
* @returns The view of the target's synchronized folder for the path.
|
|
2784
3157
|
*/
|
|
2785
3158
|
addSyncGroup(path) {
|
|
2786
|
-
for (const
|
|
2787
|
-
const existing = this.project.get(id);
|
|
2788
|
-
if (existing instanceof SyncRootGroup && existing.path === path) return existing;
|
|
2789
|
-
}
|
|
3159
|
+
for (const existing of this.syncGroups()) if (existing.path === path) return existing;
|
|
2790
3160
|
const group = this.project.add(Isa.fileSystemSynchronizedRootGroup, {
|
|
2791
3161
|
path,
|
|
2792
3162
|
sourceTree: "<group>"
|
|
@@ -2809,10 +3179,7 @@ var NativeTarget = class extends Target {
|
|
|
2809
3179
|
* @returns The view of the product dependency.
|
|
2810
3180
|
*/
|
|
2811
3181
|
addSwiftPackageProduct(options) {
|
|
2812
|
-
for (const
|
|
2813
|
-
const existing = this.project.get(id);
|
|
2814
|
-
if (existing?.getString("productName") === options.productName && existing.getString("package") === options.packageReference.id) return existing;
|
|
2815
|
-
}
|
|
3182
|
+
for (const existing of this.packageProductDependencies()) if (existing.productName === options.productName && existing.getString("package") === options.packageReference.id) return existing;
|
|
2816
3183
|
const productDependency = this.project.add(Isa.swiftPackageProductDependency, {
|
|
2817
3184
|
package: options.packageReference.id,
|
|
2818
3185
|
productName: options.productName
|
|
@@ -2833,7 +3200,7 @@ var NativeTarget = class extends Target {
|
|
|
2833
3200
|
addSystemFramework(name) {
|
|
2834
3201
|
const path = `System/Library/Frameworks/${name}.framework`;
|
|
2835
3202
|
let reference;
|
|
2836
|
-
for (const [, view] of this.project.objects()) if (view
|
|
3203
|
+
for (const [, view] of this.project.objects()) if (FileReference.is(view) && view.path === path) {
|
|
2837
3204
|
reference = view;
|
|
2838
3205
|
break;
|
|
2839
3206
|
}
|
|
@@ -2852,12 +3219,15 @@ var NativeTarget = class extends Target {
|
|
|
2852
3219
|
* targets through its dependencies and to run script or copy-files
|
|
2853
3220
|
* phases, and the shared target surface covers everything it carries.
|
|
2854
3221
|
*/
|
|
2855
|
-
var AggregateTarget = class extends Target {
|
|
3222
|
+
var AggregateTarget = class extends Target {
|
|
3223
|
+
static isa = Isa.aggregateTarget;
|
|
3224
|
+
};
|
|
2856
3225
|
/**
|
|
2857
3226
|
* A legacy target shells out to an external build tool such as make
|
|
2858
3227
|
* instead of using Xcode's build system.
|
|
2859
3228
|
*/
|
|
2860
3229
|
var LegacyTarget = class extends Target {
|
|
3230
|
+
static isa = Isa.legacyTarget;
|
|
2861
3231
|
/**
|
|
2862
3232
|
* The build tool the target invokes, as an absolute path.
|
|
2863
3233
|
*/
|
|
@@ -2898,6 +3268,7 @@ var LegacyTarget = class extends Target {
|
|
|
2898
3268
|
* the main group, and the project-level configurations.
|
|
2899
3269
|
*/
|
|
2900
3270
|
var RootProject = class extends XcodeObject {
|
|
3271
|
+
static isa = Isa.project;
|
|
2901
3272
|
/**
|
|
2902
3273
|
* Ids of the project's targets, in project order.
|
|
2903
3274
|
*/
|
|
@@ -2910,7 +3281,7 @@ var RootProject = class extends XcodeObject {
|
|
|
2910
3281
|
*/
|
|
2911
3282
|
mainGroup() {
|
|
2912
3283
|
const group = this.project.get(this.getString("mainGroup"));
|
|
2913
|
-
return group
|
|
3284
|
+
return Group.is(group) ? group : void 0;
|
|
2914
3285
|
}
|
|
2915
3286
|
/**
|
|
2916
3287
|
* The settings dictionary of the project-level default configuration.
|
|
@@ -2925,7 +3296,7 @@ var RootProject = class extends XcodeObject {
|
|
|
2925
3296
|
* in declaration order.
|
|
2926
3297
|
*/
|
|
2927
3298
|
packageReferences() {
|
|
2928
|
-
return this.referencedViews("packageReferences");
|
|
3299
|
+
return this.referencedViews("packageReferences").filter((view) => SwiftPackageReference.is(view));
|
|
2929
3300
|
}
|
|
2930
3301
|
/**
|
|
2931
3302
|
* The group product references live in, creating it (and registering it
|
|
@@ -2933,7 +3304,7 @@ var RootProject = class extends XcodeObject {
|
|
|
2933
3304
|
*/
|
|
2934
3305
|
ensureProductsGroup() {
|
|
2935
3306
|
const existing = this.project.get(this.getString("productRefGroup"));
|
|
2936
|
-
if (existing
|
|
3307
|
+
if (Group.is(existing)) return existing;
|
|
2937
3308
|
const group = this.project.add(Isa.group, {
|
|
2938
3309
|
children: [],
|
|
2939
3310
|
name: "Products",
|
|
@@ -3167,10 +3538,7 @@ var XcodeProject = class XcodeProject {
|
|
|
3167
3538
|
* Finds the remote Swift package reference for a repository URL.
|
|
3168
3539
|
*/
|
|
3169
3540
|
findSwiftPackage(repositoryUrl) {
|
|
3170
|
-
|
|
3171
|
-
const reference = this.get(id);
|
|
3172
|
-
if (reference?.getString("repositoryURL") === repositoryUrl) return reference;
|
|
3173
|
-
}
|
|
3541
|
+
return this.rootProject.packageReferences().filter((reference) => RemoteSwiftPackageReference.is(reference)).find((reference) => reference.repositoryURL === repositoryUrl);
|
|
3174
3542
|
}
|
|
3175
3543
|
/**
|
|
3176
3544
|
* Adds a remote Swift package reference and registers it on the project.
|
|
@@ -3199,7 +3567,7 @@ var XcodeProject = class XcodeProject {
|
|
|
3199
3567
|
* Finds the local Swift package reference for a directory path.
|
|
3200
3568
|
*/
|
|
3201
3569
|
findLocalSwiftPackage(relativePath) {
|
|
3202
|
-
return this.rootProject.packageReferences().
|
|
3570
|
+
return this.rootProject.packageReferences().filter((reference) => LocalSwiftPackageReference.is(reference)).find((reference) => reference.relativePath === relativePath);
|
|
3203
3571
|
}
|
|
3204
3572
|
/**
|
|
3205
3573
|
* Adds a local (path-based) Swift package reference and registers it on
|
|
@@ -3224,7 +3592,7 @@ var XcodeProject = class XcodeProject {
|
|
|
3224
3592
|
*/
|
|
3225
3593
|
buildFilesReferencing(reference) {
|
|
3226
3594
|
const buildFiles = [];
|
|
3227
|
-
for (const [, view] of this.objects()) if (view
|
|
3595
|
+
for (const [, view] of this.objects()) if (BuildFile.is(view) && (view.getString("fileRef") === reference.id || view.getString("productRef") === reference.id)) buildFiles.push(view);
|
|
3228
3596
|
return buildFiles;
|
|
3229
3597
|
}
|
|
3230
3598
|
/**
|
|
@@ -3356,26 +3724,61 @@ var XcodeProject = class XcodeProject {
|
|
|
3356
3724
|
return search(mainGroup, "");
|
|
3357
3725
|
}
|
|
3358
3726
|
/**
|
|
3359
|
-
* Creates the typed view for an object, dispatching on
|
|
3360
|
-
*
|
|
3727
|
+
* Creates the typed view for an object, dispatching on the isa each
|
|
3728
|
+
* view class declares. Unknown `PBX*BuildPhase` kinds still map to
|
|
3729
|
+
* {@link BuildPhase}, and everything else outside the vocabulary gets
|
|
3730
|
+
* the generic base view.
|
|
3361
3731
|
*/
|
|
3362
3732
|
createView(id, isa) {
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
case Isa.legacyTarget: return new LegacyTarget(this, id);
|
|
3367
|
-
case Isa.project: return new RootProject(this, id);
|
|
3368
|
-
case Isa.group:
|
|
3369
|
-
case Isa.variantGroup: return new Group(this, id);
|
|
3370
|
-
case Isa.versionGroup: return new VersionGroup(this, id);
|
|
3371
|
-
case Isa.fileSystemSynchronizedRootGroup: return new SyncRootGroup(this, id);
|
|
3372
|
-
case Isa.buildRule: return new BuildRule(this, id);
|
|
3373
|
-
case Isa.referenceProxy: return new ReferenceProxy(this, id);
|
|
3374
|
-
default: return isa.endsWith("BuildPhase") ? new BuildPhase(this, id) : new XcodeObject(this, id);
|
|
3375
|
-
}
|
|
3733
|
+
const View = VIEW_BY_ISA.get(isa);
|
|
3734
|
+
if (View != null) return new View(this, id);
|
|
3735
|
+
return isa.endsWith("BuildPhase") ? new BuildPhase(this, id) : new XcodeObject(this, id);
|
|
3376
3736
|
}
|
|
3377
3737
|
};
|
|
3378
3738
|
/**
|
|
3739
|
+
* Every concrete view class of the object model. The registry below is
|
|
3740
|
+
* derived from this list, so adding a view class with its `isa` is all
|
|
3741
|
+
* it takes to route objects of that kind to it.
|
|
3742
|
+
*/
|
|
3743
|
+
const VIEW_CLASSES = [
|
|
3744
|
+
AggregateTarget,
|
|
3745
|
+
AppleScriptBuildPhase,
|
|
3746
|
+
BuildConfiguration,
|
|
3747
|
+
BuildFile,
|
|
3748
|
+
BuildFileExceptionSet,
|
|
3749
|
+
BuildPhaseMembershipExceptionSet,
|
|
3750
|
+
BuildRule,
|
|
3751
|
+
BuildStyle,
|
|
3752
|
+
ConfigurationList,
|
|
3753
|
+
ContainerItemProxy,
|
|
3754
|
+
CopyFilesBuildPhase,
|
|
3755
|
+
FileReference,
|
|
3756
|
+
FrameworksBuildPhase,
|
|
3757
|
+
Group,
|
|
3758
|
+
HeadersBuildPhase,
|
|
3759
|
+
LegacyTarget,
|
|
3760
|
+
LocalSwiftPackageReference,
|
|
3761
|
+
NativeTarget,
|
|
3762
|
+
ReferenceProxy,
|
|
3763
|
+
RemoteSwiftPackageReference,
|
|
3764
|
+
ResourcesBuildPhase,
|
|
3765
|
+
RezBuildPhase,
|
|
3766
|
+
RootProject,
|
|
3767
|
+
ShellScriptBuildPhase,
|
|
3768
|
+
SourcesBuildPhase,
|
|
3769
|
+
SwiftPackageProductDependency,
|
|
3770
|
+
SyncRootGroup,
|
|
3771
|
+
TargetDependency,
|
|
3772
|
+
VariantGroup,
|
|
3773
|
+
VersionGroup
|
|
3774
|
+
];
|
|
3775
|
+
/**
|
|
3776
|
+
* View constructors by the isa they model, built from each class's own
|
|
3777
|
+
* `isa` declaration.
|
|
3778
|
+
*/
|
|
3779
|
+
const VIEW_BY_ISA = /* @__PURE__ */ new Map();
|
|
3780
|
+
for (const viewClass of VIEW_CLASSES) if (viewClass.isa != null) VIEW_BY_ISA.set(viewClass.isa, viewClass);
|
|
3781
|
+
/**
|
|
3379
3782
|
* Joins two path segments with a `/`, treating an empty prefix as the
|
|
3380
3783
|
* project root.
|
|
3381
3784
|
*/
|
|
@@ -3454,26 +3857,28 @@ function isXcschemeElement(node) {
|
|
|
3454
3857
|
/**
|
|
3455
3858
|
* Serializer for the `.xcscheme` XML dialect.
|
|
3456
3859
|
*
|
|
3457
|
-
* The output reproduces Xcode's own layout byte for byte
|
|
3458
|
-
* declaration, three
|
|
3459
|
-
* spaces around the equals sign, the closing
|
|
3460
|
-
* last attribute, and
|
|
3461
|
-
* Xcode-written scheme and building it
|
|
3462
|
-
*
|
|
3860
|
+
* The output reproduces Xcode's own layout byte for byte. Xcode writes
|
|
3861
|
+
* the UTF-8 declaration, indents with three spaces, puts each attribute
|
|
3862
|
+
* on its own line with spaces around the equals sign, glues the closing
|
|
3863
|
+
* angle bracket to the last attribute, and closes every element with an
|
|
3864
|
+
* explicit close tag. Parsing an Xcode-written scheme and building it
|
|
3865
|
+
* back therefore yields the identical file, and any other input reaches
|
|
3866
|
+
* that canonical form in one build.
|
|
3463
3867
|
*
|
|
3464
3868
|
* @module
|
|
3465
3869
|
*/
|
|
3870
|
+
/** The declaration line Xcode writes at the top of every scheme file. */
|
|
3466
3871
|
const XML_DECLARATION = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
|
|
3467
3872
|
/** One indentation step of Xcode's scheme writer. */
|
|
3468
3873
|
const INDENT = " ";
|
|
3469
3874
|
/**
|
|
3470
|
-
* Matches
|
|
3471
|
-
*
|
|
3875
|
+
* Matches valid XML names. A stray non-name, such as an empty string or
|
|
3876
|
+
* one carrying spaces or XML syntax, must fail rather than produce a
|
|
3472
3877
|
* document no parser accepts.
|
|
3473
3878
|
*/
|
|
3474
3879
|
const NAME_PATTERN = /^[A-Za-z_:][A-Za-z0-9_:.-]*$/u;
|
|
3475
3880
|
/**
|
|
3476
|
-
* Matches characters that cannot appear in an attribute value
|
|
3881
|
+
* Matches characters that cannot appear in an attribute value. XML 1.0
|
|
3477
3882
|
* has no representation for control characters other than tab, line
|
|
3478
3883
|
* feed, and carriage return.
|
|
3479
3884
|
*/
|
|
@@ -3493,9 +3898,10 @@ function buildXcscheme(document) {
|
|
|
3493
3898
|
return output;
|
|
3494
3899
|
}
|
|
3495
3900
|
/**
|
|
3496
|
-
* Renders one element with Xcode's layout
|
|
3497
|
-
* line indented one step past the tag, `>`
|
|
3498
|
-
* children
|
|
3901
|
+
* Renders one element with Xcode's layout. Attributes go each on their
|
|
3902
|
+
* own line indented one step past the tag, the `>` glues to the last
|
|
3903
|
+
* attribute, children indent one step, and the close tag is always
|
|
3904
|
+
* explicit.
|
|
3499
3905
|
*/
|
|
3500
3906
|
function renderElement(element, depth, path) {
|
|
3501
3907
|
if (!NAME_PATTERN.test(element.name)) throw new XcschemeBuildError(`Element name ${JSON.stringify(element.name)} is not a valid XML name`, path);
|
|
@@ -3533,10 +3939,10 @@ function renderChildren(children, depth, path) {
|
|
|
3533
3939
|
return output;
|
|
3534
3940
|
}
|
|
3535
3941
|
/**
|
|
3536
|
-
* Escapes an attribute value the way Xcode's writer does
|
|
3537
|
-
*
|
|
3538
|
-
*
|
|
3539
|
-
* normalization on the next parse.
|
|
3942
|
+
* Escapes an attribute value the way Xcode's writer does. XML syntax
|
|
3943
|
+
* characters become the five named entities, and tab, line feed, and
|
|
3944
|
+
* carriage return become character references so they survive
|
|
3945
|
+
* attribute-value normalization on the next parse.
|
|
3540
3946
|
*/
|
|
3541
3947
|
function escapeAttribute(value, path, attributeName) {
|
|
3542
3948
|
const unencodable = UNENCODABLE_PATTERN.exec(value);
|
|
@@ -3544,152 +3950,17 @@ function escapeAttribute(value, path, attributeName) {
|
|
|
3544
3950
|
return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll("\"", """).replaceAll("'", "'").replaceAll(" ", "	").replaceAll("\n", " ").replaceAll("\r", " ");
|
|
3545
3951
|
}
|
|
3546
3952
|
//#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
3953
|
//#region src/scheme/parse.ts
|
|
3684
3954
|
/**
|
|
3685
3955
|
* Parser for the `.xcscheme` XML dialect.
|
|
3686
3956
|
*
|
|
3687
|
-
* Scheme files are XML with a narrow shape
|
|
3688
|
-
* child elements, no text content, no
|
|
3689
|
-
* accepts that shape from any writer
|
|
3690
|
-
* whitespace vary across tools
|
|
3691
|
-
* in attribute values
|
|
3692
|
-
*
|
|
3957
|
+
* Scheme files are XML with a narrow shape. Elements carry attributes and
|
|
3958
|
+
* child elements, and there is no text content, no namespace, and no
|
|
3959
|
+
* DOCTYPE. The parser accepts that shape from any writer, since attribute
|
|
3960
|
+
* order, quoting style, and whitespace vary across tools. Character and
|
|
3961
|
+
* entity references in attribute values resolve to their characters, and
|
|
3962
|
+
* comments are preserved. Anything outside the shape fails loudly with a
|
|
3963
|
+
* position, in line with the pbxproj parser.
|
|
3693
3964
|
*
|
|
3694
3965
|
* @module
|
|
3695
3966
|
*/
|
|
@@ -3746,13 +4017,24 @@ const NAMED_ENTITIES = {
|
|
|
3746
4017
|
function parseXcscheme(text) {
|
|
3747
4018
|
return new Parser(text).parseDocument();
|
|
3748
4019
|
}
|
|
4020
|
+
/**
|
|
4021
|
+
* Single-pass recursive-descent parser over the source text. One instance
|
|
4022
|
+
* parses one document and is discarded.
|
|
4023
|
+
*/
|
|
3749
4024
|
var Parser = class {
|
|
4025
|
+
/** The full source text of the scheme file. */
|
|
3750
4026
|
input;
|
|
4027
|
+
/** Cursor into {@link input}, in UTF-16 code units. */
|
|
3751
4028
|
pos = 0;
|
|
3752
4029
|
constructor(input) {
|
|
3753
4030
|
this.input = input;
|
|
3754
4031
|
if (input.charCodeAt(0) === CODE_BOM) this.pos = 1;
|
|
3755
4032
|
}
|
|
4033
|
+
/**
|
|
4034
|
+
* Parses the whole document. The XML declaration is skipped, comments
|
|
4035
|
+
* around the root element are collected, and anything left after the
|
|
4036
|
+
* root fails.
|
|
4037
|
+
*/
|
|
3756
4038
|
parseDocument() {
|
|
3757
4039
|
this.skipWhitespace();
|
|
3758
4040
|
this.skipDeclaration();
|
|
@@ -3778,7 +4060,8 @@ var Parser = class {
|
|
|
3778
4060
|
}
|
|
3779
4061
|
/**
|
|
3780
4062
|
* Skips the `<?xml ... ?>` declaration when present. Its attributes are
|
|
3781
|
-
* not retained
|
|
4063
|
+
* not retained, since the writer always emits the canonical UTF-8
|
|
4064
|
+
* declaration.
|
|
3782
4065
|
*/
|
|
3783
4066
|
skipDeclaration() {
|
|
3784
4067
|
if (this.input.charCodeAt(this.pos) !== CODE_LESS_THAN || this.input.charCodeAt(this.pos + 1) !== CODE_QUESTION) return;
|
|
@@ -3786,6 +4069,12 @@ var Parser = class {
|
|
|
3786
4069
|
if (end === -1) this.fail("Unterminated XML declaration");
|
|
3787
4070
|
this.pos = end + 2;
|
|
3788
4071
|
}
|
|
4072
|
+
/**
|
|
4073
|
+
* Parses one element with the cursor on its opening `<`, including its
|
|
4074
|
+
* attributes and children, through to the matching close tag. Xcode
|
|
4075
|
+
* never writes self-closing tags, but other generators do, so both
|
|
4076
|
+
* forms are accepted.
|
|
4077
|
+
*/
|
|
3789
4078
|
parseElement() {
|
|
3790
4079
|
if (this.input.charCodeAt(this.pos) !== CODE_LESS_THAN) this.fail("Expected an element");
|
|
3791
4080
|
this.pos++;
|
|
@@ -3839,9 +4128,16 @@ var Parser = class {
|
|
|
3839
4128
|
else children.push(this.parseElement());
|
|
3840
4129
|
}
|
|
3841
4130
|
}
|
|
4131
|
+
/**
|
|
4132
|
+
* Whether the cursor sits on a `<!--` comment opener.
|
|
4133
|
+
*/
|
|
3842
4134
|
peekIsCommentStart() {
|
|
3843
4135
|
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
4136
|
}
|
|
4137
|
+
/**
|
|
4138
|
+
* Parses one comment with the cursor on its `<!--` opener. The text
|
|
4139
|
+
* between the markers is kept verbatim.
|
|
4140
|
+
*/
|
|
3845
4141
|
parseComment() {
|
|
3846
4142
|
const end = this.input.indexOf("-->", this.pos + 4);
|
|
3847
4143
|
if (end === -1) this.fail("Unterminated comment");
|
|
@@ -3849,6 +4145,10 @@ var Parser = class {
|
|
|
3849
4145
|
this.pos = end + 3;
|
|
3850
4146
|
return { comment };
|
|
3851
4147
|
}
|
|
4148
|
+
/**
|
|
4149
|
+
* Parses an XML name at the cursor. The `what` label names the
|
|
4150
|
+
* expectation in the error when no name starts here.
|
|
4151
|
+
*/
|
|
3852
4152
|
parseName(what) {
|
|
3853
4153
|
const start = this.pos;
|
|
3854
4154
|
if (!isNameStart(this.input.charCodeAt(this.pos))) this.fail(`Expected ${what}`);
|
|
@@ -3856,6 +4156,12 @@ var Parser = class {
|
|
|
3856
4156
|
while (isNameChar(this.input.charCodeAt(this.pos))) this.pos++;
|
|
3857
4157
|
return this.input.slice(start, this.pos);
|
|
3858
4158
|
}
|
|
4159
|
+
/**
|
|
4160
|
+
* Parses a quoted attribute value with the cursor on the opening quote,
|
|
4161
|
+
* resolving character and entity references along the way. Both quote
|
|
4162
|
+
* styles are accepted, and a raw `<` inside the value fails as XML
|
|
4163
|
+
* requires.
|
|
4164
|
+
*/
|
|
3859
4165
|
parseAttributeValue() {
|
|
3860
4166
|
const quote = this.input.charCodeAt(this.pos);
|
|
3861
4167
|
if (quote !== CODE_QUOTE && quote !== CODE_APOSTROPHE) this.fail("Expected a quoted attribute value");
|
|
@@ -3912,12 +4218,275 @@ var Parser = class {
|
|
|
3912
4218
|
while (isWhitespace(this.input.charCodeAt(this.pos))) this.pos++;
|
|
3913
4219
|
return this.pos > start;
|
|
3914
4220
|
}
|
|
4221
|
+
/**
|
|
4222
|
+
* Throws a parse error at the cursor.
|
|
4223
|
+
*/
|
|
3915
4224
|
fail(message) {
|
|
3916
4225
|
this.failAt(message, this.pos);
|
|
3917
4226
|
}
|
|
4227
|
+
/**
|
|
4228
|
+
* Throws a parse error at an explicit offset, which reference parsing
|
|
4229
|
+
* uses to point at the start of a bad reference rather than its end.
|
|
4230
|
+
*/
|
|
3918
4231
|
failAt(message, offset) {
|
|
3919
4232
|
throw new XcschemeParseError(message, this.input, offset);
|
|
3920
4233
|
}
|
|
3921
4234
|
};
|
|
3922
4235
|
//#endregion
|
|
3923
|
-
|
|
4236
|
+
//#region src/scheme/model.ts
|
|
4237
|
+
/**
|
|
4238
|
+
* The scheme object model and its helpers.
|
|
4239
|
+
*
|
|
4240
|
+
* {@link Xcscheme} wraps a parsed document with the typed access editing
|
|
4241
|
+
* flows want, {@link BuildableReference} gives buildable references
|
|
4242
|
+
* property-style attribute access, {@link xcschemeElements} is the
|
|
4243
|
+
* recursive query underneath it all, and {@link createXcscheme} produces
|
|
4244
|
+
* the scheme Xcode's own "New Scheme" action writes. The node tree stays
|
|
4245
|
+
* the single source of truth. Views hold only a reference into it, so
|
|
4246
|
+
* model calls and direct tree edits compose freely.
|
|
4247
|
+
*
|
|
4248
|
+
* @module
|
|
4249
|
+
*/
|
|
4250
|
+
/**
|
|
4251
|
+
* Collects elements of the given name anywhere in the tree, in document
|
|
4252
|
+
* order, the subtree root included. Passing no name collects every
|
|
4253
|
+
* element.
|
|
4254
|
+
*/
|
|
4255
|
+
function xcschemeElements(root, name) {
|
|
4256
|
+
const found = [];
|
|
4257
|
+
const visit = (element) => {
|
|
4258
|
+
if (name == null || element.name === name) found.push(element);
|
|
4259
|
+
for (const child of element.children) if (isXcschemeElement(child)) visit(child);
|
|
4260
|
+
};
|
|
4261
|
+
visit(root);
|
|
4262
|
+
return found;
|
|
4263
|
+
}
|
|
4264
|
+
/**
|
|
4265
|
+
* A `BuildableReference` element with property-style attribute access.
|
|
4266
|
+
*
|
|
4267
|
+
* Buildable references are the elements editing flows touch most, since
|
|
4268
|
+
* every action points at its target through one. The view reads and
|
|
4269
|
+
* writes the element's attributes directly, so it never goes stale and
|
|
4270
|
+
* needs no separate save step.
|
|
4271
|
+
*/
|
|
4272
|
+
var BuildableReference = class {
|
|
4273
|
+
/** The underlying element inside the document tree. */
|
|
4274
|
+
element;
|
|
4275
|
+
constructor(element) {
|
|
4276
|
+
this.element = element;
|
|
4277
|
+
}
|
|
4278
|
+
/**
|
|
4279
|
+
* The referenced target's object id in the project document, when
|
|
4280
|
+
* present. Xcode repairs a missing or stale identifier on first open.
|
|
4281
|
+
*/
|
|
4282
|
+
get blueprintIdentifier() {
|
|
4283
|
+
return this.element.attributes["BlueprintIdentifier"];
|
|
4284
|
+
}
|
|
4285
|
+
set blueprintIdentifier(value) {
|
|
4286
|
+
this.element.attributes["BlueprintIdentifier"] = value;
|
|
4287
|
+
}
|
|
4288
|
+
/**
|
|
4289
|
+
* The referenced target's name, when present.
|
|
4290
|
+
*/
|
|
4291
|
+
get blueprintName() {
|
|
4292
|
+
return this.element.attributes["BlueprintName"];
|
|
4293
|
+
}
|
|
4294
|
+
set blueprintName(value) {
|
|
4295
|
+
this.element.attributes["BlueprintName"] = value;
|
|
4296
|
+
}
|
|
4297
|
+
/**
|
|
4298
|
+
* The built product's file name, for example `DemoApp.app`, when
|
|
4299
|
+
* present.
|
|
4300
|
+
*/
|
|
4301
|
+
get buildableName() {
|
|
4302
|
+
return this.element.attributes["BuildableName"];
|
|
4303
|
+
}
|
|
4304
|
+
set buildableName(value) {
|
|
4305
|
+
this.element.attributes["BuildableName"] = value;
|
|
4306
|
+
}
|
|
4307
|
+
/**
|
|
4308
|
+
* The container the target lives in, for example
|
|
4309
|
+
* `container:DemoApp.xcodeproj`, when present.
|
|
4310
|
+
*/
|
|
4311
|
+
get referencedContainer() {
|
|
4312
|
+
return this.element.attributes["ReferencedContainer"];
|
|
4313
|
+
}
|
|
4314
|
+
set referencedContainer(value) {
|
|
4315
|
+
this.element.attributes["ReferencedContainer"] = value;
|
|
4316
|
+
}
|
|
4317
|
+
};
|
|
4318
|
+
/**
|
|
4319
|
+
* A scheme document with typed access to the elements editing flows
|
|
4320
|
+
* touch.
|
|
4321
|
+
*
|
|
4322
|
+
* The model is a thin layer over the node tree. All state lives in the
|
|
4323
|
+
* document itself, and {@link build} serializes whatever the tree
|
|
4324
|
+
* currently says, so typed edits and direct tree edits compose freely.
|
|
4325
|
+
*
|
|
4326
|
+
* ```ts
|
|
4327
|
+
* const scheme = Xcscheme.parse(xcschemeText);
|
|
4328
|
+
* for (const reference of scheme.buildableReferences()) {
|
|
4329
|
+
* reference.blueprintName = "RenamedApp";
|
|
4330
|
+
* reference.buildableName = "RenamedApp.app";
|
|
4331
|
+
* }
|
|
4332
|
+
* const text = scheme.build();
|
|
4333
|
+
* ```
|
|
4334
|
+
*/
|
|
4335
|
+
var Xcscheme = class Xcscheme {
|
|
4336
|
+
/** The underlying parsed document. */
|
|
4337
|
+
document;
|
|
4338
|
+
constructor(document) {
|
|
4339
|
+
this.document = document;
|
|
4340
|
+
}
|
|
4341
|
+
/**
|
|
4342
|
+
* Parses the text of a `.xcscheme` file into a scheme model.
|
|
4343
|
+
*
|
|
4344
|
+
* @throws XcschemeParseError when the text is not a well-formed scheme
|
|
4345
|
+
* document, with the line and column of the failure.
|
|
4346
|
+
*/
|
|
4347
|
+
static parse(text) {
|
|
4348
|
+
return new Xcscheme(parseXcscheme(text));
|
|
4349
|
+
}
|
|
4350
|
+
/**
|
|
4351
|
+
* Creates the scheme Xcode writes for an application target. See
|
|
4352
|
+
* {@link createXcscheme} for the shape it produces.
|
|
4353
|
+
*/
|
|
4354
|
+
static create(options) {
|
|
4355
|
+
return new Xcscheme(createXcscheme(options));
|
|
4356
|
+
}
|
|
4357
|
+
/**
|
|
4358
|
+
* The document's `Scheme` element.
|
|
4359
|
+
*/
|
|
4360
|
+
get root() {
|
|
4361
|
+
return this.document.root;
|
|
4362
|
+
}
|
|
4363
|
+
/**
|
|
4364
|
+
* Serializes the scheme to the text of a `.xcscheme` file in Xcode's
|
|
4365
|
+
* canonical layout.
|
|
4366
|
+
*/
|
|
4367
|
+
build() {
|
|
4368
|
+
return buildXcscheme(this.document);
|
|
4369
|
+
}
|
|
4370
|
+
/**
|
|
4371
|
+
* Collects elements of the given name anywhere in the document, in
|
|
4372
|
+
* document order. Passing no name collects every element.
|
|
4373
|
+
*/
|
|
4374
|
+
elements(name) {
|
|
4375
|
+
return xcschemeElements(this.document.root, name);
|
|
4376
|
+
}
|
|
4377
|
+
/**
|
|
4378
|
+
* The views of every buildable reference in the document, in document
|
|
4379
|
+
* order. Build entries, testables, macro expansions, runnables, and
|
|
4380
|
+
* action environment buildables all point at their target through one
|
|
4381
|
+
* of these, so rename flows iterate this list.
|
|
4382
|
+
*/
|
|
4383
|
+
buildableReferences() {
|
|
4384
|
+
return this.elements("BuildableReference").map((element) => new BuildableReference(element));
|
|
4385
|
+
}
|
|
4386
|
+
};
|
|
4387
|
+
/**
|
|
4388
|
+
* Creates the scheme Xcode writes for an application target. The
|
|
4389
|
+
* document carries build, launch, profile, analyze, and archive actions
|
|
4390
|
+
* wired to the app product, with Xcode's default configuration choices
|
|
4391
|
+
* of Debug for development actions and Release for profiling and
|
|
4392
|
+
* archiving.
|
|
4393
|
+
*/
|
|
4394
|
+
function createXcscheme(options) {
|
|
4395
|
+
const xcodeprojName = options.xcodeprojName ?? `${options.appName}.xcodeproj`;
|
|
4396
|
+
/**
|
|
4397
|
+
* Buildable references appear once per action. Each site gets its own
|
|
4398
|
+
* element so a mutation through one action cannot alias into another.
|
|
4399
|
+
*/
|
|
4400
|
+
const buildableReference = () => ({
|
|
4401
|
+
name: "BuildableReference",
|
|
4402
|
+
attributes: {
|
|
4403
|
+
BuildableIdentifier: "primary",
|
|
4404
|
+
BlueprintIdentifier: options.blueprintIdentifier ?? "",
|
|
4405
|
+
BuildableName: `${options.appName}.app`,
|
|
4406
|
+
BlueprintName: options.appName,
|
|
4407
|
+
ReferencedContainer: `container:${xcodeprojName}`
|
|
4408
|
+
},
|
|
4409
|
+
children: []
|
|
4410
|
+
});
|
|
4411
|
+
return {
|
|
4412
|
+
leading: [],
|
|
4413
|
+
root: {
|
|
4414
|
+
name: "Scheme",
|
|
4415
|
+
attributes: { version: "1.7" },
|
|
4416
|
+
children: [
|
|
4417
|
+
{
|
|
4418
|
+
name: "BuildAction",
|
|
4419
|
+
attributes: {
|
|
4420
|
+
parallelizeBuildables: "YES",
|
|
4421
|
+
buildImplicitDependencies: "YES"
|
|
4422
|
+
},
|
|
4423
|
+
children: [{
|
|
4424
|
+
name: "BuildActionEntries",
|
|
4425
|
+
attributes: {},
|
|
4426
|
+
children: [{
|
|
4427
|
+
name: "BuildActionEntry",
|
|
4428
|
+
attributes: {
|
|
4429
|
+
buildForTesting: "YES",
|
|
4430
|
+
buildForRunning: "YES",
|
|
4431
|
+
buildForProfiling: "YES",
|
|
4432
|
+
buildForArchiving: "YES",
|
|
4433
|
+
buildForAnalyzing: "YES"
|
|
4434
|
+
},
|
|
4435
|
+
children: [buildableReference()]
|
|
4436
|
+
}]
|
|
4437
|
+
}]
|
|
4438
|
+
},
|
|
4439
|
+
{
|
|
4440
|
+
name: "LaunchAction",
|
|
4441
|
+
attributes: {
|
|
4442
|
+
buildConfiguration: "Debug",
|
|
4443
|
+
selectedDebuggerIdentifier: "Xcode.DebuggerFoundation.Debugger.LLDB",
|
|
4444
|
+
selectedLauncherIdentifier: "Xcode.DebuggerFoundation.Launcher.LLDB",
|
|
4445
|
+
launchStyle: "0",
|
|
4446
|
+
useCustomWorkingDirectory: "NO",
|
|
4447
|
+
ignoresPersistentStateOnLaunch: "NO",
|
|
4448
|
+
debugDocumentVersioning: "YES",
|
|
4449
|
+
debugServiceExtension: "internal",
|
|
4450
|
+
allowLocationSimulation: "YES"
|
|
4451
|
+
},
|
|
4452
|
+
children: [{
|
|
4453
|
+
name: "BuildableProductRunnable",
|
|
4454
|
+
attributes: { runnableDebuggingMode: "0" },
|
|
4455
|
+
children: [buildableReference()]
|
|
4456
|
+
}]
|
|
4457
|
+
},
|
|
4458
|
+
{
|
|
4459
|
+
name: "ProfileAction",
|
|
4460
|
+
attributes: {
|
|
4461
|
+
buildConfiguration: "Release",
|
|
4462
|
+
shouldUseLaunchSchemeArgsEnv: "YES",
|
|
4463
|
+
savedToolIdentifier: "",
|
|
4464
|
+
useCustomWorkingDirectory: "NO",
|
|
4465
|
+
debugDocumentVersioning: "YES"
|
|
4466
|
+
},
|
|
4467
|
+
children: [{
|
|
4468
|
+
name: "BuildableProductRunnable",
|
|
4469
|
+
attributes: { runnableDebuggingMode: "0" },
|
|
4470
|
+
children: [buildableReference()]
|
|
4471
|
+
}]
|
|
4472
|
+
},
|
|
4473
|
+
{
|
|
4474
|
+
name: "AnalyzeAction",
|
|
4475
|
+
attributes: { buildConfiguration: "Debug" },
|
|
4476
|
+
children: []
|
|
4477
|
+
},
|
|
4478
|
+
{
|
|
4479
|
+
name: "ArchiveAction",
|
|
4480
|
+
attributes: {
|
|
4481
|
+
buildConfiguration: "Release",
|
|
4482
|
+
revealArchiveInOrganizer: "YES"
|
|
4483
|
+
},
|
|
4484
|
+
children: []
|
|
4485
|
+
}
|
|
4486
|
+
]
|
|
4487
|
+
},
|
|
4488
|
+
trailing: []
|
|
4489
|
+
};
|
|
4490
|
+
}
|
|
4491
|
+
//#endregion
|
|
4492
|
+
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, parsePbxproj, parseXcscheme, xcschemeElements };
|