Skip to content

Commit ebb525f

Browse files
authored
Added admin app detection for fdc (#9360)
1 parent 22bec04 commit ebb525f

File tree

7 files changed

+172
-12
lines changed

7 files changed

+172
-12
lines changed

schema/connector-yaml.json

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,24 @@
22
"$schema": "http://json-schema.org/draft-07/schema#",
33
"additionalProperties": false,
44
"definitions": {
5+
"adminNodeSdk": {
6+
"additionalProperties": true,
7+
"type": "object",
8+
"properties": {
9+
"outputDir": {
10+
"type": "string",
11+
"description": "Path to the directory where generated files should be written to."
12+
},
13+
"package": {
14+
"type": "string",
15+
"description": "The package name to use for the generated code."
16+
},
17+
"packageJSONDir": {
18+
"type": "string",
19+
"description": "The directory containing the package.json to install the generated package in."
20+
}
21+
}
22+
},
523
"javascriptSdk": {
624
"additionalProperties": true,
725
"type": "object",
@@ -90,6 +108,18 @@
90108
],
91109
"description": "Configuration for a generated Javascript SDK"
92110
},
111+
"adminNodeSdk": {
112+
"oneOf": [
113+
{ "$ref": "#/definitions/adminNodeSdk" },
114+
{
115+
"type": "array",
116+
"items": {
117+
"$ref": "#/definitions/adminNodeSdk"
118+
}
119+
}
120+
],
121+
"description": "Configuration for a generated Admin Node SDK"
122+
},
93123
"dartSdk": {
94124
"oneOf": [
95125
{ "$ref": "#/definitions/dartSdk" },

src/appUtils.spec.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,69 @@ describe("appUtils", () => {
620620
]);
621621
});
622622

623+
it("should detect an admin app with firebase-admin dependency", async () => {
624+
mockfs({
625+
[testDir]: {
626+
"package.json": JSON.stringify({
627+
dependencies: {
628+
"firebase-admin": "1.0.0",
629+
},
630+
}),
631+
},
632+
});
633+
const apps = cleanUndefinedFields(await detectApps(testDir));
634+
expect(apps).to.have.deep.members([
635+
{
636+
platform: Platform.ADMIN_NODE,
637+
directory: ".",
638+
},
639+
]);
640+
});
641+
642+
it("should detect an admin app with firebase-functions dependency", async () => {
643+
mockfs({
644+
[testDir]: {
645+
"package.json": JSON.stringify({
646+
dependencies: {
647+
"firebase-functions": "1.0.0",
648+
},
649+
}),
650+
},
651+
});
652+
const apps = cleanUndefinedFields(await detectApps(testDir));
653+
expect(apps).to.have.deep.members([
654+
{
655+
platform: Platform.ADMIN_NODE,
656+
directory: ".",
657+
},
658+
]);
659+
});
660+
661+
it("should detect an admin and client app", async () => {
662+
mockfs({
663+
[testDir]: {
664+
"package.json": JSON.stringify({
665+
dependencies: {
666+
"firebase-admin": "1.0.0",
667+
firebase: "1.0.0",
668+
},
669+
}),
670+
},
671+
});
672+
const apps = cleanUndefinedFields(await detectApps(testDir));
673+
expect(apps).to.have.deep.members([
674+
{
675+
platform: Platform.ADMIN_NODE,
676+
directory: ".",
677+
},
678+
{
679+
platform: Platform.WEB,
680+
directory: ".",
681+
frameworks: [],
682+
},
683+
]);
684+
});
685+
623686
it("should detect angular web framework", async () => {
624687
mockfs({
625688
[testDir]: {

src/appUtils.ts

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export enum Platform {
1111
WEB = "WEB",
1212
IOS = "IOS",
1313
FLUTTER = "FLUTTER",
14+
ADMIN_NODE = "ADMIN_NODE",
1415
}
1516

1617
/**
@@ -62,7 +63,11 @@ export async function detectApps(dirPath: string): Promise<App[]> {
6263
const pubSpecYamlFiles = await detectFiles(dirPath, "pubspec.yaml");
6364
const srcMainFolders = await detectFiles(dirPath, "src/main/");
6465
const xCodeProjects = await detectFiles(dirPath, "*.xcodeproj/");
65-
const webApps = await Promise.all(packageJsonFiles.map((p) => packageJsonToWebApp(dirPath, p)));
66+
const adminAndWebApps = (
67+
await Promise.all(packageJsonFiles.map((p) => packageJsonToAdminOrWebApp(dirPath, p)))
68+
).flat();
69+
console.log("packageJsonFiles", packageJsonFiles);
70+
console.log("adminAndWebApps", adminAndWebApps);
6671

6772
const flutterAppPromises = await Promise.all(
6873
pubSpecYamlFiles.map((f) => processFlutterDir(dirPath, f)),
@@ -80,7 +85,7 @@ export async function detectApps(dirPath: string): Promise<App[]> {
8085
const iosApps = iosAppPromises
8186
.flat()
8287
.filter((a) => !flutterApps.some((f) => isPathInside(f.directory, a.directory)));
83-
return [...webApps, ...flutterApps, ...androidApps, ...iosApps];
88+
return [...flutterApps, ...androidApps, ...iosApps, ...adminAndWebApps];
8489
}
8590

8691
async function processIosDir(dirPath: string, filePath: string): Promise<App[]> {
@@ -164,14 +169,35 @@ function isPathInside(parent: string, child: string): boolean {
164169
return !relativePath.startsWith(`..`);
165170
}
166171

167-
async function packageJsonToWebApp(dirPath: string, packageJsonFile: string): Promise<App> {
172+
export function getAllDepsFromPackageJson(packageJson: PackageJSON) {
173+
const devDependencies = Object.keys(packageJson.devDependencies ?? {});
174+
const dependencies = Object.keys(packageJson.dependencies ?? {});
175+
const allDeps = Array.from(new Set([...devDependencies, ...dependencies]));
176+
return allDeps;
177+
}
178+
179+
async function packageJsonToAdminOrWebApp(
180+
dirPath: string,
181+
packageJsonFile: string,
182+
): Promise<App[]> {
168183
const fullPath = path.join(dirPath, packageJsonFile);
169184
const packageJson = JSON.parse((await fs.readFile(fullPath)).toString()) as PackageJSON;
170-
return {
171-
platform: Platform.WEB,
172-
directory: path.dirname(packageJsonFile),
173-
frameworks: getFrameworksFromPackageJson(packageJson),
174-
};
185+
const allDeps = getAllDepsFromPackageJson(packageJson);
186+
const detectedApps = [];
187+
if (allDeps.includes("firebase-admin") || allDeps.includes("firebase-functions")) {
188+
detectedApps.push({
189+
platform: Platform.ADMIN_NODE,
190+
directory: path.dirname(packageJsonFile),
191+
});
192+
}
193+
if (allDeps.includes("firebase") || detectedApps.length === 0) {
194+
detectedApps.push({
195+
platform: Platform.WEB,
196+
directory: path.dirname(packageJsonFile),
197+
frameworks: getFrameworksFromPackageJson(packageJson),
198+
});
199+
}
200+
return detectedApps;
175201
}
176202

177203
const WEB_FRAMEWORKS: Framework[] = Object.values(Framework);
@@ -215,9 +241,7 @@ async function detectAppIdsForPlatform(
215241
}
216242

217243
function getFrameworksFromPackageJson(packageJson: PackageJSON): Framework[] {
218-
const devDependencies = Object.keys(packageJson.devDependencies ?? {});
219-
const dependencies = Object.keys(packageJson.dependencies ?? {});
220-
const allDeps = Array.from(new Set([...devDependencies, ...dependencies]));
244+
const allDeps = getAllDepsFromPackageJson(packageJson);
221245
return WEB_FRAMEWORKS.filter((framework) =>
222246
WEB_FRAMEWORKS_SIGNALS[framework].find((dep) => allDeps.includes(dep)),
223247
);

src/commands/dataconnect-sdk-generate.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,8 @@ async function loadAllWithSDKs(
9999
c.connectorYaml.generate?.javascriptSdk ||
100100
c.connectorYaml.generate?.kotlinSdk ||
101101
c.connectorYaml.generate?.swiftSdk ||
102-
c.connectorYaml.generate?.dartSdk
102+
c.connectorYaml.generate?.dartSdk ||
103+
c.connectorYaml.generate?.adminNodeSdk
103104
);
104105
}),
105106
);

src/dataconnect/types.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,13 +146,20 @@ export interface Generate {
146146
swiftSdk?: SwiftSDK | SwiftSDK[];
147147
kotlinSdk?: KotlinSDK | KotlinSDK[];
148148
dartSdk?: DartSDK | DartSDK[];
149+
adminNodeSdk?: AdminNodeSDK | AdminNodeSDK[];
149150
}
150151

151152
export interface SupportedFrameworks {
152153
react?: boolean;
153154
angular?: boolean;
154155
}
155156

157+
export interface AdminNodeSDK {
158+
outputDir: string;
159+
package: string;
160+
packageJsonDir?: string;
161+
}
162+
156163
export interface JavascriptSDK extends SupportedFrameworks {
157164
outputDir: string;
158165
package: string;

src/init/features/dataconnect/sdk.spec.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,18 @@ describe("addSdkGenerateToConnectorYaml", () => {
108108
},
109109
]);
110110
});
111+
112+
it("should add adminSdk for admin node platform", () => {
113+
app.platform = Platform.ADMIN_NODE;
114+
addSdkGenerateToConnectorYaml(connectorInfo, connectorYaml, app);
115+
expect(connectorYaml.generate?.adminNodeSdk).to.deep.equal([
116+
{
117+
outputDir: "../app/src/dataconnect-admin-generated",
118+
package: "@dataconnect/admin-generated",
119+
packageJsonDir: "../app",
120+
},
121+
]);
122+
});
111123
});
112124

113125
describe("chooseApp", () => {

src/init/features/dataconnect/sdk.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { Config } from "../../../config";
99
import { Setup } from "../..";
1010
import { loadAll } from "../../../dataconnect/load";
1111
import {
12+
AdminNodeSDK,
1213
ConnectorInfo,
1314
ConnectorYaml,
1415
DartSDK,
@@ -193,10 +194,14 @@ export function initAppCounters(info: SdkRequiredInfo): { [key: string]: number
193194
num_android_apps: 0,
194195
num_ios_apps: 0,
195196
num_flutter_apps: 0,
197+
num_admin_node_apps: 0,
196198
};
197199

198200
for (const app of info.apps ?? []) {
199201
switch (app.platform) {
202+
case Platform.ADMIN_NODE:
203+
counts.num_admin_node_apps++;
204+
break;
200205
case Platform.WEB:
201206
counts.num_web_apps++;
202207
break;
@@ -350,6 +355,24 @@ export function addSdkGenerateToConnectorYaml(
350355
const generate = connectorYaml.generate;
351356

352357
switch (app.platform) {
358+
case Platform.ADMIN_NODE: {
359+
const adminNodeSdk: AdminNodeSDK = {
360+
outputDir: path.relative(
361+
connectorDir,
362+
path.join(appDir, `src/dataconnect-admin-generated`),
363+
),
364+
package: `@dataconnect/admin-generated`,
365+
packageJsonDir: path.relative(connectorDir, appDir),
366+
};
367+
if (!isArray(generate?.adminNodeSdk)) {
368+
generate.adminNodeSdk = generate.adminNodeSdk ? [generate.adminNodeSdk] : [];
369+
}
370+
if (!generate.adminNodeSdk.some((s) => s.outputDir === adminNodeSdk.outputDir)) {
371+
generate.adminNodeSdk.push(adminNodeSdk);
372+
}
373+
break;
374+
}
375+
353376
case Platform.WEB: {
354377
const javascriptSdk: JavascriptSDK = {
355378
outputDir: path.relative(connectorDir, path.join(appDir, `src/dataconnect-generated`)),

0 commit comments

Comments
 (0)