1import fs from 'fs';
2import path from 'path';
3
4import { addBuildSourceFileToGroup, getProjectName } from './utils/Xcodeproj';
5import { ConfigPlugin, XcodeProject } from '../Plugin.types';
6import { withXcodeProject } from '../plugins/ios-plugins';
7
8/**
9 * Create a build source file and link it to Xcode.
10 *
11 * @param config
12 * @param props.filePath relative to the build source folder. ex: `ViewController.swift` would be created in `ios/myapp/ViewController.swift`.
13 * @param props.contents file contents to write.
14 * @param props.overwrite should the contents overwrite any existing file in the same location on disk.
15 * @returns
16 */
17export const withBuildSourceFile: ConfigPlugin<{
18  filePath: string;
19  contents: string;
20  overwrite?: boolean;
21}> = (config, { filePath, contents, overwrite }) => {
22  return withXcodeProject(config, (config) => {
23    const projectName = getProjectName(config.modRequest.projectRoot);
24
25    config.modResults = createBuildSourceFile({
26      project: config.modResults,
27      nativeProjectRoot: config.modRequest.platformProjectRoot,
28      fileContents: contents,
29      filePath: path.join(projectName, filePath),
30      overwrite,
31    });
32    return config;
33  });
34};
35
36/**
37 * Add a source file to the Xcode project and write it to the file system.
38 *
39 * @param nativeProjectRoot absolute path to the native app root `user/app/ios`
40 * @param filePath path relative to the `nativeProjectRoot` for the file to create `user/app/ios/myapp/foobar.swift`
41 * @param fileContents string file contents to write to the `filePath`
42 * @param overwrite should write file even if one already exists
43 */
44export function createBuildSourceFile({
45  project,
46  nativeProjectRoot,
47  filePath,
48  fileContents,
49  overwrite,
50}: {
51  project: XcodeProject;
52  nativeProjectRoot: string;
53  filePath: string;
54  fileContents: string;
55  overwrite?: boolean;
56}): XcodeProject {
57  const absoluteFilePath = path.join(nativeProjectRoot, filePath);
58  if (overwrite || !fs.existsSync(absoluteFilePath)) {
59    // Create the file
60    fs.writeFileSync(absoluteFilePath, fileContents, 'utf8');
61  }
62
63  // `myapp`
64  const groupName = path.dirname(filePath);
65
66  // Ensure the file is linked with Xcode resource files
67  if (!project.hasFile(filePath)) {
68    project = addBuildSourceFileToGroup({
69      filepath: filePath,
70      groupName,
71      project,
72    });
73  }
74  return project;
75}
76