This repository has been archived on 2022-03-12. You can view files and clone it, but cannot push or open issues or pull requests.
2021-04-02 02:24:13 +03:00

1 line
18 KiB
Plaintext

{"version":3,"file":"Xcodeproj.js","sourceRoot":"","sources":["../../../src/ios/utils/Xcodeproj.ts"],"names":[],"mappings":"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","sourcesContent":["import { ExpoConfig } from '@expo/config-types';\nimport * as path from 'path';\nimport xcode, {\n PBXFile,\n PBXGroup,\n PBXNativeTarget,\n PBXProject,\n UUID,\n XCBuildConfiguration,\n XCConfigurationList,\n XcodeProject,\n} from 'xcode';\nimport pbxFile from 'xcode/lib/pbxFile';\n\nimport { assert } from '../../utils/errors';\nimport { addWarningIOS } from '../../utils/warnings';\nimport * as Paths from '../Paths';\n\nexport type ProjectSectionEntry = [string, PBXProject];\n\nexport type NativeTargetSection = Record<string, PBXNativeTarget>;\n\nexport type NativeTargetSectionEntry = [string, PBXNativeTarget];\n\nexport type ConfigurationLists = Record<string, XCConfigurationList>;\n\nexport type ConfigurationListEntry = [string, XCConfigurationList];\n\nexport type ConfigurationSectionEntry = [string, XCBuildConfiguration];\n\nexport function getProjectName(projectRoot: string) {\n const sourceRoot = Paths.getSourceRoot(projectRoot);\n return path.basename(sourceRoot);\n}\n\n// TODO: come up with a better solution for using app.json expo.name in various places\nfunction sanitizedName(name: string) {\n return name\n .replace(/[\\W_]+/g, '')\n .normalize('NFD')\n .replace(/[\\u0300-\\u036f]/g, '');\n}\n\n// TODO: it's silly and kind of fragile that we look at app config to determine\n// the ios project paths. Overall this function needs to be revamped, just a\n// placeholder for now! Make this more robust when we support applying config\n// at any time (currently it's only applied on eject).\nexport function getHackyProjectName(projectRoot: string, config: ExpoConfig): string {\n // Attempt to get the current ios folder name (apply).\n try {\n return getProjectName(projectRoot);\n } catch {\n // If no iOS project exists then create a new one (eject).\n const projectName = config.name;\n assert(projectName, 'Your project needs a name in app.json/app.config.js.');\n return sanitizedName(projectName);\n }\n}\n\nfunction createProjectFileForGroup({ filepath, group }: { filepath: string; group: PBXGroup }) {\n const file = new pbxFile(filepath);\n\n const conflictingFile = group.children.find(child => child.comment === file.basename);\n if (conflictingFile) {\n // This can happen when a file like the GoogleService-Info.plist needs to be added and the eject command is run twice.\n // Not much we can do here since it might be a conflicting file.\n return null;\n }\n return file;\n}\n\n/**\n * Add a resource file (ex: `SplashScreen.storyboard`, `Images.xcassets`) to an Xcode project.\n * This is akin to creating a new code file in Xcode with `⌘+n`.\n */\nexport function addResourceFileToGroup({\n filepath,\n groupName,\n // Should add to `PBXBuildFile Section`\n isBuildFile,\n project,\n}: {\n filepath: string;\n groupName: string;\n isBuildFile?: boolean;\n project: XcodeProject;\n}): XcodeProject {\n return addFileToGroupAndLink({\n filepath,\n groupName,\n project,\n addFileToProject({ project, file }) {\n project.addToPbxFileReferenceSection(file);\n if (isBuildFile) {\n project.addToPbxBuildFileSection(file);\n }\n project.addToPbxResourcesBuildPhase(file);\n },\n });\n}\n\n/**\n * Add a build source file (ex: `AppDelegate.m`, `ViewController.swift`) to an Xcode project.\n * This is akin to creating a new code file in Xcode with `⌘+n`.\n */\nexport function addBuildSourceFileToGroup({\n filepath,\n groupName,\n project,\n}: {\n filepath: string;\n groupName: string;\n project: XcodeProject;\n}): XcodeProject {\n return addFileToGroupAndLink({\n filepath,\n groupName,\n project,\n addFileToProject({ project, file }) {\n project.addToPbxFileReferenceSection(file);\n project.addToPbxBuildFileSection(file);\n project.addToPbxSourcesBuildPhase(file);\n },\n });\n}\n\n// TODO(brentvatne): I couldn't figure out how to do this with an existing\n// higher level function exposed by the xcode library, but we should find out how to do\n// that and replace this with it\nexport function addFileToGroupAndLink({\n filepath,\n groupName,\n project,\n addFileToProject,\n}: {\n filepath: string;\n groupName: string;\n project: XcodeProject;\n addFileToProject: (props: { file: PBXFile; project: XcodeProject }) => void;\n}): XcodeProject {\n const group = pbxGroupByPathOrAssert(project, groupName);\n\n const file = createProjectFileForGroup({ filepath, group });\n\n if (!file) {\n // This can happen when a file like the GoogleService-Info.plist needs to be added and the eject command is run twice.\n // Not much we can do here since it might be a conflicting file.\n addWarningIOS(\n 'ios-xcode-project',\n `Skipped adding duplicate file \"${filepath}\" to PBXGroup named \"${groupName}\"`\n );\n return project;\n }\n\n file.uuid = project.generateUuid();\n file.fileRef = project.generateUuid();\n\n addFileToProject({ project, file });\n\n group.children.push({\n value: file.fileRef,\n comment: file.basename,\n });\n return project;\n}\n\nexport function getApplicationNativeTarget({\n project,\n projectName,\n}: {\n project: XcodeProject;\n projectName: string;\n}) {\n const applicationNativeTarget = project.getTarget('com.apple.product-type.application');\n assert(\n applicationNativeTarget,\n `Couldn't locate application PBXNativeTarget in '.xcodeproj' file.`\n );\n assert(\n String(applicationNativeTarget.target.name) === projectName,\n `Application native target name mismatch. Expected ${projectName}, but found ${applicationNativeTarget.target.name}.`\n );\n return applicationNativeTarget;\n}\n\n/**\n * Add a framework to the default app native target.\n *\n * @param projectName Name of the PBX project.\n * @param framework String ending in `.framework`, i.e. `StoreKit.framework`\n */\nexport function addFramework({\n project,\n projectName,\n framework,\n}: {\n project: XcodeProject;\n projectName: string;\n framework: string;\n}) {\n const target = getApplicationNativeTarget({ project, projectName });\n return project.addFramework(framework, { target: target.uuid });\n}\n\nfunction splitPath(path: string): string[] {\n // TODO: Should we account for other platforms that may not use `/`\n return path.split('/');\n}\n\nconst findGroup = (\n group: PBXGroup | undefined,\n name: string\n):\n | {\n value: UUID;\n comment?: string;\n }\n | undefined => {\n if (!group) {\n return undefined;\n }\n\n return group.children.find(group => group.comment === name);\n};\n\nfunction findGroupInsideGroup(\n project: XcodeProject,\n group: PBXGroup | undefined,\n name: string\n): null | PBXGroup {\n const foundGroup = findGroup(group, name);\n if (foundGroup) {\n return project.getPBXGroupByKey(foundGroup.value) ?? null;\n }\n return null;\n}\n\nfunction pbxGroupByPathOrAssert(project: XcodeProject, path: string): PBXGroup {\n const { firstProject } = project.getFirstProject();\n\n let group = project.getPBXGroupByKey(firstProject.mainGroup);\n\n const components = splitPath(path);\n for (const name of components) {\n const nextGroup = findGroupInsideGroup(project, group, name);\n if (nextGroup) {\n group = nextGroup;\n } else {\n break;\n }\n }\n\n if (!group) {\n throw Error(`Xcode PBXGroup with name \"${path}\" could not be found in the Xcode project.`);\n }\n\n return group;\n}\n\nexport function ensureGroupRecursively(project: XcodeProject, filepath: string): PBXGroup | null {\n const components = splitPath(filepath);\n const hasChild = (group: PBXGroup, name: string) =>\n group.children.find(({ comment }) => comment === name);\n const { firstProject } = project.getFirstProject();\n\n let topMostGroup = project.getPBXGroupByKey(firstProject.mainGroup);\n\n for (const pathComponent of components) {\n if (topMostGroup && !hasChild(topMostGroup, pathComponent)) {\n topMostGroup.children.push({\n comment: pathComponent,\n value: project.pbxCreateGroup(pathComponent, '\"\"'),\n });\n }\n topMostGroup = project.pbxGroupByName(pathComponent);\n }\n return topMostGroup ?? null;\n}\n\n/**\n * Get the pbxproj for the given path\n */\nexport function getPbxproj(projectRoot: string): XcodeProject {\n const projectPath = Paths.getPBXProjectPath(projectRoot);\n const project = xcode.project(projectPath);\n project.parseSync();\n return project;\n}\n\n/**\n * Get the productName for a project, if the name is using a variable `$(TARGET_NAME)`, then attempt to get the value of that variable.\n *\n * @param project\n */\nexport function getProductName(project: XcodeProject): string {\n let productName = project.productName;\n\n if (productName === '$(TARGET_NAME)') {\n const targetName = project.getFirstTarget()?.firstTarget?.productName;\n productName = targetName ?? project.productName;\n }\n\n return productName;\n}\n\nexport function getProjectSection(project: XcodeProject) {\n return project.pbxProjectSection();\n}\n\nexport function getNativeTargets(project: XcodeProject): NativeTargetSectionEntry[] {\n const section = project.pbxNativeTargetSection();\n return Object.entries(section).filter(isNotComment);\n}\n\nexport function findFirstNativeTarget(project: XcodeProject): NativeTargetSectionEntry {\n const { targets } = Object.values(getProjectSection(project))[0];\n const target = targets[0].value;\n const nativeTargets = getNativeTargets(project);\n return nativeTargets.find(([key]) => key === target) as NativeTargetSectionEntry;\n}\n\nexport function findNativeTargetByName(\n project: XcodeProject,\n targetName: string\n): NativeTargetSectionEntry {\n const nativeTargets = getNativeTargets(project);\n return nativeTargets.find(\n ([, i]) => i.name === targetName || i.name === `\"${targetName}\"`\n ) as NativeTargetSectionEntry;\n}\n\nexport function getXCConfigurationListEntries(project: XcodeProject): ConfigurationListEntry[] {\n const lists = project.pbxXCConfigurationList();\n return Object.entries(lists).filter(isNotComment);\n}\n\nexport function getBuildConfigurationForId(\n project: XcodeProject,\n configurationListId: string\n): ConfigurationSectionEntry[] {\n const configurationListEntries = getXCConfigurationListEntries(project);\n const [, configurationList] = configurationListEntries.find(\n ([key]) => key === configurationListId\n ) as ConfigurationListEntry;\n\n const buildConfigurations = configurationList.buildConfigurations.map(i => i.value);\n\n return Object.entries(project.pbxXCBuildConfigurationSection())\n .filter(isNotComment)\n .filter(isBuildConfig)\n .filter(isNotTestHost)\n .filter(([key]: ConfigurationSectionEntry) => buildConfigurations.includes(key));\n}\n\nexport function isBuildConfig([, sectionItem]: ConfigurationSectionEntry): boolean {\n return sectionItem.isa === 'XCBuildConfiguration';\n}\n\nexport function isNotTestHost([, sectionItem]: ConfigurationSectionEntry): boolean {\n return !sectionItem.buildSettings.TEST_HOST;\n}\n\nexport function isNotComment([key]:\n | ConfigurationSectionEntry\n | ProjectSectionEntry\n | ConfigurationListEntry\n | NativeTargetSectionEntry): boolean {\n return !key.endsWith(`_comment`);\n}\n"]}