// @ts-check const { withDangerousMod, withXcodeProject, IOSConfig, } = require("@expo/config-plugins"); const fs = require("fs"); const path = require("path"); const SWIFT_FILES = [ "BeenVoiceIntentHelpers.swift", "ClockInIntent.swift", "ClockOutIntent.swift", "OpenTimerIntent.swift", "BeenVoiceShortcuts.swift", ]; /** @type {import('@expo/config-plugins').ConfigPlugin} */ function withAppIntents(config) { const appIntentsSource = path.join( config._internal?.projectRoot ?? process.cwd(), "plugins", "app-intents", ); config = withDangerousMod(config, [ "ios", async (config) => { const projectRoot = config.modRequest.projectRoot; const platformRoot = config.modRequest.platformProjectRoot; const projectName = config.modRequest.projectName ?? IOSConfig.XcodeUtils.getProjectName(projectRoot); const targetDir = path.join(platformRoot, projectName); fs.mkdirSync(targetDir, { recursive: true }); for (const file of SWIFT_FILES) { fs.copyFileSync(path.join(appIntentsSource, file), path.join(targetDir, file)); } const appDelegatePath = path.join(targetDir, "AppDelegate.swift"); if (fs.existsSync(appDelegatePath)) { let appDelegate = fs.readFileSync(appDelegatePath, "utf8"); const marker = "BeenVoiceShortcuts.updateAppShortcutParameters"; if (!appDelegate.includes("import AppIntents")) { appDelegate = appDelegate.replace( "internal import Expo", "import AppIntents\ninternal import Expo", ); } if (appDelegate.includes(marker)) { appDelegate = appDelegate.replace( /if #available\(iOS 16\.0, \*\)/g, "if #available(iOS 18.0, *)", ); } else { appDelegate = appDelegate.replace( "return super.application(application, didFinishLaunchingWithOptions: launchOptions)", `if #available(iOS 18.0, *) { Task { await BeenVoiceShortcuts.updateAppShortcutParameters() } } return super.application(application, didFinishLaunchingWithOptions: launchOptions)`, ); } fs.writeFileSync(appDelegatePath, appDelegate); } return config; }, ]); return withXcodeProject(config, (config) => { const project = config.modResults; const projectRoot = config.modRequest.projectRoot; const platformRoot = config.modRequest.platformProjectRoot; const projectName = config.modRequest.projectName ?? IOSConfig.XcodeUtils.getProjectName(projectRoot); for (const file of SWIFT_FILES) { const filepath = `${projectName}/${file}`; const absolutePath = path.join(platformRoot, filepath); if (!fs.existsSync(absolutePath)) continue; const fileRef = project.pbxFileReferenceSection(); const alreadyLinked = Object.values(fileRef).some( (entry) => entry && typeof entry === "object" && "path" in entry && (entry.path === file || entry.path === `${projectName}/${file}` || String(entry.path).endsWith(`/${file}`)), ); if (!alreadyLinked) { IOSConfig.XcodeUtils.addBuildSourceFileToGroup({ filepath, groupName: projectName, project, verbose: true, }); } } return config; }); } module.exports = withAppIntents;