@bacons/xcode
Version:
pbxproj parser
232 lines • 8.52 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.PBXGroup = exports.AbstractGroup = void 0;
const assert_1 = __importDefault(require("assert"));
const path_1 = __importDefault(require("path"));
const constants_1 = require("./utils/constants");
const json = __importStar(require("../json/types"));
const paths_1 = require("./utils/paths");
const AbstractObject_1 = require("./AbstractObject");
const PBXFileReference_1 = require("./PBXFileReference");
// const debug = require("debug")("xcparse:models") as typeof console.log;
class AbstractGroup extends AbstractObject_1.AbstractObject {
// This doesn't have to be any, but otherwise the type is unacceptably long.
getObjectProps() {
return {
children: Array,
};
}
setupDefaults() {
if (!this.props.children) {
this.props.children = [];
}
}
createGroup(opts) {
(0, assert_1.default)(opts.path || opts.name, "A group must have a path or name");
const group = PBXGroup.create(this.getXcodeProject(), {
...opts,
});
this.props.children.push(group);
return group;
}
/**
* Traverses the children groups and finds the children with the given
* path, optionally, creating any needed group. If the given path is
* `null` it returns itself.
*
* @param path a string with the names of the groups separated by a `/`.
* @param shouldCreate whether the path should be created.
*
* @return `PBXGroup` the group if found.
* @return `null` if the `path` could not be found and `shouldCreate` is `false`.
*/
mkdir(path, { recursive } = {}) {
let pathArr = typeof path === "string" ? path.split("/") : path;
if (!pathArr.length) {
return this;
}
let childName = pathArr.shift();
let child = this.getChildGroups().find((c) => c.getDisplayName() === childName);
if (!child) {
if (!recursive) {
return null;
}
// @ts-expect-error: IDK
child = this.createGroup({
path: childName,
});
}
if (!path.length) {
return child;
}
return child.mkdir(pathArr, { recursive });
}
getChildGroups() {
return this.props.children.filter((child) => PBXGroup.is(child));
}
createNewProductRefForTarget(productBaseName, type) {
let prefix = "";
if (type == "staticLibrary") {
prefix = "lib";
}
let extension = constants_1.PRODUCT_UTI_EXTENSIONS[type];
let path = `${prefix}${productBaseName}`;
if (extension) {
path += `.${extension}`;
}
let ref = newReference(this, path, "BUILT_PRODUCTS_DIR");
ref.props.includeInIndex = 0;
ref.setExplicitFileType();
return ref;
}
static move(object, newParent) {
(0, assert_1.default)(PBXGroup.is(newParent), "newParent must be a PBXGroup");
(0, assert_1.default)(object, `Attempt to move nullish object to "${newParent.uuid}".`);
(0, assert_1.default)(newParent, `Attempt to move object "${object.uuid}" to nullish parent.`);
(0, assert_1.default)(newParent.uuid !== object.uuid, `Attempt to move object "${object.uuid}" to itself.`);
(0, assert_1.default)(!(0, paths_1.getParents)(newParent).find((parent) => parent.uuid === object.uuid), `Attempt to move object "${object.uuid}" to a child object "${newParent.uuid}".`);
const currentParent = object.getParent();
if (PBXGroup.is(currentParent)) {
const index = currentParent.props.children.findIndex((child) => child.uuid === object.uuid);
if (index !== -1) {
currentParent.props.children.splice(index, 1);
}
}
newParent.props.children.push(object);
}
getParent() {
return (0, paths_1.getParent)(this);
}
getParents() {
return (0, paths_1.getParents)(this);
}
isReferencing(uuid) {
return !!this.props.children.find((child) => child.uuid === uuid);
}
removeReference(uuid) {
const index = this.props.children.findIndex((child) => child.uuid === uuid);
if (index !== -1) {
this.props.children.splice(index, 1);
}
}
getPath() {
throw new Error("TODO");
}
createFile(opts) {
const fileReference = PBXFileReference_1.PBXFileReference.create(this.getXcodeProject(), opts);
this.props.children.push(fileReference);
return fileReference;
}
getDisplayName() {
if (this.props.name) {
return this.props.name;
}
else if (this.props.path) {
return path_1.default.basename(this.props.path);
}
else if (this.uuid === this.project.props.mainGroup.uuid) {
return "Main Group";
}
// Probably never happens
return this.isa.replace(/^(PBX|XC)/, "");
}
}
exports.AbstractGroup = AbstractGroup;
class PBXGroup extends AbstractGroup {
static is(object) {
return object.isa === PBXGroup.isa;
}
static create(project, opts) {
return project.createModel({
isa: PBXGroup.isa,
children: [],
sourceTree: "<group>",
...opts,
});
}
}
exports.PBXGroup = PBXGroup;
PBXGroup.isa = json.ISA.PBXGroup;
/**
* Creates a new file reference with the given path and adds it to the
* given group.
*
* @param group The group to which to add the reference.
*
* @param path The, preferably absolute, path of the reference.
*
* @param sourceTree The source tree key to use to configure the path.
*
* @return `PBXFileReference` The new file reference.
*/
function newFileReference(group, filepath, sourceTree) {
return group.createFile({
path: filepath,
sourceTree: sourceTree,
});
}
/**
* Creates a new reference with the given path and adds it to the
* provided group. The reference is configured according to the extension
* of the path.
*/
function newReference(group, filePath, sourceTree) {
const ref = (() => {
switch (path_1.default.extname(filePath).toLowerCase()) {
case ".xcdatamodeld":
case ".xcodeproj":
// TODO: maybe add this
throw new Error("Unsupported file type: " + filePath);
default:
return newFileReference(group, filePath, sourceTree);
}
})();
configureDefaultsForFileReference(ref);
return ref;
}
/**
* Configures a file reference according to the extension to math
* Xcode behavior.
*
* @param ref The file reference to configure.
*
* @note To closely match the Xcode behavior the name attribute of
* the file reference is set only if the path of the file is
* not equal to the path of the group.
*/
function configureDefaultsForFileReference(ref) {
if (ref.props.path?.includes("/")) {
ref.props.name = ref.props.path.split("/").pop();
}
if (ref.props.path &&
path_1.default.extname(ref.props.path).toLowerCase() == ".framework") {
ref.props.includeInIndex = undefined;
}
}
//# sourceMappingURL=AbstractGroup.js.map