@xcodekit/xcode 0.1.0 → 0.3.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 +94 -42
- package/index.d.ts +62 -0
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -42,10 +42,18 @@ writeFileSync("project.pbxproj", output);
|
|
|
42
42
|
|
|
43
43
|
Parse a `.pbxproj` string into a JSON-compatible object. Matches the output of `@bacons/xcode/json`'s `parse()`.
|
|
44
44
|
|
|
45
|
+
```js
|
|
46
|
+
const project = parse(readFileSync("project.pbxproj", "utf8"));
|
|
47
|
+
```
|
|
48
|
+
|
|
45
49
|
#### `build(project: object): string`
|
|
46
50
|
|
|
47
51
|
Serialize a JSON object back to `.pbxproj` format. Produces byte-identical output to `@bacons/xcode/json`'s `build()`.
|
|
48
52
|
|
|
53
|
+
```js
|
|
54
|
+
writeFileSync("project.pbxproj", build(project));
|
|
55
|
+
```
|
|
56
|
+
|
|
49
57
|
#### `buildFromJSON(json: string): string`
|
|
50
58
|
|
|
51
59
|
Same as `build()` but accepts `JSON.stringify(project)` directly. Faster because it avoids napi's recursive JS-to-Rust object marshalling.
|
|
@@ -64,32 +72,74 @@ const output = parseAndBuild(readFileSync("project.pbxproj", "utf8"));
|
|
|
64
72
|
|
|
65
73
|
### High-Level (XcodeProject)
|
|
66
74
|
|
|
67
|
-
#### `XcodeProject.open(filePath
|
|
75
|
+
#### `XcodeProject.open(filePath)` / `XcodeProject.fromString(content)`
|
|
68
76
|
|
|
69
|
-
Open
|
|
77
|
+
Open from disk or parse from a string (e.g. content fetched over the network).
|
|
70
78
|
|
|
71
79
|
```js
|
|
72
80
|
import { XcodeProject } from "@xcodekit/xcode";
|
|
73
81
|
|
|
82
|
+
// From disk
|
|
74
83
|
const project = XcodeProject.open("ios/MyApp.xcodeproj/project.pbxproj");
|
|
75
84
|
|
|
85
|
+
// From string (no file on disk needed)
|
|
86
|
+
const project = XcodeProject.fromString(pbxprojContent);
|
|
87
|
+
|
|
76
88
|
// Properties
|
|
77
89
|
project.archiveVersion; // 1
|
|
78
|
-
project.objectVersion;
|
|
79
|
-
project.filePath;
|
|
90
|
+
project.objectVersion; // 46
|
|
91
|
+
project.filePath; // path if opened from disk, null if fromString
|
|
92
|
+
project.mainGroupUuid; // root group UUID
|
|
80
93
|
|
|
81
94
|
// Targets
|
|
82
95
|
const targets = project.getNativeTargets(); // UUID[]
|
|
83
96
|
const mainApp = project.findMainAppTarget("ios"); // UUID | null
|
|
97
|
+
project.getTargetName(mainApp); // "MyApp"
|
|
98
|
+
project.setTargetName(mainApp, "NewName");
|
|
84
99
|
|
|
85
100
|
// Build settings
|
|
86
101
|
project.getBuildSetting(targetUuid, "PRODUCT_BUNDLE_IDENTIFIER");
|
|
87
102
|
project.setBuildSetting(targetUuid, "SWIFT_VERSION", "5.0");
|
|
88
103
|
project.removeBuildSetting(targetUuid, "CODE_SIGN_IDENTITY");
|
|
89
104
|
|
|
105
|
+
// Files & groups
|
|
106
|
+
const fileUuid = project.addFile(project.mainGroupUuid, "Sources/App.swift");
|
|
107
|
+
const groupUuid = project.addGroup(project.mainGroupUuid, "Features");
|
|
108
|
+
const children = project.getGroupChildren(groupUuid);
|
|
109
|
+
|
|
110
|
+
// Build phases
|
|
111
|
+
const phase = project.ensureBuildPhase(targetUuid, "PBXSourcesBuildPhase");
|
|
112
|
+
project.addBuildFile(phase, fileUuid);
|
|
113
|
+
|
|
114
|
+
// Frameworks
|
|
115
|
+
project.addFramework(targetUuid, "SwiftUI");
|
|
116
|
+
|
|
117
|
+
// Create targets
|
|
118
|
+
const widgetTarget = project.createNativeTarget(
|
|
119
|
+
"MyWidget",
|
|
120
|
+
"com.apple.product-type.app-extension",
|
|
121
|
+
"com.example.mywidget",
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
// Embed extension into host app
|
|
125
|
+
project.addDependency(mainApp, widgetTarget);
|
|
126
|
+
project.embedExtension(mainApp, widgetTarget);
|
|
127
|
+
|
|
128
|
+
// Xcode 16+ file system sync groups
|
|
129
|
+
project.addFileSystemSyncGroup(widgetTarget, "MyWidget");
|
|
130
|
+
|
|
131
|
+
// Generic object access
|
|
132
|
+
project.getObjectProperty(uuid, "path");
|
|
133
|
+
project.setObjectProperty(uuid, "path", "new/path");
|
|
134
|
+
const proxies = project.findObjectsByIsa("PBXContainerItemProxy");
|
|
135
|
+
|
|
136
|
+
// Validation
|
|
137
|
+
const orphans = project.findOrphanedReferences();
|
|
138
|
+
// [{ referrerUuid, referrerIsa, property, orphanUuid }]
|
|
139
|
+
|
|
90
140
|
// Serialize
|
|
91
141
|
const pbxproj = project.toBuild(); // string
|
|
92
|
-
const json = project.toJSON();
|
|
142
|
+
const json = project.toJSON(); // object
|
|
93
143
|
|
|
94
144
|
// Write back to disk
|
|
95
145
|
project.save();
|
|
@@ -98,46 +148,48 @@ project.save();
|
|
|
98
148
|
const uuid = project.getUniqueId("my-seed-string"); // 24-char hex
|
|
99
149
|
```
|
|
100
150
|
|
|
151
|
+
All `XcodeProject` methods operate in Rust — only primitive strings cross the JS/Rust boundary. This is the fastest path for project manipulation.
|
|
152
|
+
|
|
101
153
|
## Performance
|
|
102
154
|
|
|
103
155
|
Benchmarked on Apple M4 Pro, Node.js v24. Median of 200 iterations.
|
|
104
156
|
|
|
105
157
|
### Parse
|
|
106
158
|
|
|
107
|
-
| Fixture
|
|
108
|
-
|
|
109
|
-
| swift-protobuf (257 KB)
|
|
110
|
-
| Cocoa-Application (166 KB) | 3.2 ms | 17.3 ms
|
|
111
|
-
| AFNetworking (99 KB)
|
|
112
|
-
| watch (48 KB)
|
|
113
|
-
| project (19 KB)
|
|
159
|
+
| Fixture | Rust | TypeScript | Speedup |
|
|
160
|
+
| -------------------------- | ------ | ---------- | --------- |
|
|
161
|
+
| swift-protobuf (257 KB) | 3.7 ms | 43.5 ms | **11.6x** |
|
|
162
|
+
| Cocoa-Application (166 KB) | 3.2 ms | 17.3 ms | **5.5x** |
|
|
163
|
+
| AFNetworking (99 KB) | 1.8 ms | 6.6 ms | **3.8x** |
|
|
164
|
+
| watch (48 KB) | 0.9 ms | 2.1 ms | **2.2x** |
|
|
165
|
+
| project (19 KB) | 0.4 ms | 0.8 ms | **2.2x** |
|
|
114
166
|
|
|
115
167
|
### Round-Trip (parse + build)
|
|
116
168
|
|
|
117
|
-
| Fixture
|
|
118
|
-
|
|
119
|
-
| swift-protobuf (257 KB)
|
|
120
|
-
| Cocoa-Application (166 KB) | 8.0 ms | 22.2 ms
|
|
121
|
-
| AFNetworking (99 KB)
|
|
122
|
-
| watch (48 KB)
|
|
123
|
-
| project (19 KB)
|
|
169
|
+
| Fixture | Rust | TypeScript | Speedup |
|
|
170
|
+
| -------------------------- | ------ | ---------- | -------- |
|
|
171
|
+
| swift-protobuf (257 KB) | 9.1 ms | 63.1 ms | **6.9x** |
|
|
172
|
+
| Cocoa-Application (166 KB) | 8.0 ms | 22.2 ms | **2.8x** |
|
|
173
|
+
| AFNetworking (99 KB) | 4.2 ms | 9.3 ms | **2.2x** |
|
|
174
|
+
| watch (48 KB) | 2.1 ms | 2.7 ms | **1.3x** |
|
|
175
|
+
| project (19 KB) | 0.8 ms | 1.0 ms | **1.2x** |
|
|
124
176
|
|
|
125
177
|
### parseAndBuild (zero marshalling)
|
|
126
178
|
|
|
127
|
-
| Fixture
|
|
128
|
-
|
|
129
|
-
| swift-protobuf (257 KB)
|
|
130
|
-
| Cocoa-Application (166 KB) | 3.8 ms | 22.0 ms
|
|
131
|
-
| AFNetworking (99 KB)
|
|
132
|
-
| watch (48 KB)
|
|
133
|
-
| project (19 KB)
|
|
179
|
+
| Fixture | Rust | TypeScript | Speedup |
|
|
180
|
+
| -------------------------- | ------ | ---------- | --------- |
|
|
181
|
+
| swift-protobuf (257 KB) | 4.6 ms | 62.9 ms | **13.6x** |
|
|
182
|
+
| Cocoa-Application (166 KB) | 3.8 ms | 22.0 ms | **5.8x** |
|
|
183
|
+
| AFNetworking (99 KB) | 1.9 ms | 9.1 ms | **4.9x** |
|
|
184
|
+
| watch (48 KB) | 0.9 ms | 2.6 ms | **2.8x** |
|
|
185
|
+
| project (19 KB) | 0.4 ms | 1.0 ms | **2.7x** |
|
|
134
186
|
|
|
135
187
|
### Package Size
|
|
136
188
|
|
|
137
|
-
|
|
|
138
|
-
|
|
139
|
-
| Unpacked | 1.1 MB
|
|
140
|
-
| Gzipped
|
|
189
|
+
| | @bacons/xcode | @xcodekit/xcode |
|
|
190
|
+
| -------- | ------------- | --------------- |
|
|
191
|
+
| Unpacked | 1.1 MB | 559 KB |
|
|
192
|
+
| Gzipped | ~400 KB | ~270 KB |
|
|
141
193
|
|
|
142
194
|
Run benchmarks yourself:
|
|
143
195
|
|
|
@@ -149,13 +201,13 @@ make bench-js # Rust vs TypeScript head-to-head
|
|
|
149
201
|
|
|
150
202
|
## Choosing the Right Function
|
|
151
203
|
|
|
152
|
-
| Use case
|
|
153
|
-
|
|
154
|
-
| Parse only
|
|
155
|
-
| Build from JS object
|
|
156
|
-
| Build from JSON string | `buildFromJSON(json)` | Faster than `build()` on all sizes
|
|
157
|
-
| Full round-trip
|
|
158
|
-
| Project manipulation
|
|
204
|
+
| Use case | Function | Notes |
|
|
205
|
+
| ---------------------- | --------------------- | -------------------------------------------- |
|
|
206
|
+
| Parse only | `parse(text)` | 2-12x faster than TS |
|
|
207
|
+
| Build from JS object | `build(obj)` | Fastest on large files (>100 KB) |
|
|
208
|
+
| Build from JSON string | `buildFromJSON(json)` | Faster than `build()` on all sizes |
|
|
209
|
+
| Full round-trip | `parseAndBuild(text)` | Fastest path, zero JS/Rust overhead |
|
|
210
|
+
| Project manipulation | `XcodeProject.open()` | Stays in Rust, use `.toBuild()` to serialize |
|
|
159
211
|
|
|
160
212
|
## Compatibility
|
|
161
213
|
|
|
@@ -168,11 +220,11 @@ make bench-js # Rust vs TypeScript head-to-head
|
|
|
168
220
|
|
|
169
221
|
## Supported Platforms
|
|
170
222
|
|
|
171
|
-
| Platform | Architecture
|
|
172
|
-
|
|
173
|
-
| macOS
|
|
174
|
-
| Linux
|
|
175
|
-
| Windows
|
|
223
|
+
| Platform | Architecture |
|
|
224
|
+
| -------- | ---------------------------------- |
|
|
225
|
+
| macOS | arm64 (Apple Silicon), x64 (Intel) |
|
|
226
|
+
| Linux | x64 (glibc), arm64 (glibc) |
|
|
227
|
+
| Windows | x64 (MSVC) |
|
|
176
228
|
|
|
177
229
|
## Development
|
|
178
230
|
|
package/index.d.ts
CHANGED
|
@@ -22,6 +22,8 @@ export declare function parseAndBuild(text: string): string
|
|
|
22
22
|
export declare class XcodeProject {
|
|
23
23
|
/** Open and parse a .pbxproj file from disk. */
|
|
24
24
|
static open(filePath: string): XcodeProject
|
|
25
|
+
/** Parse a .pbxproj string into an XcodeProject (no file on disk needed). */
|
|
26
|
+
static fromString(content: string): XcodeProject
|
|
25
27
|
/** Convert the project to a JSON-compatible object. */
|
|
26
28
|
toJSON(): any
|
|
27
29
|
/** Serialize the project back to .pbxproj format. */
|
|
@@ -51,4 +53,64 @@ export declare class XcodeProject {
|
|
|
51
53
|
findMainAppTarget(platform?: string | undefined | null): string | null
|
|
52
54
|
/** Generate a unique UUID. */
|
|
53
55
|
getUniqueId(seed: string): string
|
|
56
|
+
/** Get the main group UUID. */
|
|
57
|
+
get mainGroupUuid(): string | null
|
|
58
|
+
/** Get children UUIDs of a group. */
|
|
59
|
+
getGroupChildren(groupUuid: string): Array<string>
|
|
60
|
+
/**
|
|
61
|
+
* Add a file reference to the project and a group.
|
|
62
|
+
* Returns the UUID of the new PBXFileReference.
|
|
63
|
+
*/
|
|
64
|
+
addFile(groupUuid: string, path: string): string | null
|
|
65
|
+
/**
|
|
66
|
+
* Create a group and add it as a child of a parent group.
|
|
67
|
+
* Returns the UUID of the new PBXGroup.
|
|
68
|
+
*/
|
|
69
|
+
addGroup(parentUuid: string, name: string): string | null
|
|
70
|
+
/**
|
|
71
|
+
* Add a build file to a build phase.
|
|
72
|
+
* Returns the UUID of the new PBXBuildFile.
|
|
73
|
+
*/
|
|
74
|
+
addBuildFile(phaseUuid: string, fileRefUuid: string): string | null
|
|
75
|
+
/**
|
|
76
|
+
* Find or create a build phase for a target.
|
|
77
|
+
* Returns the UUID of the build phase.
|
|
78
|
+
*/
|
|
79
|
+
ensureBuildPhase(targetUuid: string, phaseIsa: string): string | null
|
|
80
|
+
/**
|
|
81
|
+
* Add a framework to a target.
|
|
82
|
+
* Returns the UUID of the PBXBuildFile.
|
|
83
|
+
*/
|
|
84
|
+
addFramework(targetUuid: string, frameworkName: string): string | null
|
|
85
|
+
/**
|
|
86
|
+
* Create a native target with Debug/Release configs, standard build phases, and product ref.
|
|
87
|
+
* Returns the UUID of the new PBXNativeTarget.
|
|
88
|
+
*/
|
|
89
|
+
createNativeTarget(name: string, productType: string, bundleId: string): string | null
|
|
90
|
+
/**
|
|
91
|
+
* Add a dependency from one target to another.
|
|
92
|
+
* Returns the UUID of the PBXTargetDependency.
|
|
93
|
+
*/
|
|
94
|
+
addDependency(targetUuid: string, dependsOnUuid: string): string | null
|
|
95
|
+
/**
|
|
96
|
+
* Embed an extension target into a host app target.
|
|
97
|
+
* Creates PBXCopyFilesBuildPhase with correct dstSubfolderSpec.
|
|
98
|
+
* Returns the UUID of the copy files build phase.
|
|
99
|
+
*/
|
|
100
|
+
embedExtension(hostTargetUuid: string, extensionTargetUuid: string): string | null
|
|
101
|
+
/**
|
|
102
|
+
* Add a PBXFileSystemSynchronizedRootGroup to a target (Xcode 16+).
|
|
103
|
+
* Returns the UUID of the sync group.
|
|
104
|
+
*/
|
|
105
|
+
addFileSystemSyncGroup(targetUuid: string, path: string): string | null
|
|
106
|
+
/** Get a string property from any object. */
|
|
107
|
+
getObjectProperty(uuid: string, key: string): string | null
|
|
108
|
+
/** Set a string property on any object. */
|
|
109
|
+
setObjectProperty(uuid: string, key: string, value: string): boolean
|
|
110
|
+
/** Find all object UUIDs matching a given ISA type. */
|
|
111
|
+
findObjectsByIsa(isa: string): Array<string>
|
|
112
|
+
/** Get the name of a target. */
|
|
113
|
+
getTargetName(targetUuid: string): string | null
|
|
114
|
+
/** Set the name and productName of a target. */
|
|
115
|
+
setTargetName(targetUuid: string, name: string): boolean
|
|
54
116
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xcodekit/xcode",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Parse, manipulate, and serialize Xcode .pbxproj files — native Rust rewrite",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -16,11 +16,11 @@
|
|
|
16
16
|
},
|
|
17
17
|
"license": "MIT",
|
|
18
18
|
"optionalDependencies": {
|
|
19
|
-
"@xcodekit/xcode-darwin-arm64": "0.
|
|
20
|
-
"@xcodekit/xcode-darwin-x64": "0.
|
|
21
|
-
"@xcodekit/xcode-linux-arm64-gnu": "0.
|
|
22
|
-
"@xcodekit/xcode-linux-x64-gnu": "0.
|
|
23
|
-
"@xcodekit/xcode-win32-x64-msvc": "0.
|
|
19
|
+
"@xcodekit/xcode-darwin-arm64": "0.3.0",
|
|
20
|
+
"@xcodekit/xcode-darwin-x64": "0.3.0",
|
|
21
|
+
"@xcodekit/xcode-linux-arm64-gnu": "0.3.0",
|
|
22
|
+
"@xcodekit/xcode-linux-x64-gnu": "0.3.0",
|
|
23
|
+
"@xcodekit/xcode-win32-x64-msvc": "0.3.0"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
26
|
"@napi-rs/cli": "^2.18.0",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
],
|
|
45
45
|
"repository": {
|
|
46
46
|
"type": "git",
|
|
47
|
-
"url": "https://github.com/
|
|
47
|
+
"url": "https://github.com/mozharovsky/xcode"
|
|
48
48
|
},
|
|
49
49
|
"keywords": [
|
|
50
50
|
"xcode",
|