From 73de2aab0a57ed744cef00a4001dd2f23e1d5e08 Mon Sep 17 00:00:00 2001 From: Joe Hanley Date: Wed, 31 Jul 2024 15:00:55 -0700 Subject: [PATCH 1/6] Default to default --- src/init/features/dataconnect/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/init/features/dataconnect/index.ts b/src/init/features/dataconnect/index.ts index 7dfcea79385..1f363a061bf 100644 --- a/src/init/features/dataconnect/index.ts +++ b/src/init/features/dataconnect/index.ts @@ -43,7 +43,7 @@ export interface RequiredInfo { } const defaultConnector = { - id: "default-connector", + id: "default", files: [ { path: "queries.gql", From af84671a97adf3fd6f99637299cb1c6dd12a9c87 Mon Sep 17 00:00:00 2001 From: Joe Hanley Date: Thu, 1 Aug 2024 14:12:39 -0700 Subject: [PATCH 2/6] progress on using app detection in sdk:init --- src/init/features/dataconnect/sdk.ts | 89 +++++++++++++++------------- 1 file changed, 48 insertions(+), 41 deletions(-) diff --git a/src/init/features/dataconnect/sdk.ts b/src/init/features/dataconnect/sdk.ts index dc56b8e88d4..b017bc7ac46 100644 --- a/src/init/features/dataconnect/sdk.ts +++ b/src/init/features/dataconnect/sdk.ts @@ -1,21 +1,20 @@ import * as yaml from "yaml"; import * as fs from "fs"; import * as clc from "colorette"; +import * as path from "path"; import { confirm, promptOnce } from "../../../prompt"; -import { readFirebaseJson } from "../../../dataconnect/fileUtils"; +import { readFirebaseJson, getPlatformFromFolder } from "../../../dataconnect/fileUtils"; import { Config } from "../../../config"; import { Setup } from "../.."; import { load } from "../../../dataconnect/load"; import { logger } from "../../../logger"; -import { ConnectorInfo, ConnectorYaml, JavascriptSDK, KotlinSDK } from "../../../dataconnect/types"; +import { ConnectorInfo, ConnectorYaml, JavascriptSDK, KotlinSDK, Platform } from "../../../dataconnect/types"; import { DataConnectEmulator } from "../../../emulator/dataconnectEmulator"; import { FirebaseError } from "../../../error"; import { camelCase, snakeCase } from "lodash"; +import { logLabeledSuccess, logLabeledBullet } from '../../../utils'; -const IOS = "ios"; -const WEB = "web"; -const ANDROID = "android"; export type SDKInfo = { connectorYamlContents: string; connectorInfo: ConnectorInfo; @@ -53,20 +52,40 @@ async function askQuestions(setup: Setup, config: Config): Promise { type: "list", choices: connectorChoices, }); - - let platforms: string[] = []; - while (!platforms.length) { - platforms = await promptOnce({ - message: "Which platforms do you want to set up a generated SDK for?", - type: "checkbox", - choices: [ - { name: "iOS (Swift)", value: IOS }, - { name: "Web (JavaScript)", value: WEB }, - { name: "Androd (Kotlin)", value: ANDROID }, - ], + + // First, lets check if we are in a app directory + let targetPlatform: Platform = Platform.UNDETERMINED; + let appDir: string; + const cwdPlatformGuess = await getPlatformFromFolder(process.cwd()) + // If we are, we'll use that directory + if (cwdPlatformGuess !== Platform.UNDETERMINED) { + logLabeledSuccess("dataconnect", `Detected ${cwdPlatformGuess} app in current directory ${process.cwd()}`); + targetPlatform = cwdPlatformGuess; + appDir = process.cwd(); + } else { + // If we aren't, ask the user where their app is, and try to autodetect from there + logLabeledBullet("dataconnect",`Couldn't automatically detect your app directory.`); + appDir = await promptOnce({ + message: "Where is your app directory?" }); - if (!platforms.length) { - logger.info("You must pick at least one platform."); + // TODO: Validate? + // TODO: test both absolute and relative paths. + const platformGuess = await getPlatformFromFolder(appDir); + if (platformGuess !== Platform.UNDETERMINED) { + logLabeledSuccess("dataconnect",`Detected ${platformGuess} app in directory ${appDir}`); + targetPlatform = platformGuess + } else { + // If we still can't autodetect, just ask the user + logLabeledBullet("dataconnect","Couldn't automatically detect your app's platform."); + targetPlatform = await promptOnce({ + message: "Which platform do you want to set up a generated SDK for?", + type: "list", + choices: [ + { name: "iOS (Swift)", value: Platform.IOS }, + { name: "Web (JavaScript)", value: Platform.WEB }, + { name: "Androd (Kotlin)", value: Platform.ANDROID }, + ], + }); } } @@ -75,26 +94,17 @@ async function askQuestions(setup: Setup, config: Config): Promise { newConnectorYaml.generate = {}; } - if (platforms.includes(IOS)) { - const outputDir = await promptOnce({ - message: `What directory do you want to write your Swift SDK code to? (If not absolute, path will be relative to '${connectorInfo.directory}')`, - type: "input", - default: - newConnectorYaml.generate.swiftSdk?.outputDir || - `./../gensdk/${newConnectorYaml.connectorId}/swift-sdk`, - }); + if (targetPlatform === Platform.IOS) { + const outputDir = newConnectorYaml.generate.swiftSdk?.outputDir || + path.join(appDir, `generated/${newConnectorYaml.connectorId}`); const pkg = camelCase(newConnectorYaml.connectorId); const swiftSdk = { outputDir, package: pkg }; newConnectorYaml.generate.swiftSdk = swiftSdk; } - if (platforms.includes(WEB)) { - const outputDir = await promptOnce({ - message: `What directory do you want to write your JavaScript SDK code to? (If not absolute, path will be relative to '${connectorInfo.directory}')`, - type: "input", - default: - newConnectorYaml.generate.javascriptSdk?.outputDir || - `./../gensdk/${newConnectorYaml.connectorId}/javascript-sdk`, - }); + + if (targetPlatform === Platform.WEB) { + const outputDir = newConnectorYaml.generate.javascriptSdk?.outputDir || + path.join(appDir, `generated/${newConnectorYaml.connectorId}`) const pkg = newConnectorYaml.generate.javascriptSdk?.package ?? `@firebasegen/${connectorInfo.connectorYaml.connectorId}`; @@ -114,14 +124,11 @@ async function askQuestions(setup: Setup, config: Config): Promise { } newConnectorYaml.generate.javascriptSdk = javascriptSdk; } - if (platforms.includes(ANDROID)) { - const outputDir = await promptOnce({ - message: `What directory do you want to write your Kotlin SDK code to? (If not absolute, path will be relative to '${connectorInfo.directory}')`, - type: "input", - default: + + if (targetPlatform === Platform.ANDROID) { + const outputDir = newConnectorYaml.generate.kotlinSdk?.outputDir || - `./../gensdk/${newConnectorYaml.connectorId}/kotlin-sdk`, - }); + path.join(appDir, `generated/${newConnectorYaml.connectorId}`) const pkg = newConnectorYaml.generate.kotlinSdk?.package ?? `connectors.${snakeCase(connectorInfo.connectorYaml.connectorId)}`; From 6b2622dea0175c20821e1f1c5c78ef66d436d770 Mon Sep 17 00:00:00 2001 From: Joe Hanley Date: Thu, 1 Aug 2024 17:05:33 -0700 Subject: [PATCH 3/6] Don't ask, just know --- src/dataconnect/fileUtils.ts | 5 ++ src/dataconnect/types.ts | 2 +- src/init/features/dataconnect/sdk.ts | 90 ++++++++++++++++++---------- 3 files changed, 63 insertions(+), 34 deletions(-) diff --git a/src/dataconnect/fileUtils.ts b/src/dataconnect/fileUtils.ts index ef5a9a9f119..07317b8e86f 100644 --- a/src/dataconnect/fileUtils.ts +++ b/src/dataconnect/fileUtils.ts @@ -132,3 +132,8 @@ export async function getPlatformFromFolder(dirPath: string) { return Platform.UNDETERMINED; } + +export async function directoryHasPackageJson(dirPath: string) { + const fileNames = await fs.readdir(dirPath); + return fileNames.some((f) => f.toLowerCase() === "package.json"); +} diff --git a/src/dataconnect/types.ts b/src/dataconnect/types.ts index d7076dd7947..fd9fa846058 100644 --- a/src/dataconnect/types.ts +++ b/src/dataconnect/types.ts @@ -135,7 +135,7 @@ export interface Generate { export interface JavascriptSDK { outputDir: string; package: string; - packageJSONDir?: string; + packageJsonDir?: string; } export interface SwiftSDK { diff --git a/src/init/features/dataconnect/sdk.ts b/src/init/features/dataconnect/sdk.ts index b017bc7ac46..ec21e841dcd 100644 --- a/src/init/features/dataconnect/sdk.ts +++ b/src/init/features/dataconnect/sdk.ts @@ -4,16 +4,26 @@ import * as clc from "colorette"; import * as path from "path"; import { confirm, promptOnce } from "../../../prompt"; -import { readFirebaseJson, getPlatformFromFolder } from "../../../dataconnect/fileUtils"; +import { + readFirebaseJson, + getPlatformFromFolder, + directoryHasPackageJson, +} from "../../../dataconnect/fileUtils"; import { Config } from "../../../config"; import { Setup } from "../.."; import { load } from "../../../dataconnect/load"; import { logger } from "../../../logger"; -import { ConnectorInfo, ConnectorYaml, JavascriptSDK, KotlinSDK, Platform } from "../../../dataconnect/types"; +import { + ConnectorInfo, + ConnectorYaml, + JavascriptSDK, + KotlinSDK, + Platform, +} from "../../../dataconnect/types"; import { DataConnectEmulator } from "../../../emulator/dataconnectEmulator"; import { FirebaseError } from "../../../error"; import { camelCase, snakeCase } from "lodash"; -import { logLabeledSuccess, logLabeledBullet } from '../../../utils'; +import { logLabeledSuccess, logLabeledBullet } from "../../../utils"; export type SDKInfo = { connectorYamlContents: string; @@ -52,31 +62,34 @@ async function askQuestions(setup: Setup, config: Config): Promise { type: "list", choices: connectorChoices, }); - + // First, lets check if we are in a app directory let targetPlatform: Platform = Platform.UNDETERMINED; let appDir: string; - const cwdPlatformGuess = await getPlatformFromFolder(process.cwd()) - // If we are, we'll use that directory + const cwdPlatformGuess = await getPlatformFromFolder(process.cwd()); if (cwdPlatformGuess !== Platform.UNDETERMINED) { - logLabeledSuccess("dataconnect", `Detected ${cwdPlatformGuess} app in current directory ${process.cwd()}`); + // If we are, we'll use that directory + logLabeledSuccess( + "dataconnect", + `Detected ${cwdPlatformGuess} app in current directory ${process.cwd()}`, + ); targetPlatform = cwdPlatformGuess; appDir = process.cwd(); } else { // If we aren't, ask the user where their app is, and try to autodetect from there - logLabeledBullet("dataconnect",`Couldn't automatically detect your app directory.`); - appDir = await promptOnce({ - message: "Where is your app directory?" - }); - // TODO: Validate? - // TODO: test both absolute and relative paths. + logLabeledBullet("dataconnect", `Couldn't automatically detect your app directory.`); + appDir = config.path( + await promptOnce({ + message: "Where is your app directory?", + }), + ); const platformGuess = await getPlatformFromFolder(appDir); if (platformGuess !== Platform.UNDETERMINED) { - logLabeledSuccess("dataconnect",`Detected ${platformGuess} app in directory ${appDir}`); - targetPlatform = platformGuess + logLabeledSuccess("dataconnect", `Detected ${platformGuess} app in directory ${appDir}`); + targetPlatform = platformGuess; } else { // If we still can't autodetect, just ask the user - logLabeledBullet("dataconnect","Couldn't automatically detect your app's platform."); + logLabeledBullet("dataconnect", "Couldn't automatically detect your app's platform."); targetPlatform = await promptOnce({ message: "Which platform do you want to set up a generated SDK for?", type: "list", @@ -95,40 +108,51 @@ async function askQuestions(setup: Setup, config: Config): Promise { } if (targetPlatform === Platform.IOS) { - const outputDir = newConnectorYaml.generate.swiftSdk?.outputDir || - path.join(appDir, `generated/${newConnectorYaml.connectorId}`); + const outputDir = + newConnectorYaml.generate.swiftSdk?.outputDir || + path.relative( + connectorInfo.directory, + path.join(appDir, `generated/${newConnectorYaml.connectorId}`), + ); const pkg = camelCase(newConnectorYaml.connectorId); const swiftSdk = { outputDir, package: pkg }; newConnectorYaml.generate.swiftSdk = swiftSdk; } - + if (targetPlatform === Platform.WEB) { - const outputDir = newConnectorYaml.generate.javascriptSdk?.outputDir || - path.join(appDir, `generated/${newConnectorYaml.connectorId}`) + const outputDir = + newConnectorYaml.generate.javascriptSdk?.outputDir || + path.relative( + connectorInfo.directory, + path.join(appDir, `generated/${newConnectorYaml.connectorId}`), + ); const pkg = newConnectorYaml.generate.javascriptSdk?.package ?? `@firebasegen/${connectorInfo.connectorYaml.connectorId}`; - const packageJSONDir = await promptOnce({ - message: - "Which directory contains the package.json that you would like to add the JavaScript SDK dependency to? (Leave blank to skip)", - type: "input", - default: newConnectorYaml.generate.javascriptSdk?.packageJSONDir, - }); - // ../.. since we ask relative to connector.yaml + const javascriptSdk: JavascriptSDK = { outputDir, package: pkg, }; - if (packageJSONDir) { - javascriptSdk.packageJSONDir = packageJSONDir; + + if ( + (await directoryHasPackageJson(appDir)) && + (await confirm({ + message: "Would you like to add a dependency on the generated SDK to your package.json?", + })) + ) { + javascriptSdk.packageJsonDir = path.relative(connectorInfo.directory, appDir); } newConnectorYaml.generate.javascriptSdk = javascriptSdk; } if (targetPlatform === Platform.ANDROID) { - const outputDir = - newConnectorYaml.generate.kotlinSdk?.outputDir || - path.join(appDir, `generated/${newConnectorYaml.connectorId}`) + const outputDir = + newConnectorYaml.generate.kotlinSdk?.outputDir || + path.relative( + connectorInfo.directory, + path.join(appDir, `generated/${newConnectorYaml.connectorId}`), + ); const pkg = newConnectorYaml.generate.kotlinSdk?.package ?? `connectors.${snakeCase(connectorInfo.connectorYaml.connectorId)}`; From 073c3c60241b1b95b0de7d3d5f4665e6ddb85018 Mon Sep 17 00:00:00 2001 From: Joe Hanley Date: Fri, 2 Aug 2024 12:06:14 -0700 Subject: [PATCH 4/6] Better handling of file not found, tested IOS and Android --- src/dataconnect/fileUtils.ts | 2 +- src/init/features/dataconnect/sdk.ts | 37 +++++++++++++++------------- src/prompt.ts | 32 ++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 18 deletions(-) diff --git a/src/dataconnect/fileUtils.ts b/src/dataconnect/fileUtils.ts index 07317b8e86f..1eb977d12c1 100644 --- a/src/dataconnect/fileUtils.ts +++ b/src/dataconnect/fileUtils.ts @@ -110,7 +110,7 @@ export async function pickService( // case insensitive exact match indicators for supported app platforms const WEB_INDICATORS = ["package.json", "package-lock.json", "node_modules"]; const IOS_INDICATORS = ["info.plist", "podfile", "package.swift"]; -const ANDROID_INDICATORS = ["androidmanifest.xml", "build.gradle"]; +const ANDROID_INDICATORS = ["androidmanifest.xml", "build.gradle", "build.gradle.kts"]; // endswith match const IOS_INDICATORS_2 = [".xcworkspace", ".xcodeproj"]; diff --git a/src/init/features/dataconnect/sdk.ts b/src/init/features/dataconnect/sdk.ts index ec21e841dcd..f5b523a1954 100644 --- a/src/init/features/dataconnect/sdk.ts +++ b/src/init/features/dataconnect/sdk.ts @@ -3,7 +3,7 @@ import * as fs from "fs"; import * as clc from "colorette"; import * as path from "path"; -import { confirm, promptOnce } from "../../../prompt"; +import { confirm, promptForDirectory, promptOnce } from "../../../prompt"; import { readFirebaseJson, getPlatformFromFolder, @@ -12,7 +12,6 @@ import { import { Config } from "../../../config"; import { Setup } from "../.."; import { load } from "../../../dataconnect/load"; -import { logger } from "../../../logger"; import { ConnectorInfo, ConnectorYaml, @@ -23,7 +22,7 @@ import { import { DataConnectEmulator } from "../../../emulator/dataconnectEmulator"; import { FirebaseError } from "../../../error"; import { camelCase, snakeCase } from "lodash"; -import { logLabeledSuccess, logLabeledBullet } from "../../../utils"; +import { logSuccess, logBullet } from "../../../utils"; export type SDKInfo = { connectorYamlContents: string; @@ -69,27 +68,23 @@ async function askQuestions(setup: Setup, config: Config): Promise { const cwdPlatformGuess = await getPlatformFromFolder(process.cwd()); if (cwdPlatformGuess !== Platform.UNDETERMINED) { // If we are, we'll use that directory - logLabeledSuccess( - "dataconnect", - `Detected ${cwdPlatformGuess} app in current directory ${process.cwd()}`, - ); + logSuccess(`Detected ${cwdPlatformGuess} app in current directory ${process.cwd()}`); targetPlatform = cwdPlatformGuess; appDir = process.cwd(); } else { // If we aren't, ask the user where their app is, and try to autodetect from there - logLabeledBullet("dataconnect", `Couldn't automatically detect your app directory.`); - appDir = config.path( - await promptOnce({ - message: "Where is your app directory?", - }), - ); + logBullet(`Couldn't automatically detect your app directory.`); + appDir = await promptForDirectory({ + config, + message: "Where is your app directory?", + }); const platformGuess = await getPlatformFromFolder(appDir); if (platformGuess !== Platform.UNDETERMINED) { - logLabeledSuccess("dataconnect", `Detected ${platformGuess} app in directory ${appDir}`); + logSuccess(`Detected ${platformGuess} app in directory ${appDir}`); targetPlatform = platformGuess; } else { // If we still can't autodetect, just ask the user - logLabeledBullet("dataconnect", "Couldn't automatically detect your app's platform."); + logBullet("Couldn't automatically detect your app's platform."); targetPlatform = await promptOnce({ message: "Which platform do you want to set up a generated SDK for?", type: "list", @@ -172,18 +167,26 @@ async function askQuestions(setup: Setup, config: Config): Promise { ); // TODO: Prompt user about adding generated paths to .gitignore const connectorYamlContents = yaml.stringify(newConnectorYaml); + connectorInfo.connectorYaml = newConnectorYaml; return { connectorYamlContents, connectorInfo, shouldGenerate }; } export async function actuate(sdkInfo: SDKInfo, projectId?: string) { const connectorYamlPath = `${sdkInfo.connectorInfo.directory}/connector.yaml`; fs.writeFileSync(connectorYamlPath, sdkInfo.connectorYamlContents, "utf8"); - logger.info(`Wrote new config to ${connectorYamlPath}`); + logBullet(`Wrote new config to ${connectorYamlPath}`); if (projectId && sdkInfo.shouldGenerate) { await DataConnectEmulator.generate({ configDir: sdkInfo.connectorInfo.directory, connectorId: sdkInfo.connectorInfo.connectorYaml.connectorId, }); - logger.info(`Generated SDK code for ${sdkInfo.connectorInfo.connectorYaml.connectorId}`); + logBullet(`Generated SDK code for ${sdkInfo.connectorInfo.connectorYaml.connectorId}`); + } + if (sdkInfo.connectorInfo.connectorYaml.generate?.swiftSdk) { + logBullet( + clc.bold( + "Please follow the instructions here to add your generated sdk to your XCode project:\n\thttps://firebase.google.com/docs/data-connect/gp/ios-sdk#set-client", + ), + ); } } diff --git a/src/prompt.ts b/src/prompt.ts index a6b18e59d17..73a91fc9c33 100644 --- a/src/prompt.ts +++ b/src/prompt.ts @@ -1,7 +1,10 @@ import * as inquirer from "inquirer"; import AutocompletePrompt from "inquirer-autocomplete-prompt"; +import { fileExistsSync, dirExistsSync } from "./fsutils"; import { FirebaseError } from "./error"; +import { Config } from "./config"; +import { logger } from "./logger"; declare module "inquirer" { interface QuestionMap { @@ -131,3 +134,32 @@ export async function confirm(args: { return true; } } + +/** + * Prompts for a directory name, and reprompts if that path does not exist + */ +export async function promptForDirectory(args: { + message: string; + config: Config; + default?: boolean; + relativeTo?: string; +}): Promise { + let dir: string = ""; + while (!dir) { + const target = args.config.path( + await promptOnce({ + message: "Where is your app directory?", + }), + ); + if (fileExistsSync(target)) { + logger.error( + `Expected a directory, but ${target} is a file. Please provide a path to a directory.`, + ); + } else if (!dirExistsSync(target)) { + logger.error(`Directory ${target} not found. Please provide a path to a directory`); + } else { + dir = target; + } + } + return dir; +} From 5cdd938af93c36f00b5b809be34885b894e1d3cd Mon Sep 17 00:00:00 2001 From: Joe Hanley Date: Fri, 2 Aug 2024 13:34:16 -0700 Subject: [PATCH 5/6] Adding CHANGELOG --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 75fc8270001..ddf954d471e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1 +1,2 @@ -- Fixes bug where `esbuild` execution was throwing an error saying "Command line too long" on Windows (https://github.com/firebase/firebase-tools/issues/7250 and https://github.com/firebase/firebase-tools/issues/6193). +- Fixed bug where `esbuild` execution was throwing an error saying "Command line too long" on Windows (#7250, #6193). +- Automatically detect app platform during `init dataconnect:sdk`. From 382d03f7c9da0819d86f96ef97d9d015cc69c554 Mon Sep 17 00:00:00 2001 From: Joe Hanley Date: Tue, 6 Aug 2024 10:07:36 -0700 Subject: [PATCH 6/6] pr fixes --- src/init/features/dataconnect/sdk.spec.ts | 1 + src/init/features/dataconnect/sdk.ts | 24 +++++++++++++++-------- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/init/features/dataconnect/sdk.spec.ts b/src/init/features/dataconnect/sdk.spec.ts index 9a2082d628e..0fdd9a2ffc9 100644 --- a/src/init/features/dataconnect/sdk.spec.ts +++ b/src/init/features/dataconnect/sdk.spec.ts @@ -75,5 +75,6 @@ function mockSDKInfo(shouldGenerate: boolean): sdk.SDKInfo { }, }, shouldGenerate, + displayIOSWarning: false, }; } diff --git a/src/init/features/dataconnect/sdk.ts b/src/init/features/dataconnect/sdk.ts index f5b523a1954..615d27d4e5c 100644 --- a/src/init/features/dataconnect/sdk.ts +++ b/src/init/features/dataconnect/sdk.ts @@ -28,6 +28,7 @@ export type SDKInfo = { connectorYamlContents: string; connectorInfo: ConnectorInfo; shouldGenerate: boolean; + displayIOSWarning: boolean; }; export async function doSetup(setup: Setup, config: Config): Promise { const sdkInfo = await askQuestions(setup, config); @@ -36,6 +37,7 @@ export async function doSetup(setup: Setup, config: Config): Promise { async function askQuestions(setup: Setup, config: Config): Promise { const serviceCfgs = readFirebaseJson(config); + // TODO: This current approach removes comments from YAML files. Consider a different approach that won't. const serviceInfos = await Promise.all( serviceCfgs.map((c) => load(setup.projectId || "", config, c.source)), ); @@ -91,7 +93,7 @@ async function askQuestions(setup: Setup, config: Config): Promise { choices: [ { name: "iOS (Swift)", value: Platform.IOS }, { name: "Web (JavaScript)", value: Platform.WEB }, - { name: "Androd (Kotlin)", value: Platform.ANDROID }, + { name: "Android (Kotlin)", value: Platform.ANDROID }, ], }); } @@ -102,6 +104,7 @@ async function askQuestions(setup: Setup, config: Config): Promise { newConnectorYaml.generate = {}; } + let displayIOSWarning = false; if (targetPlatform === Platform.IOS) { const outputDir = newConnectorYaml.generate.swiftSdk?.outputDir || @@ -109,9 +112,11 @@ async function askQuestions(setup: Setup, config: Config): Promise { connectorInfo.directory, path.join(appDir, `generated/${newConnectorYaml.connectorId}`), ); - const pkg = camelCase(newConnectorYaml.connectorId); + const pkg = + newConnectorYaml.generate.swiftSdk?.package ?? camelCase(newConnectorYaml.connectorId); const swiftSdk = { outputDir, package: pkg }; newConnectorYaml.generate.swiftSdk = swiftSdk; + displayIOSWarning = true; } if (targetPlatform === Platform.WEB) { @@ -142,12 +147,15 @@ async function askQuestions(setup: Setup, config: Config): Promise { } if (targetPlatform === Platform.ANDROID) { + // app/src/main is a common practice for Andorid, but not explicitly required. + // If it is present, we'll use it. Otherwise, we fall back to the app directory. + const baseDir = fs.existsSync(path.join(appDir, "app/src/main")) + ? path.join(appDir, "app/src/main") + : appDir; + const outputDir = newConnectorYaml.generate.kotlinSdk?.outputDir || - path.relative( - connectorInfo.directory, - path.join(appDir, `generated/${newConnectorYaml.connectorId}`), - ); + path.relative(connectorInfo.directory, path.join(baseDir, `generated`)); const pkg = newConnectorYaml.generate.kotlinSdk?.package ?? `connectors.${snakeCase(connectorInfo.connectorYaml.connectorId)}`; @@ -168,7 +176,7 @@ async function askQuestions(setup: Setup, config: Config): Promise { // TODO: Prompt user about adding generated paths to .gitignore const connectorYamlContents = yaml.stringify(newConnectorYaml); connectorInfo.connectorYaml = newConnectorYaml; - return { connectorYamlContents, connectorInfo, shouldGenerate }; + return { connectorYamlContents, connectorInfo, shouldGenerate, displayIOSWarning }; } export async function actuate(sdkInfo: SDKInfo, projectId?: string) { @@ -182,7 +190,7 @@ export async function actuate(sdkInfo: SDKInfo, projectId?: string) { }); logBullet(`Generated SDK code for ${sdkInfo.connectorInfo.connectorYaml.connectorId}`); } - if (sdkInfo.connectorInfo.connectorYaml.generate?.swiftSdk) { + if (sdkInfo.connectorInfo.connectorYaml.generate?.swiftSdk && sdkInfo.displayIOSWarning) { logBullet( clc.bold( "Please follow the instructions here to add your generated sdk to your XCode project:\n\thttps://firebase.google.com/docs/data-connect/gp/ios-sdk#set-client",