From 185a9ab9fe2df41d4130700e79fbe40a2e44ecc7 Mon Sep 17 00:00:00 2001 From: fatme Date: Fri, 4 Oct 2019 08:48:31 +0300 Subject: [PATCH 01/31] fix: fix apple watch extension with space in name Rel to: https://github.com/NativeScript/nativescript-cli/issues/5005 --- lib/constants.js | 8 +++++++- lib/pbxProject.js | 4 ++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/constants.js b/lib/constants.js index fefd9de..1275c3d 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -112,6 +112,11 @@ function unquoted(text) { return text == null ? '' : text.replace (/(^")|("$)/g, '') } +function quote(name) { + const quotedName = (name.indexOf(" ") >= 0 || name.indexOf("@") >= 0) && name[0] !== `"` ? `"${name}"` : name; + return quotedName; +} + function isModuleMapFileType(fileType) { return fileType === FILETYPE_BY_EXTENSION.modulemap; } @@ -137,5 +142,6 @@ module.exports = { isEntitlementFileType, isPlistFileType, isModuleMapFileType, - unquoted + unquoted, + quote } \ No newline at end of file diff --git a/lib/pbxProject.js b/lib/pbxProject.js index d510221..d10cfcb 100644 --- a/lib/pbxProject.js +++ b/lib/pbxProject.js @@ -550,7 +550,7 @@ pbxProject.prototype.addPbxGroup = function (filePathsArray, name, path, sourceT var groups = this.hash.project.objects['PBXGroup'], pbxGroupUuid = opt.uuid || this.generateUuid(), commentKey = f("%s_comment", pbxGroupUuid), - groupName = (name.indexOf(" ") >= 0 || name.indexOf("@") >= 0) && name[0] !== `"` ? `"${name}"` : name, + groupName = constants.quote(name), pbxGroup = { isa: 'PBXGroup', children: [], @@ -611,7 +611,7 @@ pbxProject.prototype.addPbxGroup = function (filePathsArray, name, path, sourceT } if(isEntitlementFileType(file.lastKnownFileType)) { - this.addToBuildSettings('CODE_SIGN_ENTITLEMENTS', file.path, opt.target); + this.addToBuildSettings('CODE_SIGN_ENTITLEMENTS', constants.quote(file.path), opt.target); continue; } From c785a4fa3479e971b0f246b73096930d1a0b9dc2 Mon Sep 17 00:00:00 2001 From: fatme Date: Fri, 4 Oct 2019 19:12:12 +0300 Subject: [PATCH 02/31] fix: fix PR comments --- lib/constants.js | 4 ++-- lib/pbxProject.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/constants.js b/lib/constants.js index 1275c3d..68d0b15 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -112,7 +112,7 @@ function unquoted(text) { return text == null ? '' : text.replace (/(^")|("$)/g, '') } -function quote(name) { +function quoteIfNeeded(name) { const quotedName = (name.indexOf(" ") >= 0 || name.indexOf("@") >= 0) && name[0] !== `"` ? `"${name}"` : name; return quotedName; } @@ -143,5 +143,5 @@ module.exports = { isPlistFileType, isModuleMapFileType, unquoted, - quote + quoteIfNeeded } \ No newline at end of file diff --git a/lib/pbxProject.js b/lib/pbxProject.js index d10cfcb..5d770bf 100644 --- a/lib/pbxProject.js +++ b/lib/pbxProject.js @@ -550,7 +550,7 @@ pbxProject.prototype.addPbxGroup = function (filePathsArray, name, path, sourceT var groups = this.hash.project.objects['PBXGroup'], pbxGroupUuid = opt.uuid || this.generateUuid(), commentKey = f("%s_comment", pbxGroupUuid), - groupName = constants.quote(name), + groupName = constants.quoteIfNeeded(name), pbxGroup = { isa: 'PBXGroup', children: [], @@ -611,7 +611,7 @@ pbxProject.prototype.addPbxGroup = function (filePathsArray, name, path, sourceT } if(isEntitlementFileType(file.lastKnownFileType)) { - this.addToBuildSettings('CODE_SIGN_ENTITLEMENTS', constants.quote(file.path), opt.target); + this.addToBuildSettings('CODE_SIGN_ENTITLEMENTS', constants.quoteIfNeeded(file.path), opt.target); continue; } From f88457fd02c9e3c368026bc7344b2765721065ff Mon Sep 17 00:00:00 2001 From: fatme Date: Fri, 4 Oct 2019 19:12:25 +0300 Subject: [PATCH 03/31] chore: bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5591b6a..3f78fc5 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "name": "nativescript-dev-xcode", "description": "parser for xcodeproj/project.pbxproj files", "main": "index.js", - "version": "0.2.0", + "version": "0.2.1", "repository": { "url": "https://github.com/NativeScript/nativescript-dev-xcode.git" }, From 04563e2bbc5532698e3c630f053cb0b32bba2869 Mon Sep 17 00:00:00 2001 From: Teodor Dermendjiev Date: Thu, 18 Feb 2021 00:01:27 +0200 Subject: [PATCH 04/31] feat: Add removeBuildPhase method to pbxProject (#14) --- .vscode/launch.json | 18 +++++++++++++++++ lib/pbxProject.js | 33 ++++++++++++++++++++++++++++-- test/removeBuildPhase.js | 43 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 test/removeBuildPhase.js diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..6e228a3 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,18 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "pwa-node", + "request": "launch", + "name": "Launch Program", + "skipFiles": [ + "/**" + ], + "runtimeExecutable": "nodeunit", + "runtimeArgs": ["test/parser", "test"] + } + ] +} \ No newline at end of file diff --git a/lib/pbxProject.js b/lib/pbxProject.js index 5d770bf..ed2e8c8 100644 --- a/lib/pbxProject.js +++ b/lib/pbxProject.js @@ -702,7 +702,7 @@ pbxProject.prototype.removePbxGroupByKey = function(groupKey, path) { if (!group) { return; } - + path = path || ""; var children = group.children; @@ -1064,7 +1064,7 @@ pbxProject.prototype.addTargetDependency = function(target, dependencyTargets) { containerPortal: this.hash.project['rootObject'], containerPortal_comment: this.hash.project['rootObject_comment'], proxyType: 1, - remoteGlobalIDString: dependencyTargetUuid, + remoteGlobalIDString: dependencyTargetUuid, remoteInfo: nativeTargets[dependencyTargetUuid].name }, targetDependency = { @@ -1087,6 +1087,35 @@ pbxProject.prototype.addTargetDependency = function(target, dependencyTargets) { return { uuid: target, target: nativeTargets[target] }; } +pbxProject.prototype.removeBuildPhase = function(comment, target) { // Build phase files should be removed separately + var buildPhaseUuid = undefined, + buildPhaseTargetUuid = target || this.getFirstTarget().uuid + + if (this.hash.project.objects['PBXNativeTarget'][buildPhaseTargetUuid]['buildPhases']) { + let phases = this.hash.project.objects['PBXNativeTarget'][buildPhaseTargetUuid]['buildPhases']; + for (let i = 0; i < phases.length; i++) { + const phase = phases[i]; + if (phase.comment === comment) { + buildPhaseUuid = phase.value; + let commentKey = f("%s_comment", buildPhaseUuid) + if (this.hash.project.objects['PBXCopyFilesBuildPhase']) { + let phase = this.hash.project.objects['PBXCopyFilesBuildPhase'][commentKey] + delete phase + } + + if (this.hash.project.objects['PBXShellScriptBuildPhase']) { + let phase = this.hash.project.objects['PBXShellScriptBuildPhase'][commentKey] + delete phase + } + + phases.splice(i, 1); + } + } + + } + +} + pbxProject.prototype.addBuildPhase = function(filePathsArray, buildPhaseType, comment, target, optionsOrFolderType, subfolderPath) { var buildPhaseSection, fileReferenceSection = this.pbxFileReferenceSection(), diff --git a/test/removeBuildPhase.js b/test/removeBuildPhase.js new file mode 100644 index 0000000..bd35c24 --- /dev/null +++ b/test/removeBuildPhase.js @@ -0,0 +1,43 @@ +/** + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + 'License'); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + */ + +var fullProject = require('./fixtures/full-project') + fullProjectStr = JSON.stringify(fullProject), + pbx = require('../lib/pbxProject'), + proj = new pbx('.'); + +function cleanHash() { + return JSON.parse(fullProjectStr); +} + +exports.setUp = function (callback) { + proj.hash = cleanHash(); + callback(); +} + +exports.removeBuildPhase = { + + 'should remove a pbxBuildPhase': function (test) { + const comment = 'My build phase'; + var buildPhase = proj.addBuildPhase([], 'PBXSourcesBuildPhase', comment); + proj.removeBuildPhase(comment) + let phases = proj.hash.project.objects['PBXNativeTarget'][proj.getFirstTarget().uuid]['buildPhases']; + + test.ok(phases.map(p => p.comment).indexOf(comment) === -1); + test.done() + }, +} From a7f032722d0edab445598bc8602ef49d4640151e Mon Sep 17 00:00:00 2001 From: Nathan Walker Date: Wed, 17 Feb 2021 14:06:30 -0800 Subject: [PATCH 05/31] chore: bump --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 3f78fc5..b4b9a34 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,9 @@ { - "author": "Telerik ", + "author": "NativeScript TSC ", "name": "nativescript-dev-xcode", "description": "parser for xcodeproj/project.pbxproj files", "main": "index.js", - "version": "0.2.1", + "version": "0.3.0", "repository": { "url": "https://github.com/NativeScript/nativescript-dev-xcode.git" }, From 9f4ca0856ac0a766726e9bc754f5809fdafb9331 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Fri, 29 Apr 2022 16:55:49 +0200 Subject: [PATCH 06/31] fix: don't remove groups by name as multiple can coexist (#15) --- lib/pbxProject.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lib/pbxProject.js b/lib/pbxProject.js index ed2e8c8..36fe84b 100644 --- a/lib/pbxProject.js +++ b/lib/pbxProject.js @@ -542,11 +542,6 @@ pbxProject.prototype.findMainPbxGroup = function () { pbxProject.prototype.addPbxGroup = function (filePathsArray, name, path, sourceTree, opt) { opt = opt || {}; var srcRootPath = $path.dirname($path.dirname(this.filepath)); - var oldGroup = this.pbxGroupByName(name); - if (oldGroup) { - this.removePbxGroup(name, path); - } - var groups = this.hash.project.objects['PBXGroup'], pbxGroupUuid = opt.uuid || this.generateUuid(), commentKey = f("%s_comment", pbxGroupUuid), From 2aad41772754ca735fe47792080581476b0f07ba Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Tue, 21 Mar 2023 20:42:54 +0100 Subject: [PATCH 07/31] chore: update deps --- .gitignore | 2 ++ .npmignore | 7 ------- lib/pbxProject.js | 2 +- package.json | 16 ++++++++++------ 4 files changed, 13 insertions(+), 14 deletions(-) delete mode 100644 .npmignore diff --git a/.gitignore b/.gitignore index 796bd5b..0a5bb72 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ node_modules/* .DS_Store npm-debug.log package-lock.json + +*.tgz \ No newline at end of file diff --git a/.npmignore b/.npmignore deleted file mode 100644 index 442a34a..0000000 --- a/.npmignore +++ /dev/null @@ -1,7 +0,0 @@ -lib/parser/pbxproj.pegjs -test/ -.travis.yml -AUTHORS -Makefile -RELEASENOTES.md -*.tgz \ No newline at end of file diff --git a/lib/pbxProject.js b/lib/pbxProject.js index 36fe84b..58ff837 100644 --- a/lib/pbxProject.js +++ b/lib/pbxProject.js @@ -98,7 +98,7 @@ pbxProject.prototype.allUuids = function() { pbxProject.prototype.generateUuid = function() { var id = $uuid.v4() .replace(/-/g, '') - .substr(0, 24) + .substring(0, 24) .toUpperCase() if (this.allUuids().indexOf(id) >= 0) { diff --git a/package.json b/package.json index b4b9a34..8cf63a3 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,10 @@ "description": "parser for xcodeproj/project.pbxproj files", "main": "index.js", "version": "0.3.0", + "files": [ + "lib", + "!lib/parser/pbxproj.pegjs" + ], "repository": { "url": "https://github.com/NativeScript/nativescript-dev-xcode.git" }, @@ -11,16 +15,16 @@ "node": ">=6.0.0" }, "dependencies": { - "simple-plist": "^1.0.0", - "uuid": "^3.3.2" + "simple-plist": "1.3.1", + "uuid": "9.0.0" }, "devDependencies": { - "nodeunit": "^0.11.3", - "pegjs": "^0.10.0" + "nodeunit": "0.11.3", + "pegjs": "0.10.0" }, "scripts": { - "pegjs": "node_modules/.bin/pegjs lib/parser/pbxproj.pegjs", - "test": "node_modules/.bin/nodeunit test/parser test" + "pegjs": "pegjs lib/parser/pbxproj.pegjs", + "test": "nodeunit test/parser test" }, "license": "Apache-2.0" } From e37a17a13b6d5c9da258bd7c5573c44cc5d9dad3 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Tue, 21 Mar 2023 20:49:26 +0100 Subject: [PATCH 08/31] chore(release): 0.5.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8cf63a3..393bffd 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "name": "nativescript-dev-xcode", "description": "parser for xcodeproj/project.pbxproj files", "main": "index.js", - "version": "0.3.0", + "version": "0.5.0", "files": [ "lib", "!lib/parser/pbxproj.pegjs" From 293025e00a3e24782602c732da5a90674ff7486b Mon Sep 17 00:00:00 2001 From: farfromrefuge Date: Fri, 19 Jan 2024 16:34:50 +0100 Subject: [PATCH 09/31] fix: allow symlink folders in addPbxGroup (#16) --- lib/pbxProject.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pbxProject.js b/lib/pbxProject.js index 58ff837..7852427 100644 --- a/lib/pbxProject.js +++ b/lib/pbxProject.js @@ -588,7 +588,7 @@ pbxProject.prototype.addPbxGroup = function (filePathsArray, name, path, sourceT if(opt.target) { file.target = opt.target; } - if (fs.existsSync(filePath) && fs.lstatSync(filePath).isDirectory() && !isAssetFileType(file.lastKnownFileType)) { + if (fs.existsSync(filePath) && (fs.lstatSync(filePath).isDirectory() || fs.lstatSync(filePath).isSymbolicLink()) && !isAssetFileType(file.lastKnownFileType)) { if($path.extname(filePath) === ".lproj") { continue; } From 0059652db3a1f4f3d5c1159942e64e993e746c1c Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Fri, 19 Jan 2024 16:46:57 +0100 Subject: [PATCH 10/31] chore: cleanup --- .ratignore | 2 -- .travis.yml | 19 ------------------- .vscode/launch.json | 32 +++++++++++++++----------------- README.md | 29 +++++++++++++---------------- package.json | 2 +- 5 files changed, 29 insertions(+), 55 deletions(-) delete mode 100644 .ratignore delete mode 100644 .travis.yml diff --git a/.ratignore b/.ratignore deleted file mode 100644 index eecfa9a..0000000 --- a/.ratignore +++ /dev/null @@ -1,2 +0,0 @@ -fixtures -*.pbxproj diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 14a176e..0000000 --- a/.travis.yml +++ /dev/null @@ -1,19 +0,0 @@ -language: node_js -sudo: false - -git: - depth: 10 - -node_js: - - 6 - - 8 - - 10 - -install: - - nvm --version - - node --version - - npm --version - - npm install - -script: - - npm test diff --git a/.vscode/launch.json b/.vscode/launch.json index 6e228a3..f280792 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,18 +1,16 @@ { - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "type": "pwa-node", - "request": "launch", - "name": "Launch Program", - "skipFiles": [ - "/**" - ], - "runtimeExecutable": "nodeunit", - "runtimeArgs": ["test/parser", "test"] - } - ] -} \ No newline at end of file + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Launch Program", + "skipFiles": ["/**"], + "runtimeExecutable": "nodeunit", + "runtimeArgs": ["test/parser", "test"] + } + ] +} diff --git a/README.md b/README.md index 53f9376..6f9060e 100644 --- a/README.md +++ b/README.md @@ -21,11 +21,6 @@ # nativescript-dev-xcode - -[![Build Status](https://travis-ci.org/NativeScript/nativescript-dev-xcode.svg?branch=master)](https://travis-ci.org/apache/cordova-node-xcode) - Parser utility for xcodeproj project files Allows you to edit xcodeproject files and write them back out. @@ -36,19 +31,19 @@ Forked from: [apache/cordova-node-xcode](https://github.com/apache/cordova-node- ```js // API is a bit wonky right now -var xcode = require('xcode'), - fs = require('fs'), - projectPath = 'myproject.xcodeproj/project.pbxproj', - myProj = xcode.project(projectPath); +var xcode = require("xcode"), + fs = require("fs"), + projectPath = "myproject.xcodeproj/project.pbxproj", + myProj = xcode.project(projectPath); // parsing is async, in a different process myProj.parse(function (err) { - myProj.addHeaderFile('foo.h'); - myProj.addSourceFile('foo.m'); - myProj.addFramework('FooKit.framework'); - - fs.writeFileSync(projectPath, myProj.writeSync()); - console.log('new project written'); + myProj.addHeaderFile("foo.h"); + myProj.addSourceFile("foo.m"); + myProj.addFramework("FooKit.framework"); + + fs.writeFileSync(projectPath, myProj.writeSync()); + console.log("new project written"); }); ``` @@ -63,7 +58,9 @@ grammar. Other tests will use the prebuilt parser (`lib/parser/pbxproj.js`). To rebuild the parser js file after editing the grammar, run: - npm run pegjs +``` +npm run pegjs +``` (and be sure to restore the Apache license notice in `lib/parser/pbxproj.js` before committing) diff --git a/package.json b/package.json index 393bffd..25bd532 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ }, "dependencies": { "simple-plist": "1.3.1", - "uuid": "9.0.0" + "uuid": "9.0.1" }, "devDependencies": { "nodeunit": "0.11.3", From 77267e742deb01668fe6bfa35feeb9255ae27e45 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Fri, 19 Jan 2024 16:47:36 +0100 Subject: [PATCH 11/31] release: 0.6.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 25bd532..e781114 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "name": "nativescript-dev-xcode", "description": "parser for xcodeproj/project.pbxproj files", "main": "index.js", - "version": "0.5.0", + "version": "0.6.0", "files": [ "lib", "!lib/parser/pbxproj.pegjs" From 99947af5ca72755ac59dcf9d458a8a4ee2c8594f Mon Sep 17 00:00:00 2001 From: Jason Cassidy <47318351+jcassidyav@users.noreply.github.com> Date: Tue, 20 Feb 2024 15:11:57 +0000 Subject: [PATCH 12/31] fix: ensure that PbxGroups are not duplicated (#17) --- .gitignore | 2 +- lib/guidMapper.js | 52 ++++++++++++++++++++++++++++++++++ lib/pbxProject.js | 27 +++++++++++++++++- test/guidMapper.js | 69 ++++++++++++++++++++++++++++++++++++++++++++++ test/pbxProject.js | 17 ++++++++++++ 5 files changed, 165 insertions(+), 2 deletions(-) create mode 100644 lib/guidMapper.js create mode 100644 test/guidMapper.js diff --git a/.gitignore b/.gitignore index 0a5bb72..5ef95a1 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,5 @@ node_modules/* .DS_Store npm-debug.log package-lock.json - +.ns-build-pbxgroup-data.json *.tgz \ No newline at end of file diff --git a/lib/guidMapper.js b/lib/guidMapper.js new file mode 100644 index 0000000..98300ff --- /dev/null +++ b/lib/guidMapper.js @@ -0,0 +1,52 @@ +const fs = require('fs'); +const path = require('path'); + +function guidMapper(filePath) { + this.filePath = filePath; + this.data = this.loadFromFile(); +} + +guidMapper.prototype.loadFromFile = function () { + try { + const rawData = fs.readFileSync(this.filePath, 'utf8'); + return JSON.parse(rawData); + } catch (error) { + // If file doesn't exist or there's an error parsing it, initialize with an empty object. + return {}; + } +}; + +guidMapper.prototype.writeFileSync = function () { + const jsonData = JSON.stringify(this.data, null, 2); + fs.writeFileSync(this.filePath, jsonData, 'utf8'); +}; + +guidMapper.prototype.addEntry = function (guid, path, name) { + if(!!guid && !! path && !!name){ + this.data[guid] = { path: path, name: name }; + } +}; + +guidMapper.prototype.removeEntry = function (guid) { + if (this.data[guid]) { + delete this.data[guid]; + } +}; + +guidMapper.prototype.getEntries = function () { + return this.data; +}; + +guidMapper.prototype.findEntryGuid = function (name, path) { + for (const guid in this.data) { + if (this.data.hasOwnProperty(guid)) { + const entry = this.data[guid]; + if (entry.path === path && entry.name === name) { + return guid; + } + } + } + return null; +}; + +module.exports = guidMapper; \ No newline at end of file diff --git a/lib/pbxProject.js b/lib/pbxProject.js index 7852427..6364ee3 100644 --- a/lib/pbxProject.js +++ b/lib/pbxProject.js @@ -35,7 +35,8 @@ var util = require('util'), isEntitlementFileType = constants.isEntitlementFileType, isAssetFileType = constants.isAssetFileType, isPlistFileType = constants.isPlistFileType, - isModuleMapFileType = constants.isModuleMapFileType; + isModuleMapFileType = constants.isModuleMapFileType, + guidMapper = require('./guidMapper'); function pbxProject(filename) { if (!(this instanceof pbxProject)) @@ -74,6 +75,10 @@ pbxProject.prototype.parseSync = function() { } pbxProject.prototype.writeSync = function(options) { + if(this.pbxGroupTracker){ + this.pbxGroupTracker.writeFileSync(); + } + this.writer = new pbxWriter(this.hash, options); return this.writer.writeSync(); } @@ -538,10 +543,27 @@ pbxProject.prototype.findMainPbxGroup = function () { return null; } +pbxProject.prototype.getPbxGroupTracker = function (path) { + + if(!this.pbxGroupTracker){ + this.pbxGroupTracker = new guidMapper($path.join(path, '.ns-build-pbxgroup-data.json')); + } + + return this.pbxGroupTracker; +} pbxProject.prototype.addPbxGroup = function (filePathsArray, name, path, sourceTree, opt) { opt = opt || {}; var srcRootPath = $path.dirname($path.dirname(this.filepath)); + + var existingGroupId = this.getPbxGroupTracker(srcRootPath).findEntryGuid(name, path); + if(existingGroupId){ + if(this.getPBXGroupByKey(existingGroupId)){ + this.removePbxGroupByKey(existingGroupId, path); + } + this.pbxGroupTracker.removeEntry(existingGroupId); + } + var groups = this.hash.project.objects['PBXGroup'], pbxGroupUuid = opt.uuid || this.generateUuid(), commentKey = f("%s_comment", pbxGroupUuid), @@ -560,6 +582,9 @@ pbxProject.prototype.addPbxGroup = function (filePathsArray, name, path, sourceT pbxGroup.path = path; } + // save to group to the tracker + this.pbxGroupTracker.addEntry(pbxGroupUuid, path, name); + for (var key in fileReferenceSection) { // only look for comments if (!COMMENT_KEY.test(key)) continue; diff --git a/test/guidMapper.js b/test/guidMapper.js new file mode 100644 index 0000000..8c9cb72 --- /dev/null +++ b/test/guidMapper.js @@ -0,0 +1,69 @@ +var guidMapper = require('../lib/guidMapper'); +const fs = require('fs'); +const $uuid = require('uuid'); +const TEST_FILE_NAME = 'test/.ns-build-pbxgroup-data.json'; +const goodGUID = $uuid.v4(); +const goodName = "goodName"; +const badName = 'badName'; +const goodPath = "goodPath"; +const badPath = "badPath"; +exports.setUp = function(callback) { + if(fs.existsSync(TEST_FILE_NAME)){ + fs.rmSync(TEST_FILE_NAME); + } + callback(); +} +exports.tearDown = function(callback) { + if(fs.existsSync(TEST_FILE_NAME)){ + fs.rmSync(TEST_FILE_NAME); + } + callback(); +} +function addTestData(){ + var mapper = new guidMapper(TEST_FILE_NAME); + mapper.addEntry(goodGUID, goodPath, goodName); + mapper.writeFileSync(); +} +exports.operations = { + 'should be able to add to map': function(test) { + var mapper = new guidMapper(TEST_FILE_NAME); + mapper.addEntry(goodGUID, goodPath, goodName); + mapper.writeFileSync(); + mapper = new guidMapper(TEST_FILE_NAME); + const result = mapper.findEntryGuid(goodName, goodPath); + + test.ok(result === goodGUID) + test.done(); + }, + 'should not match only on name': function(test) { + addTestData(); + var mapper = new guidMapper(TEST_FILE_NAME); + + const result = mapper.findEntryGuid(goodName, badPath); + + test.ok(result === null) + test.done(); + }, + 'should not match only on path': function(test) { + addTestData(); + var mapper = new guidMapper(TEST_FILE_NAME); + + const result = mapper.findEntryGuid(badName, goodPath); + + test.ok(result === null) + test.done(); + }, + 'can remove': function(test) { + addTestData(); + var mapper = new guidMapper(TEST_FILE_NAME); + mapper.removeEntry(goodGUID); + var result = mapper.findEntryGuid(goodName, goodPath); + + test.ok(result === null); + mapper.writeFileSync(); + result = mapper.findEntryGuid(goodName, goodPath); + test.ok(result === null) + + test.done(); + } +} \ No newline at end of file diff --git a/test/pbxProject.js b/test/pbxProject.js index e846294..860c4f4 100644 --- a/test/pbxProject.js +++ b/test/pbxProject.js @@ -433,3 +433,20 @@ exports['addToPbxFileReferenceSection'] = { } } + +exports['addPbxGroup'] = { + 'should not add the same group twice': function (test) { + var newProj = new pbx('test/parser/projects/group.pbxproj'); + newProj.parse(function (err, hash) { + this.hash.project.objects['PBXVariantGroup']={}; + var group1 = newProj.addPbxGroup(['test/somefile'], "TestGroup", "test/somepath", null, null); + var group2 = newProj.addPbxGroup(['test/somefile'], "TestGroup", "test/somepath", null, null); + test.equal(newProj.getPBXGroupByKey(group1.uuid), null); + test.equal(newProj.getPBXGroupByKey(group2.uuid).name, "TestGroup"); + test.equal(newProj.getPbxGroupTracker().getEntries().hasOwnProperty(group1.uuid), false); + test.equal(newProj.getPbxGroupTracker().getEntries().hasOwnProperty(group2.uuid), true); + + test.done(); + }); + } +} \ No newline at end of file From fef3352ffe3cf0cecbd4b8064d652dab208497aa Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Tue, 20 Feb 2024 16:13:04 +0100 Subject: [PATCH 13/31] release: 0.7.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e781114..5b0cdec 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "name": "nativescript-dev-xcode", "description": "parser for xcodeproj/project.pbxproj files", "main": "index.js", - "version": "0.6.0", + "version": "0.7.0", "files": [ "lib", "!lib/parser/pbxproj.pegjs" From 01236a9a92b9c8bdf404225411603bc18b12ad91 Mon Sep 17 00:00:00 2001 From: farfromrefuge Date: Sat, 6 Jul 2024 03:39:21 +0200 Subject: [PATCH 14/31] fix: symlinks (#18) --- lib/pbxProject.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/pbxProject.js b/lib/pbxProject.js index 6364ee3..bc458de 100644 --- a/lib/pbxProject.js +++ b/lib/pbxProject.js @@ -613,7 +613,14 @@ pbxProject.prototype.addPbxGroup = function (filePathsArray, name, path, sourceT if(opt.target) { file.target = opt.target; } - if (fs.existsSync(filePath) && (fs.lstatSync(filePath).isDirectory() || fs.lstatSync(filePath).isSymbolicLink()) && !isAssetFileType(file.lastKnownFileType)) { + // if the file is a symLink, isDirectory() returns false + // but isFile() too so we need to see if the realPath is a directory + const exists = fs.existsSync(filePath); + const stats = exists && fs.lstatSync(filePath); + const isSymlink = exists && fs.lstatSync(filePath).isSymbolicLink(); + let symRealPath = isSymlink && fs.realpathSync(filePath); + const isRealDir = stats && stats.isDirectory() || (isSymlink && fs.lstatSync(symRealPath).isDirectory()); + if (exists && isRealDir && !isAssetFileType(file.lastKnownFileType)) { if($path.extname(filePath) === ".lproj") { continue; } From 36f7c9f4358e79df18a53309181b65b05fdc4767 Mon Sep 17 00:00:00 2001 From: Nathan Walker Date: Fri, 5 Jul 2024 18:42:42 -0700 Subject: [PATCH 15/31] fix: optional groups when using embedding against host projects --- lib/pbxProject.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pbxProject.js b/lib/pbxProject.js index bc458de..1582859 100644 --- a/lib/pbxProject.js +++ b/lib/pbxProject.js @@ -2143,7 +2143,7 @@ function correctForFrameworksPath(file, project) { function correctForPath(file, project, group) { var r_group_dir = new RegExp('^' + group + '[\\\\/]'); - if (project.pbxGroupByName(group).path) + if (project.pbxGroupByName(group)?.path) file.path = file.path.replace(r_group_dir, ''); return file; @@ -2393,7 +2393,7 @@ pbxProject.prototype.getPBXGroupByKey = function(key) { }; pbxProject.prototype.getPBXVariantGroupByKey = function(key) { - return this.hash.project.objects['PBXVariantGroup'][key]; + return this.hash.project.objects['PBXVariantGroup']?.[key]; }; From bcb1f9be1af585cbeb349b03d7a805dbae6a664f Mon Sep 17 00:00:00 2001 From: Nathan Walker Date: Mon, 8 Jul 2024 14:27:49 -0700 Subject: [PATCH 16/31] fix: add PBXCopyFilesBuildPhase if does not exist --- lib/pbxProject.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/pbxProject.js b/lib/pbxProject.js index 1582859..a6424a5 100644 --- a/lib/pbxProject.js +++ b/lib/pbxProject.js @@ -1324,7 +1324,13 @@ pbxProject.prototype.pbxFrameworksBuildPhaseObj = function(target) { } pbxProject.prototype.pbxEmbedFrameworksBuildPhaseObj = function (target) { - return this.buildPhaseObject('PBXCopyFilesBuildPhase', 'Embed Frameworks', target); + let buildPhase = this.buildPhaseObject('PBXCopyFilesBuildPhase', 'Embed Frameworks', target); + if (!buildPhase) { + // Create CopyFiles phase in parent target + const phase = this.addBuildPhase([], 'PBXCopyFilesBuildPhase', 'Embed Frameworks', target); + buildPhase = phase.buildPhase; + } + return buildPhase; }; // Find Build Phase from group/target From 4b846bbe6907210d9bc0c39c35f409df77d923bd Mon Sep 17 00:00:00 2001 From: Nathan Walker Date: Mon, 8 Jul 2024 14:28:02 -0700 Subject: [PATCH 17/31] release: 0.7.1-alpha.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5b0cdec..774be68 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "name": "nativescript-dev-xcode", "description": "parser for xcodeproj/project.pbxproj files", "main": "index.js", - "version": "0.7.0", + "version": "0.7.1-alpha.1", "files": [ "lib", "!lib/parser/pbxproj.pegjs" From a1fbeca0d787c8179aaef79d00cb1b4a3f2d62a2 Mon Sep 17 00:00:00 2001 From: Nathan Walker Date: Mon, 8 Jul 2024 21:02:56 -0700 Subject: [PATCH 18/31] fix: add PBXFrameworksBuildPhase if does not exist --- lib/pbxProject.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/pbxProject.js b/lib/pbxProject.js index a6424a5..234590d 100644 --- a/lib/pbxProject.js +++ b/lib/pbxProject.js @@ -1320,7 +1320,13 @@ pbxProject.prototype.pbxResourcesBuildPhaseObj = function(target) { } pbxProject.prototype.pbxFrameworksBuildPhaseObj = function(target) { - return this.buildPhaseObject('PBXFrameworksBuildPhase', 'Frameworks', target); + let buildPhase = this.buildPhaseObject('PBXFrameworksBuildPhase', 'Frameworks', target); + if (!buildPhase) { + // Create Frameworks phase in parent target + const phase = this.addBuildPhase([], 'PBXFrameworksBuildPhase', 'Frameworks', target); + buildPhase = phase.buildPhase; + } + return buildPhase; } pbxProject.prototype.pbxEmbedFrameworksBuildPhaseObj = function (target) { From 3dec27ce4497fbfd73e419ffa5cefb70a096f006 Mon Sep 17 00:00:00 2001 From: Nathan Walker Date: Mon, 8 Jul 2024 21:03:20 -0700 Subject: [PATCH 19/31] release: 0.7.1-alpha.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 774be68..024684b 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "name": "nativescript-dev-xcode", "description": "parser for xcodeproj/project.pbxproj files", "main": "index.js", - "version": "0.7.1-alpha.1", + "version": "0.7.1-alpha.2", "files": [ "lib", "!lib/parser/pbxproj.pegjs" From 4b8ef6e8a5e38c73c765d6c9a2e7bcb7632b5751 Mon Sep 17 00:00:00 2001 From: Nathan Walker Date: Mon, 8 Jul 2024 21:24:51 -0700 Subject: [PATCH 20/31] fix: ensure frameworks are added to destination type 'frameworks' on build --- lib/pbxProject.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pbxProject.js b/lib/pbxProject.js index 234590d..fdc3f38 100644 --- a/lib/pbxProject.js +++ b/lib/pbxProject.js @@ -1323,7 +1323,7 @@ pbxProject.prototype.pbxFrameworksBuildPhaseObj = function(target) { let buildPhase = this.buildPhaseObject('PBXFrameworksBuildPhase', 'Frameworks', target); if (!buildPhase) { // Create Frameworks phase in parent target - const phase = this.addBuildPhase([], 'PBXFrameworksBuildPhase', 'Frameworks', target); + const phase = this.addBuildPhase([], 'PBXFrameworksBuildPhase', 'Frameworks', target, 'frameworks'); buildPhase = phase.buildPhase; } return buildPhase; @@ -1333,7 +1333,7 @@ pbxProject.prototype.pbxEmbedFrameworksBuildPhaseObj = function (target) { let buildPhase = this.buildPhaseObject('PBXCopyFilesBuildPhase', 'Embed Frameworks', target); if (!buildPhase) { // Create CopyFiles phase in parent target - const phase = this.addBuildPhase([], 'PBXCopyFilesBuildPhase', 'Embed Frameworks', target); + const phase = this.addBuildPhase([], 'PBXCopyFilesBuildPhase', 'Embed Frameworks', target, 'frameworks'); buildPhase = phase.buildPhase; } return buildPhase; From 19adee4e00942be272f4caa8494aef82a9b13559 Mon Sep 17 00:00:00 2001 From: Nathan Walker Date: Mon, 8 Jul 2024 21:25:37 -0700 Subject: [PATCH 21/31] release: 0.7.1-alpha.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 024684b..2731a34 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "name": "nativescript-dev-xcode", "description": "parser for xcodeproj/project.pbxproj files", "main": "index.js", - "version": "0.7.1-alpha.2", + "version": "0.7.1-alpha.3", "files": [ "lib", "!lib/parser/pbxproj.pegjs" From 8f7639fb2b65cddedd6e88af2b552478a841d076 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Tue, 9 Jul 2024 16:53:35 +0200 Subject: [PATCH 22/31] fix: only set PBXGroup path when defined --- lib/pbxProject.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pbxProject.js b/lib/pbxProject.js index fdc3f38..2f31cf2 100644 --- a/lib/pbxProject.js +++ b/lib/pbxProject.js @@ -578,7 +578,7 @@ pbxProject.prototype.addPbxGroup = function (filePathsArray, name, path, sourceT filePathToReference = {}; //path is mandatory only for the main group - if(!opt.filesRelativeToProject) { + if(!opt.filesRelativeToProject && path) { pbxGroup.path = path; } From 99be00ff24b269d93d2cdd5637827a4ec7ebd118 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Tue, 9 Jul 2024 16:53:51 +0200 Subject: [PATCH 23/31] fix: don't add duplicate HEADER_SEARCH_PATHS --- lib/pbxProject.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/pbxProject.js b/lib/pbxProject.js index 2f31cf2..1379e04 100644 --- a/lib/pbxProject.js +++ b/lib/pbxProject.js @@ -1566,7 +1566,11 @@ pbxProject.prototype.addToHeaderSearchPaths = function(file, productName) { buildSettings['HEADER_SEARCH_PATHS'] = [INHERITED]; } - buildSettings['HEADER_SEARCH_PATHS'].push(searchPathForFile(file, this)); + // Check if the search path is already in the HEADER_SEARCH_PATHS and add it if it's not. + const searchPath = searchPathForFile(file, this); + if (buildSettings['HEADER_SEARCH_PATHS'].indexOf(searchPath) < 0) { + buildSettings['HEADER_SEARCH_PATHS'].push(searchPath); + } } } From 5512dcc033628d22cd41164131a01ef2b1ae2263 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Tue, 9 Jul 2024 16:54:27 +0200 Subject: [PATCH 24/31] fix: make sure Frameworks is a main group (so it's visible in xcode sidebar) --- lib/pbxProject.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pbxProject.js b/lib/pbxProject.js index 1379e04..b45e1be 100644 --- a/lib/pbxProject.js +++ b/lib/pbxProject.js @@ -885,7 +885,7 @@ pbxProject.prototype.removeFromResourcesPbxGroup = function(file) { pbxProject.prototype.addToFrameworksPbxGroup = function(file) { var pluginsGroup = this.pbxGroupByName('Frameworks'); if (!pluginsGroup) { - this.addPbxGroup([file.path], 'Frameworks'); + this.addPbxGroup([file.path], 'Frameworks', 'Frameworks', null, { isMain: true, filesRelativeToProject: true}); } else { pluginsGroup.children.push(pbxGroupChild(file)); } From 01f1563acaae85634508b957700524b8e200003f Mon Sep 17 00:00:00 2001 From: Nathan Walker Date: Tue, 9 Jul 2024 09:11:37 -0700 Subject: [PATCH 25/31] release: 0.7.1-alpha.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2731a34..a6d5785 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "name": "nativescript-dev-xcode", "description": "parser for xcodeproj/project.pbxproj files", "main": "index.js", - "version": "0.7.1-alpha.3", + "version": "0.7.1-alpha.4", "files": [ "lib", "!lib/parser/pbxproj.pegjs" From 8f96af8e71274570eea6369a7723f67406a67b5c Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Thu, 11 Jul 2024 16:46:53 +0200 Subject: [PATCH 26/31] release: 0.8.0 --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index a6d5785..88f2554 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "name": "nativescript-dev-xcode", "description": "parser for xcodeproj/project.pbxproj files", "main": "index.js", - "version": "0.7.1-alpha.4", + "version": "0.8.0", "files": [ "lib", "!lib/parser/pbxproj.pegjs" @@ -12,7 +12,7 @@ "url": "https://github.com/NativeScript/nativescript-dev-xcode.git" }, "engines": { - "node": ">=6.0.0" + "node": ">=14.0.0" }, "dependencies": { "simple-plist": "1.3.1", From bf41b1d06b951dab4400bb5f267c7a47cb4cf73e Mon Sep 17 00:00:00 2001 From: Nathan Walker Date: Wed, 19 Feb 2025 19:45:06 -0800 Subject: [PATCH 27/31] fix: when removing targets with projects including widgets, ref may not be found This case can be safely ignored to prevent a cli hard exit --- lib/pbxProject.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/pbxProject.js b/lib/pbxProject.js index b45e1be..70f82ea 100644 --- a/lib/pbxProject.js +++ b/lib/pbxProject.js @@ -1855,10 +1855,13 @@ pbxProject.prototype.removeTarget = function(target, targetKey) { if(!stillReferenced) { var frameworkFileRef = fileReferenceSection[fileRef]; - var fileToRemove = new pbxFile(unquote(frameworkFileRef.path), {basename: frameworkFileRef.name}); - fileToRemove.fileRef = fileRef; - this.removeFromFrameworksPbxGroup(fileToRemove); - removeItemAndCommentFromSectionByUuid(fileReferenceSection, fileRef); + if (frameworkFileRef?.path) { + // when working with widgets, the framework might be in a different group + var fileToRemove = new pbxFile(unquote(frameworkFileRef.path), {basename: frameworkFileRef.name}); + fileToRemove.fileRef = fileRef; + this.removeFromFrameworksPbxGroup(fileToRemove); + removeItemAndCommentFromSectionByUuid(fileReferenceSection, fileRef); + } } } files = files.concat(frameworkFiles); From 748f1801e58159a5233b60046b9f566873bf76db Mon Sep 17 00:00:00 2001 From: Nathan Walker Date: Wed, 19 Feb 2025 19:45:22 -0800 Subject: [PATCH 28/31] release: 0.8.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 88f2554..69b2110 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "name": "nativescript-dev-xcode", "description": "parser for xcodeproj/project.pbxproj files", "main": "index.js", - "version": "0.8.0", + "version": "0.8.1", "files": [ "lib", "!lib/parser/pbxproj.pegjs" From f0bf52d9d530c87e7caa9eb839f4feee9d6a14e9 Mon Sep 17 00:00:00 2001 From: farfromrefuge Date: Wed, 11 Mar 2026 21:39:12 +0100 Subject: [PATCH 29/31] fix: prevent error when adding framework from build product dir (#20) --- lib/pbxFile.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/pbxFile.js b/lib/pbxFile.js index 1b52d25..e977084 100644 --- a/lib/pbxFile.js +++ b/lib/pbxFile.js @@ -128,9 +128,11 @@ function pbxFile(filepath, opt) { if (opt.explicitFileType) { this.explicitFileType = opt.explicitFileType; this.basename = this.basename + '.' + defaultExtension(this); - delete this.path; + // dont delete path as it is used after + // delete this.path; delete this.lastKnownFileType; - delete this.group; + // dont delete group as it is used after + // delete this.group; delete this.defaultEncoding; } @@ -155,4 +157,4 @@ function pbxFile(filepath, opt) { } } -module.exports = pbxFile; \ No newline at end of file +module.exports = pbxFile; From 0d2873d860b0729a9b5ed53a597211721b8a3054 Mon Sep 17 00:00:00 2001 From: farfromrefuge Date: Wed, 11 Mar 2026 21:39:59 +0100 Subject: [PATCH 30/31] fix: allow adding resource, source... to a target when it was already added to another target (#21) --- lib/pbxProject.js | 56 ++++++++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/lib/pbxProject.js b/lib/pbxProject.js index 70f82ea..77b7dec 100644 --- a/lib/pbxProject.js +++ b/lib/pbxProject.js @@ -119,8 +119,8 @@ pbxProject.prototype.addPluginFile = function(path, opt) { file.plugin = true; // durr correctForPluginsPath(file, this); - // null is better for early errors - if (this.hasFile(file.path)) return null; + const existingFile = this.hasFile(file.path); + if (existingFile) return {...file, fileRef: existingFile.fileRef}; file.fileRef = this.generateUuid(); @@ -256,19 +256,25 @@ pbxProject.prototype.addResourceFile = function(path, opt, group) { opt = opt || {}; var file; + var fileIsAlreadyAdded = false; if (opt.plugin) { file = this.addPluginFile(path, opt); if (!file) return false; } else { file = new pbxFile(path, opt); - if (this.hasFile(file.path)) return false; + const existingFile = this.hasFile(file.path); + fileIsAlreadyAdded = !!existingFile; + if (existingFile) { + // use existing fileRef + file.fileRef = existingFile.fileRef; + } } file.uuid = this.generateUuid(); file.target = opt ? opt.target : undefined; - if (!opt.plugin) { + if (!opt.plugin && !fileIsAlreadyAdded) { correctForResourcesPath(file, this); file.fileRef = this.generateUuid(); } @@ -278,7 +284,7 @@ pbxProject.prototype.addResourceFile = function(path, opt, group) { this.addToPbxResourcesBuildPhase(file); // PBXResourcesBuildPhase } - if (!opt.plugin) { + if (!opt.plugin && !fileIsAlreadyAdded) { this.addToPbxFileReferenceSection(file); // PBXFileReference if (group) { if (this.getPBXGroupByKey(group)) { @@ -345,8 +351,7 @@ pbxProject.prototype.addFramework = function(fpath, opt) { var fileReference = this.hasFile(file.path); if (fileReference) { - var key = this.getFileKey(file.path); - file.fileRef = key; + file.fileRef = fileReference.fileRef; } else { this.addToPbxFileReferenceSection(file); // PBXFileReference this.addToFrameworksPbxGroup(file); // PBXGroup @@ -424,13 +429,14 @@ pbxProject.prototype.addCopyfile = function(fpath, opt) { // catch duplicates if (this.hasFile(file.path)) { file = this.hasFile(file.path); + } else { + file.fileRef = this.generateUuid(); + this.addToPbxFileReferenceSection(file); // PBXFileReference } - - file.fileRef = file.uuid = this.generateUuid(); + file.uuid = this.generateUuid(); file.target = opt ? opt.target : undefined; this.addToPbxBuildFileSection(file); // PBXBuildFile - this.addToPbxFileReferenceSection(file); // PBXFileReference this.addToPbxCopyfilesBuildPhase(file); // PBXCopyFilesBuildPhase return file; @@ -470,19 +476,24 @@ pbxProject.prototype.addStaticLibrary = function(path, opt) { opt = opt || {}; var file; + var fileIsAlreadyAdded = false; if (opt.plugin) { file = this.addPluginFile(path, opt); if (!file) return false; } else { file = new pbxFile(path, opt); - if (this.hasFile(file.path)) return false; + const existingFile = this.hasFile(file.path); + fileIsAlreadyAdded = !!existingFile; + if (existingFile) { + file.fileRef = existingFile.fileRef; + } } file.uuid = this.generateUuid(); file.target = opt ? opt.target : undefined; - if (!opt.plugin) { + if (!opt.plugin && !fileIsAlreadyAdded) { file.fileRef = this.generateUuid(); this.addToPbxFileReferenceSection(file); // PBXFileReference } @@ -859,20 +870,20 @@ pbxProject.prototype.removeFromPluginsPbxGroup = function(file) { } } -pbxProject.prototype.addToResourcesPbxGroup = function(file) { - var pluginsGroup = this.pbxGroupByName('Resources'); +pbxProject.prototype.addToResourcesPbxGroup = function(file, groupName = 'Resources') { + var pluginsGroup = this.pbxGroupByName(groupName); if (!pluginsGroup) { - this.addPbxGroup([file.path], 'Resources'); + this.addPbxGroup([file.path], groupName); } else { pluginsGroup.children.push(pbxGroupChild(file)); } } -pbxProject.prototype.removeFromResourcesPbxGroup = function(file) { - if (!this.pbxGroupByName('Resources')) { +pbxProject.prototype.removeFromResourcesPbxGroup = function(file, groupName = 'Resources') { + if (!this.pbxGroupByName(groupName)) { return null; } - var pluginsGroupChildren = this.pbxGroupByName('Resources').children, i; + var pluginsGroupChildren = this.pbxGroupByName(groupName).children, i; for (i in pluginsGroupChildren) { if (pbxGroupChild(file).value == pluginsGroupChildren[i].value && pbxGroupChild(file).comment == pluginsGroupChildren[i].comment) { @@ -1680,7 +1691,7 @@ pbxProject.prototype.hasFile = function(filePath) { for (id in files) { file = files[id]; if (file.path == filePath || file.path == ('"' + filePath + '"')) { - return file; + return {...file, fileRef: id}; } } @@ -2058,7 +2069,7 @@ function pbxFileReferenceObj(file) { fileObject.name = "\"" + fileObject.name + "\""; } - if(!file.path.match(NO_SPECIAL_SYMBOLS)) { + if(file.path && !file.path.match(NO_SPECIAL_SYMBOLS)) { fileObject.path = "\"" + fileObject.path + "\""; } @@ -2525,10 +2536,11 @@ pbxProject.prototype.getPBXObject = function(name) { pbxProject.prototype.addFile = function (path, group, opt) { var file = new pbxFile(path, opt); - // null is better for early errors - if (this.hasFile(file.path)) return null; + const existingFile = this.hasFile(file.path); + if (existingFile) return {...file, fileRef: existingFile.fileRef}; file.fileRef = this.generateUuid(); + file.target = opt ? opt.target : undefined; this.addToPbxFileReferenceSection(file); // PBXFileReference From c696dbe865f4c0795a5343561dc2bc5e1661d55f Mon Sep 17 00:00:00 2001 From: farfromrefuge Date: Wed, 11 Mar 2026 21:40:22 +0100 Subject: [PATCH 31/31] fix: addTarget allow different productType (#22) --- lib/pbxProject.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/pbxProject.js b/lib/pbxProject.js index 77b7dec..694ca37 100644 --- a/lib/pbxProject.js +++ b/lib/pbxProject.js @@ -1711,11 +1711,12 @@ pbxProject.prototype.getFileKey = function(filePath) { return false; } -pbxProject.prototype.addTarget = function(name, type, subfolder, parentTarget) { +pbxProject.prototype.addTarget = function(name, type, subfolder, parentTarget, productTargetType) { // Setup uuid and name of new target var targetUuid = this.generateUuid(), targetType = type, + productTargetType = productTargetType || targetType, targetSubfolder = subfolder || name, targetName = name.trim(); @@ -1764,7 +1765,7 @@ pbxProject.prototype.addTarget = function(name, type, subfolder, parentTarget) { // Product: Create var productName = targetName, - productType = producttypeForTargettype(targetType), + productType = producttypeForTargettype(productTargetType), productFileType = filetypeForProducttype(productType), productFile = this.addProductFile(productName, { group: 'Copy Files', 'target': targetUuid, 'explicitFileType': productFileType}), productFileName = productFile.basename; @@ -1792,10 +1793,10 @@ pbxProject.prototype.addTarget = function(name, type, subfolder, parentTarget) { // Target: Add to PBXNativeTarget section this.addToPbxNativeTargetSection(target); - if (targetType === 'app_extension' || targetType === 'watch_extension' || targetType === 'watch_app') { - const isWatchApp = targetType === 'watch_app'; + if (productTargetType === 'app_extension' || productTargetType === 'watch_extension' || productTargetType === 'watch_app') { + const isWatchApp = productTargetType === 'watch_app'; const copyTargetUuid = parentTarget || this.getFirstTarget().uuid; - const phaseComment = targetType === 'watch_app' ? 'Embed Watch Content' : 'Copy Files'; + const phaseComment = productTargetType === 'watch_app' ? 'Embed Watch Content' : 'Copy Files'; let destination; if(isWatchApp) { @@ -1803,7 +1804,7 @@ pbxProject.prototype.addTarget = function(name, type, subfolder, parentTarget) { } // Create CopyFiles phase in parent target - this.addBuildPhase([], 'PBXCopyFilesBuildPhase', phaseComment, copyTargetUuid, targetType, destination); + this.addBuildPhase([], 'PBXCopyFilesBuildPhase', phaseComment, copyTargetUuid, productTargetType, destination); // Add product to CopyFiles phase this.addToPbxCopyfilesBuildPhase(productFile, phaseComment, copyTargetUuid);