1
+ import * as fs from "fs-extra" ;
1
2
import * as path from "path" ;
3
+ import { glob } from "glob" ;
2
4
import { Framework , Platform } from "./types" ;
3
- import {
4
- detectApps as appUtilsDetectApps ,
5
- getPlatformsFromFolder ,
6
- Platform as AppUtilsPlatform ,
7
- Framework as AppUtilsFramework ,
8
- App as AppUtilsApp ,
9
- } from "../appUtils" ;
5
+ import { PackageJSON } from "../frameworks/compose/discover/runtime/node" ;
10
6
11
7
export interface App {
12
8
platform : Platform ;
@@ -21,61 +17,96 @@ export function appDescription(a: App): string {
21
17
22
18
/** Given a directory, determine the platform type */
23
19
export async function getPlatformFromFolder ( dirPath : string ) : Promise < Platform > {
24
- const platforms = await getPlatformsFromFolder ( dirPath ) ;
25
-
26
- if ( platforms . length === 0 ) {
20
+ const apps = await detectApps ( dirPath ) ;
21
+ const hasWeb = apps . some ( ( app ) => app . platform === Platform . WEB ) ;
22
+ const hasAndroid = apps . some ( ( app ) => app . platform === Platform . ANDROID ) ;
23
+ const hasIOS = apps . some ( ( app ) => app . platform === Platform . IOS ) ;
24
+ const hasDart = apps . some ( ( app ) => app . platform === Platform . FLUTTER ) ;
25
+ if ( ! hasWeb && ! hasAndroid && ! hasIOS && ! hasDart ) {
27
26
return Platform . NONE ;
27
+ } else if ( hasWeb && ! hasAndroid && ! hasIOS && ! hasDart ) {
28
+ return Platform . WEB ;
29
+ } else if ( hasAndroid && ! hasWeb && ! hasIOS && ! hasDart ) {
30
+ return Platform . ANDROID ;
31
+ } else if ( hasIOS && ! hasWeb && ! hasAndroid && ! hasDart ) {
32
+ return Platform . IOS ;
33
+ } else if ( hasDart && ! hasWeb && ! hasIOS && ! hasAndroid ) {
34
+ return Platform . FLUTTER ;
28
35
}
29
-
30
- // Its not clear which platform the app directory is
36
+ // At this point, its not clear which platform the app directory is
31
37
// because we found indicators for multiple platforms.
32
- if ( platforms . length > 1 ) {
33
- return Platform . MULTIPLE ;
34
- }
35
-
36
- return toDataConnectPlatform ( platforms [ 0 ] ) ;
38
+ return Platform . MULTIPLE ;
37
39
}
38
40
39
41
/** Detects the apps in a given directory */
40
42
export async function detectApps ( dirPath : string ) : Promise < App [ ] > {
41
- return appUtilsDetectApps ( dirPath ) . then ( ( apps ) => apps . map ( toDataConnectApp ) ) ;
43
+ const packageJsonFiles = await detectFiles ( dirPath , "package.json" ) ;
44
+ const pubSpecYamlFiles = await detectFiles ( dirPath , "pubspec.yaml" ) ;
45
+ const srcMainFolders = await detectFiles ( dirPath , "src/main/" ) ;
46
+ const xCodeProjects = await detectFiles ( dirPath , "*.xcodeproj/" ) ;
47
+ const webApps = await Promise . all ( packageJsonFiles . map ( ( p ) => packageJsonToWebApp ( dirPath , p ) ) ) ;
48
+ const flutterApps = pubSpecYamlFiles . map ( ( f ) => ( {
49
+ platform : Platform . FLUTTER ,
50
+ directory : path . dirname ( f ) ,
51
+ } ) ) ;
52
+ const androidApps = srcMainFolders
53
+ . map ( ( f ) => ( {
54
+ platform : Platform . ANDROID ,
55
+ directory : path . dirname ( path . dirname ( f ) ) ,
56
+ } ) )
57
+ . filter ( ( a ) => ! flutterApps . some ( ( f ) => isPathInside ( f . directory , a . directory ) ) ) ;
58
+ const iosApps = xCodeProjects
59
+ . map ( ( f ) => ( {
60
+ platform : Platform . IOS ,
61
+ directory : path . dirname ( f ) ,
62
+ } ) )
63
+ . filter ( ( a ) => ! flutterApps . some ( ( f ) => isPathInside ( f . directory , a . directory ) ) ) ;
64
+ return [ ...webApps , ...flutterApps , ...androidApps , ...iosApps ] ;
42
65
}
43
66
44
67
export function isPathInside ( parent : string , child : string ) : boolean {
45
68
const relativePath = path . relative ( parent , child ) ;
46
69
return ! relativePath . startsWith ( `..` ) ;
47
70
}
48
71
49
- function toDataConnectPlatform ( platform : AppUtilsPlatform ) : Platform {
50
- switch ( platform ) {
51
- case AppUtilsPlatform . IOS :
52
- return Platform . IOS ;
53
- case AppUtilsPlatform . ANDROID :
54
- return Platform . ANDROID ;
55
- case AppUtilsPlatform . FLUTTER :
56
- return Platform . FLUTTER ;
57
- case AppUtilsPlatform . WEB :
58
- return Platform . WEB ;
59
- }
72
+ async function packageJsonToWebApp ( dirPath : string , packageJsonFile : string ) : Promise < App > {
73
+ const fullPath = path . join ( dirPath , packageJsonFile ) ;
74
+ const packageJson = JSON . parse ( ( await fs . readFile ( fullPath ) ) . toString ( ) ) ;
75
+ return {
76
+ platform : Platform . WEB ,
77
+ directory : path . dirname ( packageJsonFile ) ,
78
+ frameworks : getFrameworksFromPackageJson ( packageJson ) ,
79
+ } ;
60
80
}
61
81
62
- function toDataConnectFramework ( framework : AppUtilsFramework ) : Framework {
63
- switch ( framework ) {
64
- case AppUtilsFramework . ANGULAR :
65
- return "angular" ;
66
- case AppUtilsFramework . REACT :
67
- return "react" ;
68
- }
82
+ export const WEB_FRAMEWORKS : Framework [ ] = [ "react" , "angular" ] ;
83
+ export const WEB_FRAMEWORKS_SIGNALS : { [ key in Framework ] : string [ ] } = {
84
+ react : [ "react" , "next" ] ,
85
+ angular : [ "@angular/core" ] ,
86
+ } ;
87
+
88
+ export function getFrameworksFromPackageJson ( packageJson : PackageJSON ) : Framework [ ] {
89
+ const devDependencies = Object . keys ( packageJson . devDependencies ?? { } ) ;
90
+ const dependencies = Object . keys ( packageJson . dependencies ?? { } ) ;
91
+ const allDeps = Array . from ( new Set ( [ ...devDependencies , ...dependencies ] ) ) ;
92
+ return WEB_FRAMEWORKS . filter ( ( framework ) =>
93
+ WEB_FRAMEWORKS_SIGNALS [ framework ] ! . find ( ( dep ) => allDeps . includes ( dep ) ) ,
94
+ ) ;
69
95
}
70
96
71
- function toDataConnectApp ( app : AppUtilsApp ) : App {
72
- const output : App = {
73
- platform : toDataConnectPlatform ( app . platform ) ,
74
- directory : app . directory ,
97
+ async function detectFiles ( dirPath : string , filePattern : string ) : Promise < string [ ] > {
98
+ const options = {
99
+ cwd : dirPath ,
100
+ ignore : [
101
+ "**/dataconnect*/**" ,
102
+ "**/node_modules/**" , // Standard dependency directory
103
+ "**/dist/**" , // Common build output
104
+ "**/build/**" , // Common build output
105
+ "**/out/**" , // Another common build output
106
+ "**/.next/**" , // Next.js build directory
107
+ "**/coverage/**" , // Test coverage reports
108
+ ] ,
109
+ absolute : false ,
75
110
} ;
76
-
77
- if ( app . frameworks ) {
78
- output . frameworks = app . frameworks . map ( ( framework ) => toDataConnectFramework ( framework ) ) ;
79
- }
80
- return output ;
111
+ return glob ( `**/${ filePattern } ` , options ) ;
81
112
}
0 commit comments