Parser utility for xcodeproj/project.pbxproj files that allows editing and writing back Xcode project files
Core functionality for loading and saving Xcode project files with support for both asynchronous and synchronous operations.
Parse Xcode project files (.pbxproj) into a manipulable JavaScript object structure.
/**
* Parse project file asynchronously using worker process
* Uses a forked child process to avoid blocking the main thread
* @param {function} callback - Callback function(err, project)
*/
parse(callback);
/**
* Parse project file synchronously
* Blocks execution until parsing is complete
* @returns {pbxProject} Self for chaining
*/
parseSync();Usage Examples:
const xcode = require('xcode');
const proj = xcode.project('path/to/project.pbxproj');
// Asynchronous parsing (recommended for large projects)
proj.parse(function(err) {
if (err) {
console.error('Parse error:', err);
return;
}
console.log('Project parsed successfully');
console.log('Product name:', proj.productName);
// Project is ready for manipulation
proj.addSourceFile('MyNewFile.m');
});
// Synchronous parsing (simpler but blocking)
try {
proj.parseSync();
console.log('Project loaded:', proj.productName);
} catch (err) {
console.error('Parse error:', err);
}Serialize project data back to the pbxproj file format for saving to disk.
/**
* Write project data to string format
* Converts the internal project structure back to pbxproj format
* @param {object} options - Formatting options for output control
* @returns {string} Serialized project data ready for file writing
*/
writeSync(options);Usage Examples:
const fs = require('fs');
// Basic writing
const projectData = proj.writeSync();
fs.writeFileSync('project.pbxproj', projectData);
// Writing with formatting options
const projectData = proj.writeSync({
omitEmptyValues: true, // Remove empty arrays/objects
omitBuildFileSection: false, // Keep build file section
omitGroupChildren: false // Keep group children arrays
});
fs.writeFileSync('project.pbxproj', projectData);/**
* Options for controlling project serialization
*/
interface WriterOptions {
/** Remove empty values from output to reduce file size */
omitEmptyValues?: boolean;
/** Exclude build file section from output */
omitBuildFileSection?: boolean;
/** Exclude group children arrays from output */
omitGroupChildren?: boolean;
}The parsing operations can throw or return several types of errors:
// Common error scenarios
proj.parse(function(err) {
if (err) {
if (err.name === 'SyntaxError') {
console.error('Invalid pbxproj file format:', err.message);
} else if (err.code) {
console.error('System error:', err.code, err.message);
} else {
console.error('Unknown parsing error:', err);
}
}
});
// Synchronous error handling
try {
proj.parseSync();
} catch (err) {
if (err.name === 'SyntaxError') {
throw new Error('Invalid project file format');
}
throw err;
}After parsing, the project data is available in the hash property:
/**
* Parsed project data structure
*/
interface ProjectHash {
/** Project metadata and configuration */
project: {
/** Root object UUID */
rootObject: string;
/** Project object sections */
objects: {
/** Project configuration */
PBXProject: object;
/** Build files */
PBXBuildFile: object;
/** File references */
PBXFileReference: object;
/** Groups */
PBXGroup: object;
/** Native targets */
PBXNativeTarget: object;
/** Build configurations */
XCBuildConfiguration: object;
/** Configuration lists */
XCConfigurationList: object;
/** Build phases */
PBXSourcesBuildPhase: object;
PBXResourcesBuildPhase: object;
PBXFrameworksBuildPhase: object;
PBXCopyFilesBuildPhase?: object;
PBXShellScriptBuildPhase?: object;
/** Target dependencies */
PBXTargetDependency?: object;
PBXContainerItemProxy?: object;
/** Variant groups for localization */
PBXVariantGroup?: object;
/** Core Data version groups */
XCVersionGroup?: object;
};
};
}Usage Examples:
// Access parsed data directly
proj.parse(function(err) {
if (err) throw err;
// Access project sections
const buildFiles = proj.hash.project.objects.PBXBuildFile;
const fileReferences = proj.hash.project.objects.PBXFileReference;
const groups = proj.hash.project.objects.PBXGroup;
// Count files in project
const buildFileCount = Object.keys(buildFiles).filter(key => !key.endsWith('_comment')).length;
console.log('Build files in project:', buildFileCount);
// Find specific groups
for (let key in groups) {
if (!key.endsWith('_comment')) {
const group = groups[key];
console.log('Group:', group.name, 'Children:', group.children?.length || 0);
}
}
});Install with Tessl CLI
npx tessl i tessl/npm-xcode