Repository navigation
Releases
Releases · rorkai/rork-xcode
0.13.0
Added
- Support for Xcode 27's JSON project format.
parseXcprojreads any JSON5project.xcprojinto plain JSON values, accepting comments, unquoted keys, and single-quoted strings the way Xcode reads hand-edited files.buildXcprojwrites them back in the exact layout Xcode uses, deriving the key order of each record kind, the sorting of settings and sets, and the choice between single-line and multi-line containers from the project schema. A file Xcode wrote rebuilds byte for byte, and any other input reaches the same bytes in one build. Malformed input fails with the newXcprojParseErrorcarrying line and column, and values Xcode could not read back, such as U+0000 and unpaired surrogates, fail with the newXcprojBuildErrorand the path of the offending value. Xcprojis the object model over the format, with the document-first design ofXcodeProject.getBuildSettingandresolveBuildSettingread per configuration through the target's settings, the target's xcconfig, the project's settings, and the project's xcconfig, and list settings read as arrays.setBuildSettingandremoveBuildSettingwork for every configuration or for one, folding values into plain and[config=Name]keys the way Xcode saves them.files(),references(), andfindReferencewalk the file tree by name path, andfindTargetandfindMainAppTargetfind targets.renameTargetandremoveTargetonXcprojfollow every place the format names a target, which covers dependencies, test hosts, build-phase references in file memberships, folder memberships and exception sets, the product and the target's path to it, and theTEST_TARGET_NAME,TEST_HOST, andBUNDLE_LOADERsettings. Name paths switch between their string and array encodings as names gain or lose a/, and a rename the format cannot represent is refused without changing anything. Both reproduce Xcode's own saves of the same edits byte for byte.- The views
XcprojTargetandXcprojReference, the value typesXcprojValue,XcprojObject,XcprojArray, andXcprojBuildSettingValue, and the optionsXcprojBuildSettingOptionsandXcprojResolveBuildSettingOptionsship as public API.
Changed
- The corpus sweep (
pnpm corpus) auditsproject.xcprojfiles next to the other formats, and caps each format at the limit on its own, so a root rich in one format no longer hides the others.
Full Changelog: 0.12.0...0.13.0
0.12.0
Added
Xcworkspace— a model overcontents.xcworkspacedata, the file listing the projects a workspace shows.projectFilePaths()resolves every referenced.xcodeprojrelative to the workspace's directory, with group locations composing through their enclosing groups, container locations anchoring at the workspace's directory, and absolute paths passing through, so tooling resolves the real project set instead of globbing directory trees.fileRefs()returns typed views with location access,addFileRefandremoveFileRefedit the tree,parseWorkspaceLocationsplits a location into kind and path, andXcworkspace.createproduces the document Xcode writes.parseXcworkspaceandbuildXcworkspace— the same contract as schemes. An Xcode-written file rebuilds byte-identically, any other input reaches the canonical layout in one build, and malformed input fails with the newXcworkspaceParseErrorandXcworkspaceBuildErrorcarrying line, column, and node path.- The shared XML node types ship as
XmlDocument,XmlElement,XmlComment, andXmlNode, withisXmlElementandxmlElements. TheXcscheme*type names remain as aliases, so existing annotations keep compiling. TextPosition— the XML-neutral position type every parse error now carries, withPbxprojErrorPositionkept as a documented alias.- Cross-library benchmarks for the XML dialect files in
pnpm bench:compareand the README, measured against the one other npm package that parses and writes them.
Changed
- Scheme and workspace files share one XML core, now strict about what XML cannot carry, symmetrically on parse and build. Only a real
<?xmldeclaration is consumed, numeric character references validate their full digit run and the decoded code point against XML's character set, comment text rejects--and a trailing-, and attribute values reject raw control characters, unpaired surrogates, and the U+FFFE and U+FFFF noncharacters. Every input the parser accepts is one the serializer reproduces, and the corpus sweep over hundreds of real files confirms the strictness rejects nothing Xcode writes. - The serializer validates and escapes attribute values in a single scan, returns the near-universal value with nothing to escape untouched, memoizes name validity and indentation, and resolves error paths only when a build actually fails. Scheme and workspace operations now measure fastest across the board, with parsing 3.9 to 4.3 times faster and building 1.1 to 1.4 times faster than the alternative.
- Parse-error positions count all three line-ending conventions, so CR-only and CRLF sources report correct lines and columns.
Full Changelog: 0.11.0...0.12.0
0.11.0
Added
expandBuildSettingReferences(value, lookup)— evaluates Xcode's$(NAME)and${NAME}build-setting reference syntax in a value through a caller-supplied lookup. Substituted text expands recursively, reference names may themselves contain references ($(SETTING_$(VARIANT)), resolved innermost first), and cycles stay finite. A lookup answer ofundefinedleaves the reference verbatim, so partial resolution loses no information, while an empty string expands to nothing the way Xcode treats empty settings. The:operators are honored forlower,upper,rfc1034identifier,c99extidentifier, anddefault=, and a reference carrying any other operator stays verbatim rather than expanding to a wrongly transformed value. The supported operator names ship as theBuildSettingOperatorunion.Target.resolveBuildSetting(key, options?)— reads a setting through the same layers asgetBuildSetting(target settings, target xcconfig, project settings, project xcconfig) and expands the references in it. Referenced settings resolve through the full chain,$(inherited)and a setting referencing itself continue from the next layer down the way Xcode composes values, and$(TARGET_NAME)falls back to the target's name, so the template'sPRODUCT_NAME = "$(TARGET_NAME)"and imported projects'com.example.$(PRODUCT_NAME:rfc1034identifier)bundle identifiers resolve with zero setup. An optionallookupanswers references the document cannot, such as$(BUILT_PRODUCTS_DIR).
Full Changelog: 0.10.0...0.11.0
0.10.0
Added
XcodeProject.renameTarget(target, newName)— renames a target and every place the pbxproj knows it by name: the target'snameandproductName, the literalPRODUCT_NAMEsetting, the product file reference (Old.appbecomesNew.app, whatever the extension),remoteInfoon container item proxies pointing at the target by id,TEST_TARGET_NAMEvalues naming it, and the path segments ofTEST_HOSTandBUNDLE_LOADERthat name the target or its product. Names match whole per path segment, so renamingDemoAppnever touchesDemoAppTests, and aPRODUCT_NAMEof$(TARGET_NAME)follows by itself. Renaming to the same name is a true no-op, and a target of another project throwsXcodeModelError. File-system renames (source folders, entitlements files) stay with the caller.Xcscheme.renameTarget(oldName, newName)— the scheme-file counterpart. Blueprint names match whole and buildable names match by stem, soOld.apprenames whileOldTests.xctest, a different target's product, stays untouched. Returns whether anything changed, so callers can skip rewriting untouched files.Xcscheme.renameContainer(oldProjectName, newProjectName)— follows a rename of the.xcodeprojdirectory itself, rewritingcontainer:Old.xcodeprojreferences across every buildable reference. Returns whether anything changed.- The corpus sweep gained a rename probe — every parsed project with an app target renames to a probe name and back, with byte-stable fixed-point checks after each step.
Changed
- Every comment, JSDoc, and doc in the repository rewritten as plain flowing prose. No code changes, and parse and build benchmarks are unchanged.
Full Changelog: 0.9.0...0.10.0
0.9.0
Added
.xcconfigsupport end to end.parseXcconfigandbuildXcconfigtreat the hand-authored format losslessly — an untouched file rebuilds byte for byte, comments, blank lines, alignment, and line endings included — and malformed lines fail with the newXcconfigParseErrorcarrying line and column instead of being dropped.Xcconfigmodel —parse/create/build,get/set/removeediting single lines in place,keys,assignments,includes, andsettings()flattening that applies#includedirectives at their position through a caller-supplied resolver. A file included again later re-applies like pasted text, while true cycles terminate through recursion-stack guards that work with both cached and fresh-instance resolvers.- Build-context flattening —
settings({ context: { sdk, arch, config } })applies conditional assignments when every condition matches, with trailing*wildcards.$(inherited)and${inherited}splice in the value accumulated earlier in the chain and stay literal when there is none, so lower layers can still resolve them. - Build-setting layering —
BuildConfiguration.baseConfigurationReference(),XcodeProject.registerXcconfig(reference, config), andTarget.getBuildSettingresolving in Xcode's order: target settings, target xcconfig, project settings, project xcconfig. - Four neutralized
.xcconfigfixtures captured from real file shapes run in CI, and the corpus sweep now covers every.xcconfigon the machine with a byte-exact losslessness bar.
Full Changelog: 0.8.0...0.9.0
0.8.0
Added
parseApplePlatform(value)— normalizes a platform name to theApplePlatformunion. Casing and punctuation are ignored, so spellings liketvOS,TV_OS, andvisionosall resolve, and the SDK identifiers Xcode writes intoSDKROOT(iphoneos,appletvos,xros,macosx, and their simulator variants) resolve to the platform they build for. Unknown input returnsundefined, leaving the default to the caller.
Full Changelog: 0.7.0...0.8.0
0.7.0
Added
NativeTarget.embeddedTargets()— the read-side counterpart ofembed(). Resolves which targets' products this target's copy-files phases carry and returns them as target views in phase and file order, deduplicated and excluding self. Targets embedding further targets of their own can be walked recursively through the accessor.CopyFilesBuildPhase.dstSubfolderSpec— a typed getter for the destination folder code alongsidedstPath, comparable against the exportedCopyFilesDestinationconstants.
Full Changelog: 0.6.0...0.7.0
0.6.0
Added
- Isa literals type the returns —
project.add(Isa.fileReference, ...)is aFileReference,target.ensureBuildPhase(Isa.copyFilesBuildPhase, ...)is aCopyFilesBuildPhase, andtarget.findBuildPhase(Isa.shellScriptBuildPhase)is aShellScriptBuildPhase | undefined, with no cast at the call site. A dynamic string falls back to the generic view types as before. The mapping is derived from the sameVIEWSregistry the view factory dispatches on, so the promised type and the created class cannot drift apart. - Exported
IsaValue,BuildPhaseIsa,ViewByIsa,ViewOf, andBuildPhaseOftypes for building typed helpers on top of the model.
Changed
ensureBuildPhasenarrows its parameter fromstringtoBuildPhaseIsa, the union of the eight build phase isas, so creating a phase with a non-phase isa is now a compile error. Code passing a plainstringvariable needs a literal or a narrowing check.
Full Changelog: 0.5.0...0.6.0
0.5.0
Added
- A view class for every isa Xcode writes.
ExceptionSetsplits intoBuildFileExceptionSetandBuildPhaseMembershipExceptionSet(with a typedbuildPhase()accessor),SwiftPackageReferencesplits intoRemoteSwiftPackageReference(repositoryURL) andLocalSwiftPackageReference(relativePath), and every build phase kind gets its own class:SourcesBuildPhase,FrameworksBuildPhase,ResourcesBuildPhase,HeadersBuildPhase,CopyFilesBuildPhase(dstPath), andShellScriptBuildPhase(shellScript,shellPath). Code that had to compareobject.isaafter anis()check now narrows with the specific class alone. - Legacy kinds —
PBXRezBuildPhase,PBXAppleScriptBuildPhase, andPBXBuildStyleget classes, andbuildStylesjoins the doctor's reference vocabulary, so decades-old documents validate and traverse typed. - Tighter return types across the model:
ensureSourcesPhase,ensureFrameworksPhase,ensureResourcesPhase,ensureShellScriptPhase, andembedreturn their specific phase classes, and the Swift package helpers returnRemoteSwiftPackageReferenceorLocalSwiftPackageReference.
Changed
- Each view class now declares the single isa it models through
static readonly isa(previously a pluralisasarray), and the view factory registry derives from the class declarations. Behavior-only bases such asTargetdeclarenulland never route.
Full Changelog: 0.4.0...0.5.0
0.4.0
Added
- Scheme object model with
XcschemeandBuildableReference—Xcschemewraps a parsed scheme document the wayXcodeProjectwraps a pbxproj, withparse,create,build,root, andelements(name), andbuildableReferences()returns typed views whoseblueprintIdentifier,blueprintName,buildableName, andreferencedContainerproperties read and write the underlying element's attributes directly. The tree stays the single source of truth, so typed edits and direct tree edits compose freely and byte-fidelity guarantees are unchanged. is()narrowing on every view class — a static type guard for discriminating mixed objects, so walking a document reads asif (NativeTarget.is(object))and narrows the wayinstanceofdoes, subclasses included.- Typed views for three more kinds —
BuildConfigurationexposes itsnameand a livebuildSettingsdictionary typed asBuildSettings(writes land in the document),FileReferenceexposespathandname, andContainerItemProxyexposesremoteInfo. All three come out of the factory and the property queries automatically.BuildSettingsalso gains theTEST_HOSTandTEST_TARGET_NAMEkeys rename flows touch. - A documentation pass over the scheme module: the parser class, its fields, and every previously undocumented method now carry doc comments.
Full Changelog: 0.3.0...0.4.0