Skip to content

Commit

Permalink
Added react code generation
Browse files Browse the repository at this point in the history
  • Loading branch information
maneesht committed Jan 30, 2025
1 parent 58c383c commit 4819ebc
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 21 deletions.
2 changes: 1 addition & 1 deletion firebase-vscode/src/data-connect/sdk-generation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ export function registerFdcSdkGeneration(
vscode.commands.executeCommand("fdc.init-sdk", { appFolder });
} else {
// generate yaml
const newConnectorYaml = generateSdkYaml(
const newConnectorYaml = await generateSdkYaml(
platform,
connectorYaml,
connectorYamlFolderPath,
Expand Down
58 changes: 45 additions & 13 deletions src/dataconnect/fileUtils.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as mockfs from "mock-fs";

import { expect } from "chai";
import { getPlatformFromFolder } from "./fileUtils";
import { getPlatformFromFolder, SUPPORTED_FRAMEWORKS } from "./fileUtils";
import { generateSdkYaml } from "../init/features/dataconnect/sdk";
import { ConnectorYaml, Platform } from "./types";
import FileSystem from "mock-fs/lib/filesystem";
Expand Down Expand Up @@ -192,9 +192,9 @@ describe("generateSdkYaml", () => {
},
];
for (const c of cases) {
it(c.desc, () => {
it(c.desc, async () => {
mockfs({ [appFolderDetectable]: { ["package.json"]: "{}" } });
const modifiedYaml = generateSdkYaml(
const modifiedYaml = await generateSdkYaml(
Platform.WEB,
sampleConnectorYaml,
connectorYamlFolder,
Expand All @@ -203,6 +203,38 @@ describe("generateSdkYaml", () => {
expect(modifiedYaml.generate?.javascriptSdk).to.deep.equal(c.output);
});
}
for (const f of SUPPORTED_FRAMEWORKS) {
const cases = [
{
desc: `can detect a ${f}`,
depName: f,
detect: true,
},
{
desc: `can detect not ${f}`,
depName: `not-${f}`,
detect: false,
},
];
for (const c of cases) {
it(c.desc, async () => {
mockfs({
[appFolderDetectable]: { ["package.json"]: `{"dependencies": {"${c.depName}": "1"}}` },
});
const modifiedYaml = await generateSdkYaml(
Platform.WEB,
sampleConnectorYaml,
connectorYamlFolder,
appFolderDetectable,
);
if (c.detect) {
expect(modifiedYaml.generate?.javascriptSdk![f]).to.equal(true);
} else {
expect(modifiedYaml.generate?.javascriptSdk![f]).to.not.equal(true);
}
});
}
}
});

describe("IOS platform should add Swift SDK Generation", () => {
Expand Down Expand Up @@ -237,8 +269,8 @@ describe("generateSdkYaml", () => {
},
];
for (const c of cases) {
it(c.desc, () => {
const modifiedYaml = generateSdkYaml(
it(c.desc, async () => {
const modifiedYaml = await generateSdkYaml(
Platform.IOS,
sampleConnectorYaml,
connectorYamlFolder,
Expand Down Expand Up @@ -308,14 +340,14 @@ describe("generateSdkYaml", () => {
},
];
for (const c of cases) {
it(c.desc, () => {
it(c.desc, async () => {
mockfs({
[appFolderHasJava + "/app/src/main/java"]: {},
[appFolderHasKotlin + "/app/src/main/kotlin"]: {},
[appFolderHasBoth + "/app/src/main/java"]: {},
[appFolderHasBoth + "/app/src/main/kotlin"]: {},
});
const modifiedYaml = generateSdkYaml(
const modifiedYaml = await generateSdkYaml(
Platform.ANDROID,
sampleConnectorYaml,
connectorYamlFolder,
Expand Down Expand Up @@ -358,8 +390,8 @@ describe("generateSdkYaml", () => {
},
];
for (const c of cases) {
it(c.desc, () => {
const modifiedYaml = generateSdkYaml(
it(c.desc, async () => {
const modifiedYaml = await generateSdkYaml(
Platform.FLUTTER,
sampleConnectorYaml,
connectorYamlFolder,
Expand All @@ -370,9 +402,9 @@ describe("generateSdkYaml", () => {
}
});

it("should create generate object if it doesn't exist", () => {
it("should create generate object if it doesn't exist", async () => {
const yamlWithoutGenerate: ConnectorYaml = { connectorId: "default-connector" };
const modifiedYaml = generateSdkYaml(
const modifiedYaml = await generateSdkYaml(
Platform.WEB,
yamlWithoutGenerate,
connectorYamlFolder,
Expand All @@ -381,9 +413,9 @@ describe("generateSdkYaml", () => {
expect(modifiedYaml.generate).to.exist;
});

it("should not modify yaml for unknown platforms", () => {
it("should not modify yaml for unknown platforms", async () => {
const unknownPlatform = "unknown" as Platform; // Type assertion for test
const modifiedYaml = generateSdkYaml(
const modifiedYaml = await generateSdkYaml(
unknownPlatform,
sampleConnectorYaml,
connectorYamlFolder,
Expand Down
55 changes: 54 additions & 1 deletion src/dataconnect/fileUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,19 @@ import * as fs from "fs-extra";
import * as path from "path";

import { FirebaseError } from "../error";
import { ConnectorYaml, DataConnectYaml, File, Platform, ServiceInfo } from "./types";
import {
ConnectorYaml,
DataConnectYaml,
File,
Platform,
ServiceInfo,
SupportedFrameworks,
} from "./types";
import { readFileFromDirectory, wrappedSafeLoad } from "../utils";
import { Config } from "../config";
import { DataConnectMultiple } from "../firebaseConfig";
import { load } from "./load";
import { PackageJSON } from "../frameworks/compose/discover/runtime/node";

export function readFirebaseJson(config?: Config): DataConnectMultiple {
if (!config?.has("dataconnect")) {
Expand Down Expand Up @@ -152,3 +160,48 @@ export async function getPlatformFromFolder(dirPath: string) {
// because we found indicators for multiple platforms.
return Platform.MULTIPLE;
}

export async function resolvePackageJson(
packageJsonPath: string,
): Promise<PackageJSON | undefined> {
let validPackageJsonPath = packageJsonPath;
if (!packageJsonPath.endsWith("package.json")) {
validPackageJsonPath = path.join(packageJsonPath, "package.json");
}
validPackageJsonPath = path.resolve(validPackageJsonPath);
try {
return JSON.parse((await fs.readFile(validPackageJsonPath)).toString());
} catch {
return undefined;
}
}

export const SUPPORTED_FRAMEWORKS: (keyof SupportedFrameworks)[] = ["react"];
function lookForFramework(
key: "dependencies" | "devDependencies",
packageJson: PackageJSON,
frameworksUsed: (keyof SupportedFrameworks)[],
) {
if (!packageJson[key]) {
return frameworksUsed;
}
Object.keys(packageJson[key]).forEach((dep) => {
if (
SUPPORTED_FRAMEWORKS.includes(dep as keyof SupportedFrameworks) &&
!frameworksUsed.includes(dep as keyof SupportedFrameworks)
) {
frameworksUsed.push(dep as keyof SupportedFrameworks);
}
});
return frameworksUsed;
}
export function getFrameworksFromPackageJson(
packageJson: PackageJSON,
): (keyof SupportedFrameworks)[] {
const frameworksUsed: (keyof SupportedFrameworks)[] = lookForFramework(
"dependencies",
packageJson,
[],
);
return lookForFramework("devDependencies", packageJson, frameworksUsed);
}
6 changes: 5 additions & 1 deletion src/dataconnect/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,11 @@ export interface Generate {
dartSdk?: DartSDK;
}

export interface JavascriptSDK {
export interface SupportedFrameworks {
react?: boolean;
}

export interface JavascriptSDK extends SupportedFrameworks {
outputDir: string;
package: string;
packageJsonDir?: string;
Expand Down
42 changes: 37 additions & 5 deletions src/init/features/dataconnect/sdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@ import * as path from "path";

import { dirExistsSync } from "../../../fsutils";
import { promptForDirectory, promptOnce } from "../../../prompt";
import { readFirebaseJson, getPlatformFromFolder } from "../../../dataconnect/fileUtils";
import {
readFirebaseJson,
getPlatformFromFolder,
getFrameworksFromPackageJson,
resolvePackageJson,
} from "../../../dataconnect/fileUtils";
import { Config } from "../../../config";
import { Setup } from "../..";
import { load } from "../../../dataconnect/load";
Expand Down Expand Up @@ -101,7 +106,7 @@ async function askQuestions(setup: Setup, config: Config): Promise<SDKInfo> {
});

const connectorYaml = JSON.parse(JSON.stringify(connectorInfo.connectorYaml)) as ConnectorYaml;
const newConnectorYaml = generateSdkYaml(
const newConnectorYaml = await generateSdkYaml(
targetPlatform,
connectorYaml,
connectorInfo.directory,
Expand All @@ -115,12 +120,12 @@ async function askQuestions(setup: Setup, config: Config): Promise<SDKInfo> {
return { connectorYamlContents, connectorInfo, displayIOSWarning };
}

export function generateSdkYaml(
export async function generateSdkYaml(
targetPlatform: Platform,
connectorYaml: ConnectorYaml,
connectorDir: string,
appDir: string,
): ConnectorYaml {
): Promise<ConnectorYaml> {
if (!connectorYaml.generate) {
connectorYaml.generate = {};
}
Expand All @@ -135,14 +140,41 @@ export function generateSdkYaml(

if (targetPlatform === Platform.WEB) {
const pkg = `${connectorYaml.connectorId}-connector`;
const packageJsonDir = path.relative(connectorDir, appDir);
const javascriptSdk: JavascriptSDK = {
outputDir: path.relative(connectorDir, path.join(appDir, `dataconnect-generated/js/${pkg}`)),
package: `@firebasegen/${pkg}`,
// If appDir has package.json, Emulator would add Generated JS SDK to `package.json`.
// Otherwise, emulator would ignore it. Always add it here in case `package.json` is added later.
// TODO: Explore other platforms that can be automatically installed. Dart? Android?
packageJsonDir: path.relative(connectorDir, appDir),
packageJsonDir,
};
const packageJson = await resolvePackageJson(appDir);
if (packageJson) {
const frameworksUsed = getFrameworksFromPackageJson(packageJson);
frameworksUsed.forEach((framework) => {
javascriptSdk[framework] = true;
});
}
// const unusedFrameworks = SUPPORTED_FRAMEWORKS.filter(framework => !frameworksUsed.includes(framework));
// if (unusedFrameworks.length > 0 && setup) {
// const additionalFrameworks: { features: (keyof SupportedFrameworks)[] } = await prompt(
// setup,
// [
// {
// type: "checkbox",
// name: "features",
// message:
// "Which framework would you like to generate SDKs for? " +
// "Press Space to select features, then Enter to confirm your choices.",
// choices: unusedFrameworks,
// },
// ],
// );
// additionalFrameworks.features.forEach((framework) => {
// javascriptSdk[framework] = true;
// });
// }
connectorYaml.generate.javascriptSdk = javascriptSdk;
}

Expand Down

0 comments on commit 4819ebc

Please sign in to comment.