@@ -52,6 +52,12 @@ func (FileDetector) Detect(dir string) (*DetectResult, error) {
5252 if result := detectJava (dir ); result != nil {
5353 return result , nil
5454 }
55+ if result := detectSwift (dir ); result != nil {
56+ return result , nil
57+ }
58+ if result := detectDotnet (dir ); result != nil {
59+ return result , nil
60+ }
5561 return nil , errors .New ("could not detect project language from directory; try specifying --sdk-id manually" )
5662}
5763
@@ -93,54 +99,55 @@ func detectNode(dir string) *DetectResult {
9399 }
94100 }
95101
96- if _ , ok := allDeps ["react" ]; ok {
102+ if _ , ok := allDeps ["react-native " ]; ok {
97103 return & DetectResult {
98104 Language : "JavaScript" ,
99- Framework : "React" ,
105+ Framework : "React Native " ,
100106 PackageManager : pm ,
101- SDKID : "react-client-sdk " ,
107+ SDKID : "react-native " ,
102108 EntryPoint : filepath .Join (dir , firstExistingIn (dir , []string {
103109 "src/App.tsx" , "src/App.jsx" , "src/App.js" ,
104110 "src/index.tsx" , "src/index.jsx" , "src/index.js" ,
105111 "index.js" ,
106112 })),
107113 }
108114 }
109- if _ , ok := allDeps ["react-native " ]; ok {
115+ if _ , ok := allDeps ["react" ]; ok {
110116 return & DetectResult {
111117 Language : "JavaScript" ,
112- Framework : "React Native " ,
118+ Framework : "React" ,
113119 PackageManager : pm ,
114- SDKID : "react-native- client-sdk" ,
120+ SDKID : "react-client-sdk" ,
115121 EntryPoint : filepath .Join (dir , firstExistingIn (dir , []string {
116122 "src/App.tsx" , "src/App.jsx" , "src/App.js" ,
117123 "src/index.tsx" , "src/index.jsx" , "src/index.js" ,
118124 "index.js" ,
119125 })),
120126 }
121127 }
122- jsClientFrameworks := map [string ]string {
123- "backbone" : "Backbone" ,
124- "svelte" : "Svelte" ,
125- "vue" : "Vue" ,
126- "@angular/core" : "Angular" ,
127- "ember-source" : "Ember" ,
128- }
129- for dep , framework := range jsClientFrameworks {
130- if _ , ok := allDeps [dep ]; ok {
131- return & DetectResult {
132- Language : "JavaScript" ,
133- Framework : framework ,
134- PackageManager : pm ,
135- SDKID : "js-client-sdk" ,
136- EntryPoint : filepath .Join (dir , firstExistingIn (dir , []string {
137- "src/App.tsx" , "src/App.jsx" , "src/App.js" ,
138- "src/index.tsx" , "src/index.jsx" , "src/index.js" ,
139- "src/main.ts" , "src/main.js" ,"index.js" ,
140- })),
141- }
142- }
143- }
128+ jsClientFrameworks := []struct { dep , framework string }{
129+ {"backbone" , "Backbone" },
130+ {"svelte" , "Svelte" },
131+ {"vue" , "Vue" },
132+ {"@angular/core" , "Angular" },
133+ {"ember-source" , "Ember" },
134+ {"preact" , "Preact" },
135+ }
136+ for _ , fw := range jsClientFrameworks {
137+ if _ , ok := allDeps [fw .dep ]; ok {
138+ return & DetectResult {
139+ Language : "JavaScript" ,
140+ Framework : fw .framework ,
141+ PackageManager : pm ,
142+ SDKID : "js-client-sdk" ,
143+ EntryPoint : filepath .Join (dir , firstExistingIn (dir , []string {
144+ "src/App.tsx" , "src/App.jsx" , "src/App.js" ,
145+ "src/index.tsx" , "src/index.jsx" , "src/index.js" ,
146+ "src/main.ts" , "src/main.js" , "index.js" ,
147+ })),
148+ }
149+ }
150+ }
144151
145152
146153 return & DetectResult {
@@ -177,7 +184,7 @@ func detectGo(dir string) *DetectResult {
177184 Language : "Go" ,
178185 PackageManager : "go" ,
179186 SDKID : "go-server-sdk" ,
180- EntryPoint : filepath .Join (dir , firstExistingIn (dir , []string {"main.go" , "cmd/ main.go" })),
187+ EntryPoint : filepath .Join (dir , firstExistingIn (dir , []string {"cmd/ main.go" , "main.go" })),
181188 }
182189}
183190
@@ -189,7 +196,7 @@ func detectPython(dir string) *DetectResult {
189196 PackageManager : "pip" ,
190197 SDKID : "python-server-sdk" ,
191198 EntryPoint : filepath .Join (dir , firstExistingIn (dir , []string {
192- "main.py" , "app .py" , "manage .py" , "src/ main.py" ,
199+ "src/ main.py" , "manage .py" , "app .py" , "main.py" ,
193200 })),
194201 }
195202 }
@@ -204,6 +211,20 @@ func detectJava(dir string) *DetectResult {
204211 if indicator == "pom.xml" {
205212 pm = "mvn"
206213 }
214+ // Android projects use Gradle but are distinguished by AndroidManifest.xml.
215+ for _ , manifest := range []string {
216+ "app/src/main/AndroidManifest.xml" ,
217+ "src/main/AndroidManifest.xml" ,
218+ } {
219+ if _ , err := os .Stat (filepath .Join (dir , manifest )); err == nil {
220+ return & DetectResult {
221+ Language : "Java" ,
222+ PackageManager : "gradle" ,
223+ SDKID : "android-client-sdk" ,
224+ EntryPoint : filepath .Join (dir , "app/src/main/java/MainActivity.java" ),
225+ }
226+ }
227+ }
207228 return & DetectResult {
208229 Language : "Java" ,
209230 PackageManager : pm ,
@@ -215,6 +236,78 @@ func detectJava(dir string) *DetectResult {
215236 return nil
216237}
217238
239+ func detectSwift (dir string ) * DetectResult {
240+ pm := "spm"
241+ if _ , err := os .Stat (filepath .Join (dir , "Podfile" )); err == nil {
242+ pm = "cocoapods"
243+ }
244+ indicators := []string {"Package.swift" , "Podfile" }
245+ for _ , f := range indicators {
246+ if _ , err := os .Stat (filepath .Join (dir , f )); err == nil {
247+ return & DetectResult {
248+ Language : "Swift" ,
249+ PackageManager : pm ,
250+ SDKID : "swift-client-sdk" ,
251+ EntryPoint : filepath .Join (dir , firstExistingIn (dir , []string {
252+ "Sources/main.swift" , "App.swift" , "ContentView.swift" , "AppDelegate.swift" ,
253+ })),
254+ }
255+ }
256+ }
257+ matches , _ := filepath .Glob (filepath .Join (dir , "*.xcodeproj" ))
258+ if len (matches ) > 0 {
259+ return & DetectResult {
260+ Language : "Swift" ,
261+ PackageManager : pm ,
262+ SDKID : "swift-client-sdk" ,
263+ EntryPoint : filepath .Join (dir , firstExistingIn (dir , []string {
264+ "Sources/main.swift" , "App.swift" , "ContentView.swift" , "AppDelegate.swift" ,
265+ })),
266+ }
267+ }
268+ return nil
269+ }
270+
271+ func detectDotnet (dir string ) * DetectResult {
272+ for _ , pattern := range []string {"*.csproj" , "*.sln" } {
273+ matches , _ := filepath .Glob (filepath .Join (dir , pattern ))
274+ if len (matches ) > 0 {
275+ return & DetectResult {
276+ Language : "C#" ,
277+ PackageManager : "dotnet" ,
278+ SDKID : "dotnet-server-sdk" ,
279+ EntryPoint : filepath .Join (dir , firstExistingIn (dir , []string {
280+ "Program.cs" , "Startup.cs" , "src/Program.cs" ,
281+ })),
282+ }
283+ }
284+ }
285+ return nil
286+ }
287+
288+ // SDKOption describes a LaunchDarkly SDK available for use with ldcli setup.
289+ type SDKOption struct {
290+ ID string
291+ Language string
292+ Name string
293+ }
294+
295+ // KnownSDKs is the ordered list of SDKs available for manual selection when
296+ // auto-detection fails or the user wants to override the detected SDK.
297+ var KnownSDKs = []SDKOption {
298+ {ID : "node-server" , Language : "JavaScript" , Name : "Node.js" },
299+ {ID : "react-client-sdk" , Language : "JavaScript" , Name : "React" },
300+ {ID : "react-native" , Language : "JavaScript" , Name : "React Native" },
301+ {ID : "js-client-sdk" , Language : "JavaScript" , Name : "JavaScript (Browser)" },
302+ {ID : "python-server-sdk" , Language : "Python" , Name : "Python" },
303+ {ID : "go-server-sdk" , Language : "Go" , Name : "Go" },
304+ {ID : "java-server-sdk" , Language : "Java" , Name : "Java" },
305+ {ID : "android-client-sdk" , Language : "Java" , Name : "Android" },
306+ {ID : "dotnet-server-sdk" , Language : "C#" , Name : ".NET" },
307+ {ID : "swift-client-sdk" , Language : "Swift" , Name : "iOS/Swift" },
308+ {ID : "ruby-server-sdk" , Language : "Ruby" , Name : "Ruby" },
309+ }
310+
218311// firstExistingIn returns the first candidate that exists as a file in dir,
219312// or the last candidate if none exist (as a suggested path).
220313// Returns an empty string if candidates is empty.
0 commit comments