Skip to content

Commit afd812b

Browse files
EvanBaconclaude
andcommitted
Add XCWorkspace support for parsing and building workspace files
- Add low-level workspace module (src/workspace/) with parser, writer, types - Add high-level XCWorkspace API class with open(), create(), save() methods - Support all location types: group, container, absolute, developer, self - Support nested groups in workspaces - Use package.json exports instead of top-level entry point files - Add comprehensive tests matching XcodeProj test coverage (55 tests) - Update README with workspace documentation Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 8e49ff6 commit afd812b

20 files changed

Lines changed: 1409 additions & 13 deletions

README.md

Lines changed: 78 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -116,13 +116,16 @@ import * as scheme from "@bacons/xcode/scheme";
116116
import fs from "fs";
117117

118118
// Parse an xcscheme file
119-
const xml = fs.readFileSync("/path/to/Project.xcodeproj/xcshareddata/xcschemes/App.xcscheme", "utf-8");
119+
const xml = fs.readFileSync(
120+
"/path/to/Project.xcodeproj/xcshareddata/xcschemes/App.xcscheme",
121+
"utf-8",
122+
);
120123
const xcscheme = scheme.parse(xml);
121124

122125
// Modify the scheme
123126
xcscheme.buildAction.parallelizeBuildables = true;
124127
xcscheme.launchAction.environmentVariables = [
125-
{ key: "DEBUG", value: "1", isEnabled: true }
128+
{ key: "DEBUG", value: "1", isEnabled: true },
126129
];
127130

128131
// Serialize back to XML
@@ -144,7 +147,7 @@ const appScheme = project.getScheme("App");
144147
const newScheme = XCScheme.create("MyNewScheme");
145148
newScheme.addBuildTarget({
146149
buildableIdentifier: "primary",
147-
blueprintIdentifier: "ABC123", // Target UUID
150+
blueprintIdentifier: "ABC123", // Target UUID
148151
buildableName: "App.app",
149152
blueprintName: "App",
150153
referencedContainer: "container:Project.xcodeproj",
@@ -179,6 +182,77 @@ console.log(management.SchemeUserState?.["App.xcscheme"]?.isShown);
179182
const output = scheme.buildManagement(management);
180183
```
181184

185+
## XCWorkspace Support
186+
187+
Parse and manipulate Xcode workspace files (`.xcworkspace`). Workspaces group multiple Xcode projects together, commonly used with CocoaPods, monorepos, and multi-project setups.
188+
189+
### Low-level API
190+
191+
```ts
192+
import * as workspace from "@bacons/xcode/workspace";
193+
import fs from "fs";
194+
195+
// Parse a workspace file
196+
const xml = fs.readFileSync(
197+
"/path/to/MyApp.xcworkspace/contents.xcworkspacedata",
198+
"utf-8",
199+
);
200+
const ws = workspace.parse(xml);
201+
202+
// Access project references
203+
console.log(ws.fileRefs); // [{ location: "group:App.xcodeproj" }, ...]
204+
205+
// Modify the workspace
206+
ws.fileRefs?.push({ location: "group:NewProject.xcodeproj" });
207+
208+
// Serialize back to XML
209+
const outputXml = workspace.build(ws);
210+
fs.writeFileSync("/path/to/contents.xcworkspacedata", outputXml);
211+
```
212+
213+
### High-level API
214+
215+
```ts
216+
import { XCWorkspace } from "@bacons/xcode";
217+
218+
// Open an existing workspace
219+
const workspace = XCWorkspace.open("/path/to/MyApp.xcworkspace");
220+
221+
// Get all project paths
222+
const projects = workspace.getProjectPaths();
223+
console.log(projects); // ["group:App.xcodeproj", "group:Pods/Pods.xcodeproj"]
224+
225+
// Check if workspace contains a project
226+
if (!workspace.hasProject("NewProject.xcodeproj")) {
227+
workspace.addProject("NewProject.xcodeproj");
228+
}
229+
230+
// Remove a project
231+
workspace.removeProject("OldProject.xcodeproj");
232+
233+
// Work with groups
234+
const group = workspace.addGroup("Libraries", "group:Libraries");
235+
group.fileRefs?.push({ location: "group:Libraries/MyLib.xcodeproj" });
236+
237+
// Save changes
238+
workspace.save();
239+
240+
// Create a new workspace
241+
const newWorkspace = XCWorkspace.create("MyWorkspace");
242+
newWorkspace.addProject("App.xcodeproj");
243+
newWorkspace.addProject("Pods/Pods.xcodeproj");
244+
newWorkspace.save("/path/to/MyWorkspace.xcworkspace");
245+
```
246+
247+
### Location Types
248+
249+
Workspace file references use location specifiers:
250+
251+
- `group:path` - Relative path from workspace root (most common)
252+
- `self:` - Self-reference (embedded workspace inside `.xcodeproj`)
253+
- `container:path` - Absolute container reference (rare)
254+
- `absolute:path` - Absolute file path
255+
182256
## Solution
183257

184258
- Unlike the [xcode](https://www.npmjs.com/package/xcode) package which uses PEG.js, this implementation uses [Chevrotain](https://chevrotain.io/).
@@ -205,7 +279,7 @@ We support the following types: `Object`, `Array`, `Data`, `String`. Notably, we
205279
- [x] Reference-type API.
206280
- [x] Build setting parsing.
207281
- [x] xcscheme support.
208-
- [ ] xcworkspace support.
282+
- [x] xcworkspace support.
209283
- [ ] Benchmarks.
210284
- [ ] Create robust xcode projects from scratch.
211285
- [ ] Skills.

json.d.ts

Lines changed: 0 additions & 1 deletion
This file was deleted.

json.js

Lines changed: 0 additions & 1 deletion
This file was deleted.

package.json

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"name": "@bacons/xcode",
33
"version": "1.0.0-alpha.29",
44
"main": "./build/index",
5+
"types": "./build/index.d.ts",
56
"description": "pbxproj parser",
67
"license": "MIT",
78
"repository": {
@@ -15,12 +16,26 @@
1516
"xcode",
1617
"ios"
1718
],
19+
"exports": {
20+
".": {
21+
"types": "./build/index.d.ts",
22+
"default": "./build/index.js"
23+
},
24+
"./json": {
25+
"types": "./build/json/index.d.ts",
26+
"default": "./build/json/index.js"
27+
},
28+
"./scheme": {
29+
"types": "./build/scheme/index.d.ts",
30+
"default": "./build/scheme/index.js"
31+
},
32+
"./workspace": {
33+
"types": "./build/workspace/index.d.ts",
34+
"default": "./build/workspace/index.js"
35+
}
36+
},
1837
"files": [
19-
"build",
20-
"json.js",
21-
"json.d.ts",
22-
"scheme.js",
23-
"scheme.d.ts"
38+
"build"
2439
],
2540
"dependencies": {
2641
"@expo/plist": "^0.0.18",

scheme.d.ts

Lines changed: 0 additions & 1 deletion
This file was deleted.

scheme.js

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)