{"library":"pbxproj-dom","title":"Xcode Project File DOM Parser","description":"pbxproj-dom is a JavaScript/TypeScript library designed to parse and manipulate Xcode's `project.pbxproj` files, providing a Document Object Model (DOM) for programmatic access. It aims to offer a JavaScript API similar to Cocoapods' Ruby-based project modification capabilities. The current stable version is 1.2.0, released in April 2019. The project appears to be in maintenance mode, with infrequent updates since its last major release. Its primary differentiator is enabling direct, code-driven modifications to Xcode project settings and configurations without requiring manual interaction with Xcode itself, facilitating automation of tasks such as setting build configurations, managing signing styles, or modifying build settings within a Node.js environment.","language":"javascript","status":"maintenance","last_verified":"Sun Apr 19","install":{"commands":["npm install pbxproj-dom"],"cli":null},"imports":["import { Xcode } from 'pbxproj-dom/xcode';","import type { Xcode } from 'pbxproj-dom/xcode';"],"auth":{"required":false,"env_vars":[]},"quickstart":{"code":"import { Xcode } from 'pbxproj-dom/xcode';\nimport path from 'path';\nimport fs from 'fs';\n\n// Define paths for a dummy Xcode project for demonstration\nconst dummyProjectPath = './temp-test.xcodeproj';\nconst dummyPbxprojPath = path.join(dummyProjectPath, 'project.pbxproj');\n\n// Create the dummy project directory if it doesn't exist\nif (!fs.existsSync(dummyProjectPath)) {\n  fs.mkdirSync(dummyProjectPath, { recursive: true });\n}\n\n// A minimal, valid pbxproj content for testing purposes\nconst minimalPbxprojContent = `// !$*UTF8*$!\\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n/* End PBXBuildFile section */\n\n/* Begin PBXContainerItemProxy section */\n/* End PBXContainerItemProxy section */\n\n/* Begin PBXFileReference section */\n/* End PBXFileReference section */\n\n/* Begin PBXGroup section */\n\t\t08FB7C8017B03F0100B1A761 /* CustomFolder */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t);\n\t\t\tpath = CustomFolder;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tmainGroup = 08FB7C8017B03F0100B1A761;\n/* End PBXGroup section */\n\n/* Begin PBXProject section */\n\t\t08FB7C7917B03F0100B1A761 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tbuildConfigurationList = 08FB7C7D17B03F0100B1A761 /* Build configuration list for PBXProject \\\"TestProject\\\" */;\n\t\t\tcompatibilityVersion = \\\"Xcode 3.2\\\";\n\t\t\tmainGroup = 08FB7C8017B03F0100B1A761;\n\t\t\tproductRefGroup = 08FB7C8117B03F0100B1A761 /* Products */;\n\t\t\tprojectDirPath = \\\"\\\";\n\t\t\tprojectRoot = \\\"\\\";\n\t\t\ttargets = (\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin XCBuildConfiguration section */\n\t\t08FB7C7E17B03F0100B1A761 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;\n\t\t\t\tCODE_SIGN_ENTITLEMENTS = \\\"TestProject/TestProject.entitlements\\\";\n\t\t\t\tCODE_SIGN_IDENTITY = \\\"Apple Development\\\";\n\t\t\t\t\\\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\\\" = \\\"iPhone Developer\\\";\n\t\t\t\tENABLE_BITCODE = NO;\n\t\t\t\tGCC_PRECOMPILE_PREFIX_HEADER = YES;\n\t\t\t\tGCC_PREFIX_HEADER = \\\"TestProject/TestProject-Prefix.pch\\\";\n\t\t\t\tINFOPLIST_FILE = \\\"TestProject/Info.plist\\\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \\\"$(inherited) @executable_path/Frameworks\\\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.example.testproject;\n\t\t\t\tPRODUCT_NAME = \\\"$(TARGET_NAME)\\\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \\\"-Onone\\\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \\\"1,2\\\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t08FB7C7F17B03F0100B1A761 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;\n\t\t\t\tCODE_SIGN_ENTITLEMENTS = \\\"TestProject/TestProject.entitlements\\\";\n\t\t\t\tCODE_SIGN_IDENTITY = \\\"Apple Development\\\";\n\t\t\t\t\\\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\\\" = \\\"iPhone Developer\\\";\n\t\t\t\tENABLE_BITCODE = NO;\n\t\t\t\tGCC_PRECOMPILE_PREFIX_HEADER = YES;\n\t\t\t\tGCC_PREFIX_HEADER = \\\"TestProject/TestProject-Prefix.pch\\\";\n\t\t\t\tINFOPLIST_FILE = \\\"TestProject/Info.plist\\\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = \\\"$(inherited) @executable_path/Frameworks\\\";\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.example.testproject;\n\t\t\t\tPRODUCT_NAME = \\\"$(TARGET_NAME)\\\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \\\"-Owholemodule\\\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \\\"1,2\\\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t08FB7C7D17B03F0100B1A761 /* Build configuration list for PBXProject \\\"TestProject\\\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t08FB7C7E17B03F0100B1A761 /* Debug */,\n\t\t\t\t08FB7C7F17B03F0100B1A761 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = 08FB7C7917B03F0100B1A761 /* Project object */;\n}\\n`;\nfs.writeFileSync(dummyPbxprojPath, minimalPbxprojContent);\n\ntry {\n  const xcode = Xcode.open(dummyPbxprojPath);\n  console.log('Successfully opened pbxproj file.');\n\n  // Access the project object and its build configurations\n  const project = xcode.project;\n  const rootObject = project.objects[project.rootObject];\n\n  if (rootObject && rootObject.isa === 'PBXProject') {\n    console.log(`Root Project Object Name (via productRefGroup): ${project.objects[rootObject.productRefGroup]?.name || 'Unknown'}`);\n\n    const configListId = rootObject.buildConfigurationList;\n    const configList = project.objects[configListId];\n\n    if (configList && configList.isa === 'XCConfigurationList') {\n      // Find the Debug build configuration\n      const debugConfigId = configList.buildConfigurations.find(configRef => project.objects[configRef]?.name === 'Debug');\n\n      if (debugConfigId) {\n        const debugConfig = project.objects[debugConfigId];\n        console.log(`Debug SWIFT_VERSION: ${debugConfig.buildSettings.SWIFT_VERSION}`);\n\n        // Example of modification (uncomment to run and save):\n        // debugConfig.buildSettings.SWIFT_VERSION = '5.5';\n        // console.log(`Updated Debug SWIFT_VERSION to: ${debugConfig.buildSettings.SWIFT_VERSION}`);\n        // xcode.save(); // Save changes back to the file\n        // console.log('Modified SWIFT_VERSION and saved to ' + dummyPbxprojPath);\n      } else {\n        console.log('Debug configuration not found.');\n      }\n    }\n  } else {\n    console.log('Root project object not found or incorrect type.');\n  }\n\n} catch (error) {\n  console.error('Error processing pbxproj file:', error.message);\n} finally {\n  // Clean up the dummy project file and directory\n  if (fs.existsSync(dummyPbxprojPath)) {\n    fs.unlinkSync(dummyPbxprojPath);\n  }\n  if (fs.existsSync(dummyProjectPath)) {\n    fs.rmdirSync(dummyProjectPath);\n  }\n  console.log('Cleaned up dummy project files.');\n}\n","lang":"typescript","description":"Demonstrates how to programmatically open an Xcode `project.pbxproj` file, access its main project object, retrieve build configurations, and read specific build settings like `SWIFT_VERSION`. This runnable example dynamically creates a minimal valid `pbxproj` file for testing purposes.","tag":null,"tag_description":null,"last_tested":null,"results":[]},"compatibility":null}